fix: follow up Codex launcher and input handling
This commit is contained in:
@@ -97,12 +97,15 @@ async function resolveOllamaDefaultModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function runCommand(command: string, env: NodeJS.ProcessEnv): Promise<number> {
|
function runCommand(command: string, env: NodeJS.ProcessEnv): Promise<number> {
|
||||||
|
return runProcess(command, [], env)
|
||||||
|
}
|
||||||
|
|
||||||
|
function runProcess(command: string, args: string[], env: NodeJS.ProcessEnv): Promise<number> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const child = spawn(command, {
|
const child = spawn(command, args, {
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
env,
|
env,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
shell: true,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
child.on('close', code => resolve(code ?? 1))
|
child.on('close', code => resolve(code ?? 1))
|
||||||
@@ -120,11 +123,6 @@ function applyFastFlags(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
function quoteArg(arg: string): string {
|
|
||||||
if (!arg.includes(' ') && !arg.includes('"')) return arg
|
|
||||||
return `"${arg.replace(/"/g, '\\"')}"`
|
|
||||||
}
|
|
||||||
|
|
||||||
function printSummary(profile: ProviderProfile, env: NodeJS.ProcessEnv): void {
|
function printSummary(profile: ProviderProfile, env: NodeJS.ProcessEnv): void {
|
||||||
console.log(`Launching profile: ${profile}`)
|
console.log(`Launching profile: ${profile}`)
|
||||||
if (profile === 'gemini') {
|
if (profile === 'gemini') {
|
||||||
@@ -216,15 +214,18 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
printSummary(profile, env)
|
printSummary(profile, env)
|
||||||
|
|
||||||
const doctorCode = await runCommand('bun run scripts/system-check.ts', env)
|
const doctorCode = await runProcess('bun', ['run', 'scripts/system-check.ts'], env)
|
||||||
if (doctorCode !== 0) {
|
if (doctorCode !== 0) {
|
||||||
console.error('Runtime doctor failed. Fix configuration before launching.')
|
console.error('Runtime doctor failed. Fix configuration before launching.')
|
||||||
process.exit(doctorCode)
|
process.exit(doctorCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cliArgs = options.passthroughArgs.map(quoteArg).join(' ')
|
const buildCode = await runProcess('bun', ['run', 'build'], env)
|
||||||
const devCommand = cliArgs ? `bun run dev -- ${cliArgs}` : 'bun run dev'
|
if (buildCode !== 0) {
|
||||||
const devCode = await runCommand(devCommand, env)
|
process.exit(buildCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
const devCode = await runProcess('node', ['dist/cli.mjs', ...options.passthroughArgs], env)
|
||||||
process.exit(devCode)
|
process.exit(devCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import indentString from 'indent-string'
|
import indentString from 'indent-string'
|
||||||
import { applyTextStyles } from './colorize.js'
|
import { applyTextStyles } from './colorize.js'
|
||||||
import type { DOMElement } from './dom.js'
|
import type { DOMElement, DOMNode } from './dom.js'
|
||||||
import getMaxWidth from './get-max-width.js'
|
import getMaxWidth from './get-max-width.js'
|
||||||
import type { Rectangle } from './layout/geometry.js'
|
import type { Rectangle } from './layout/geometry.js'
|
||||||
import { LayoutDisplay, LayoutEdge, type LayoutNode } from './layout/node.js'
|
import { LayoutDisplay, LayoutEdge, type LayoutNode } from './layout/node.js'
|
||||||
@@ -383,6 +383,23 @@ function applyPaddingToText(
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isElementNode(node: DOMNode | undefined): node is DOMElement {
|
||||||
|
return Boolean(node && node.nodeName !== '#text')
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRenderableElementNode(node: unknown): node is DOMElement {
|
||||||
|
if (!node || typeof node !== 'object') return false
|
||||||
|
const candidate = node as Partial<DOMElement> & { nodeName?: string }
|
||||||
|
return (
|
||||||
|
candidate.nodeName !== undefined &&
|
||||||
|
candidate.nodeName !== '#text' &&
|
||||||
|
candidate.style !== undefined &&
|
||||||
|
typeof candidate.style === 'object' &&
|
||||||
|
typeof candidate.dirty === 'boolean' &&
|
||||||
|
Array.isArray(candidate.childNodes)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// After nodes are laid out, render each to output object, which later gets rendered to terminal
|
// After nodes are laid out, render each to output object, which later gets rendered to terminal
|
||||||
function renderNodeToOutput(
|
function renderNodeToOutput(
|
||||||
node: DOMElement,
|
node: DOMElement,
|
||||||
@@ -701,9 +718,9 @@ function renderNodeToOutput(
|
|||||||
yogaNode.getComputedPadding(LayoutEdge.Bottom),
|
yogaNode.getComputedPadding(LayoutEdge.Bottom),
|
||||||
)
|
)
|
||||||
|
|
||||||
const content = node.childNodes.find(c => (c as DOMElement).yogaNode) as
|
const content = node.childNodes.find(
|
||||||
| DOMElement
|
(c): c is DOMElement => isElementNode(c) && c.yogaNode !== undefined,
|
||||||
| undefined
|
)
|
||||||
const contentYoga = content?.yogaNode
|
const contentYoga = content?.yogaNode
|
||||||
// scrollHeight is the intrinsic height of the content wrapper.
|
// scrollHeight is the intrinsic height of the content wrapper.
|
||||||
// Do NOT add getComputedTop() — that's the wrapper's offset
|
// Do NOT add getComputedTop() — that's the wrapper's offset
|
||||||
@@ -937,8 +954,13 @@ function renderNodeToOutput(
|
|||||||
// Snapshot dirty children before the first pass — the first
|
// Snapshot dirty children before the first pass — the first
|
||||||
// pass clears dirty flags, and edge-spanning children would be
|
// pass clears dirty flags, and edge-spanning children would be
|
||||||
// missed by the second pass without this snapshot.
|
// missed by the second pass without this snapshot.
|
||||||
const dirtyChildren = content.dirty
|
const dirtyChildren =
|
||||||
? new Set(content.childNodes.filter(c => (c as DOMElement).dirty))
|
content.dirty
|
||||||
|
? new Set(
|
||||||
|
content.childNodes.filter(
|
||||||
|
(c): c is DOMElement => isElementNode(c) && c.dirty,
|
||||||
|
),
|
||||||
|
)
|
||||||
: null
|
: null
|
||||||
renderScrolledChildren(
|
renderScrolledChildren(
|
||||||
content,
|
content,
|
||||||
@@ -989,7 +1011,8 @@ function renderNodeToOutput(
|
|||||||
// preserving the ghost-box fix.
|
// preserving the ghost-box fix.
|
||||||
let cumHeightShift = 0
|
let cumHeightShift = 0
|
||||||
for (const childNode of content.childNodes) {
|
for (const childNode of content.childNodes) {
|
||||||
const childElem = childNode as DOMElement
|
if (!isElementNode(childNode)) continue
|
||||||
|
const childElem = childNode
|
||||||
const isDirty = dirtyChildren.has(childNode)
|
const isDirty = dirtyChildren.has(childNode)
|
||||||
if (!isDirty && cumHeightShift === 0) {
|
if (!isDirty && cumHeightShift === 0) {
|
||||||
if (nodeCache.has(childElem)) continue
|
if (nodeCache.has(childElem)) continue
|
||||||
@@ -1266,7 +1289,10 @@ function renderChildren(
|
|||||||
let seenDirtyChild = false
|
let seenDirtyChild = false
|
||||||
let seenDirtyClipped = false
|
let seenDirtyClipped = false
|
||||||
for (const childNode of node.childNodes) {
|
for (const childNode of node.childNodes) {
|
||||||
const childElem = childNode as DOMElement
|
if (!isRenderableElementNode(childNode)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const childElem = childNode
|
||||||
// Capture dirty before rendering — renderNodeToOutput clears the flag
|
// Capture dirty before rendering — renderNodeToOutput clears the flag
|
||||||
const wasDirty = childElem.dirty
|
const wasDirty = childElem.dirty
|
||||||
const isAbsolute = childElem.style.position === 'absolute'
|
const isAbsolute = childElem.style.position === 'absolute'
|
||||||
@@ -1313,14 +1339,18 @@ function siblingSharesY(node: DOMElement, yogaNode: LayoutNode): boolean {
|
|||||||
const siblings = parent.childNodes
|
const siblings = parent.childNodes
|
||||||
const idx = siblings.indexOf(node)
|
const idx = siblings.indexOf(node)
|
||||||
for (let i = idx + 1; i < siblings.length; i++) {
|
for (let i = idx + 1; i < siblings.length; i++) {
|
||||||
const sib = (siblings[i] as DOMElement).yogaNode
|
const sibling = siblings[i]
|
||||||
|
if (!isElementNode(sibling)) continue
|
||||||
|
const sib = sibling.yogaNode
|
||||||
if (!sib) continue
|
if (!sib) continue
|
||||||
return sib.getComputedTop() === myTop
|
return sib.getComputedTop() === myTop
|
||||||
}
|
}
|
||||||
// No next sibling with a yoga node — check previous. A run of h=0 boxes
|
// No next sibling with a yoga node — check previous. A run of h=0 boxes
|
||||||
// at the tail would all share y with each other.
|
// at the tail would all share y with each other.
|
||||||
for (let i = idx - 1; i >= 0; i--) {
|
for (let i = idx - 1; i >= 0; i--) {
|
||||||
const sib = (siblings[i] as DOMElement).yogaNode
|
const sibling = siblings[i]
|
||||||
|
if (!isElementNode(sibling)) continue
|
||||||
|
const sib = sibling.yogaNode
|
||||||
if (!sib) continue
|
if (!sib) continue
|
||||||
return sib.getComputedTop() === myTop
|
return sib.getComputedTop() === myTop
|
||||||
}
|
}
|
||||||
@@ -1399,7 +1429,10 @@ function renderScrolledChildren(
|
|||||||
// culling since their yogaTop shifted).
|
// culling since their yogaTop shifted).
|
||||||
let cumHeightShift = 0
|
let cumHeightShift = 0
|
||||||
for (const childNode of node.childNodes) {
|
for (const childNode of node.childNodes) {
|
||||||
const childElem = childNode as DOMElement
|
if (!isRenderableElementNode(childNode)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const childElem = childNode
|
||||||
const cy = childElem.yogaNode
|
const cy = childElem.yogaNode
|
||||||
if (cy) {
|
if (cy) {
|
||||||
const cached = nodeCache.get(childElem)
|
const cached = nodeCache.get(childElem)
|
||||||
|
|||||||
Reference in New Issue
Block a user