Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/ipc/filesystem-watcher-ignore-real.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ describe('filesystem watcher native ignores', () => {
sourceFiles.push(join(root, 'source\nnewline.ts'), join(nestedSource, 'source\nnewline.ts'))
}
await writeUntilSeen(sourceFiles)
// Why: events arrive in order, so once a file written after the storm is seen, any
// Why: events arrive in order, so once a file written after the storm is seen at both levels, any
// unignored generated event is already recorded. Replaces a fixed debounce sleep.
await writeUntilSeen([join(nestedSource, 'sentinel.ts')])
await writeUntilSeen([join(root, 'sentinel.ts'), join(nestedSource, 'sentinel.ts')])

expect(errors).toEqual([])
const generatedPaths = new Set(generatedFiles)
Expand Down
38 changes: 29 additions & 9 deletions src/main/orcad/orcad-serve-parity.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,14 @@ describe.skipIf(skip)('orca serve on orcad', () => {
const appRoot = profile()
mkdirSync(join(appRoot, 'out', 'web'), { recursive: true })
writeFileSync(join(appRoot, 'out', 'web', WEB_CLIENT_INDEX_FILENAME), '<title>orca web</title>')
// The argv `orca serve` builds, but on loopback: a test must not listen on every interface.
const args = orcadServeArgs({ json: true, port: '0' }, findBundledWebClientRoot(appRoot))
args.splice(args.indexOf('0.0.0.0'), 1, '127.0.0.1')
// The argv `orca serve` builds, but on loopback.
const args = orcadServeArgs(
{ json: true, port: '0' },
findBundledWebClientRoot(appRoot),
'127.0.0.1'
)
try {
const readiness = await serveOnce(userData, args)
const { readiness } = await serveOnce(userData, args)
const webClientUrl: unknown = readiness.pairing?.webClientUrl
expect(webClientUrl).toEqual(expect.stringMatching(/^http:\/\/127\.0\.0\.1:\d+\//u))
const index = await fetch(new URL(`/${WEB_CLIENT_INDEX_FILENAME}`, String(webClientUrl)))
Expand Down Expand Up @@ -262,14 +265,30 @@ const running = new Map<string, ReturnType<typeof spawnProcess>>()

/** Starts `orca serve --json` on orcad and returns the terminal daemon pid its readiness names. */
async function serveDaemonPid(userData: string): Promise<number> {
const readiness = await serveOnce(userData, ['--bind', '127.0.0.1', '--port', '0', '--json'])
const { readiness, stderr } = await serveOnce(userData, [
'--bind',
'127.0.0.1',
'--port',
'0',
'--json'
])
const daemon = readiness.health?.terminalDaemon
expect(daemon?.state).toBe('live')
if (daemon?.state !== 'live') {
throw new Error(`terminal daemon not live (${String(daemon?.state)}): ${stderr}`)
}
return daemon.pid
}

/** Starts orcad with `args` and returns its parsed readiness line. */
async function serveOnce(userData: string, args: string[]) {
type ServeReadiness = {
pairing?: { webClientUrl?: unknown }
health?: { terminalDaemon?: { state?: string; pid: number } }
}

/** Starts orcad with `args` and returns its parsed readiness line and stderr so far. */
async function serveOnce(
userData: string,
args: string[]
): Promise<{ readiness: ServeReadiness; stderr: string }> {
const child = spawnProcess({
program: runtime!,
args: [join(slotDir, 'orcad.js'), ...args],
Expand All @@ -291,7 +310,8 @@ async function serveOnce(userData: string, args: string[]) {
}
})
})
return JSON.parse(line)
const readiness: ServeReadiness = JSON.parse(line)
return { readiness, stderr }
}

/** SIGTERM is serve's graceful stop on POSIX; it leaves the daemon running by design. */
Expand Down
62 changes: 26 additions & 36 deletions src/main/runtime/construction/runtime-composition-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { SKILL_INSTALL_CAPABILITY } from '../../../shared/skill-install-capabili

/**
* Electron (`main-process-*`) and orcad (`orcad-entry.ts`) each compose the same runtime, and every
* dependency is optional, so one root can silently skip a service the other wires (C2: #30120 never
* dependency is optional, so one root can silently skip a service the other wires (#30120 never
* gave orcad its web client root). This records what each root's source wires and fails on any
* difference that is not declared below with a reason.
*/
Expand All @@ -18,7 +18,7 @@ type DeclaredDifference = {
wiring: string
missingOn: Root
reason: string
/** Capabilities the missing host still advertises; its methods must refuse accurately (D3). */
/** Capabilities the missing host still advertises; its methods must refuse accurately. */
advertisedUnserved?: readonly string[]
}

Expand Down Expand Up @@ -148,29 +148,37 @@ const SPREAD_SOURCES: Record<string, { file: string; anchor: string }> = {
const repoRoot = join(__dirname, '../../../..')
const read = (file: string): string => stripComments(readFileSync(join(repoRoot, file), 'utf8'))

const QUOTES = `'"\``

/** The index of the quote that closes the string opening at `open` (or the end of the source). */
function stringEnd(source: string, open: number): number {
for (let i = open + 1; i < source.length; i++) {
if (source[i] === '\\') {
i++
} else if (source[i] === source[open]) {
return i
}
}
return source.length
}

function stripComments(source: string): string {
let out = ''
let quote: string | null = null
for (let i = 0; i < source.length; i++) {
const char = source[i]
if (quote) {
out += char
if (char === '\\') {
out += source[++i] ?? ''
} else if (char === quote) {
quote = null
}
if (QUOTES.includes(char)) {
const end = stringEnd(source, i)
out += source.slice(i, end + 1)
i = end
} else if (char === '/' && source[i + 1] === '/') {
while (i < source.length && source[i] !== '\n') {
i++
}
out += '\n'
} else if (char === '/' && source[i + 1] === '*') {
i = source.indexOf('*/', i + 2) + 1
const end = source.indexOf('*/', i + 2)
i = end === -1 ? source.length : end + 1
} else {
if (char === "'" || char === '"' || char === '`') {
quote = char
}
out += char
}
}
Expand All @@ -180,19 +188,10 @@ function stripComments(source: string): string {
/** The inner text of the brace group that opens at `open` (strings are opaque). */
function braceGroup(source: string, open: number): string {
let depth = 0
let quote: string | null = null
for (let i = open; i < source.length; i++) {
const char = source[i]
if (quote) {
if (char === '\\') {
i++
} else if (char === quote) {
quote = null
}
continue
}
if (char === "'" || char === '"' || char === '`') {
quote = char
if (QUOTES.includes(char)) {
i = stringEnd(source, i)
} else if (char === '{') {
depth++
} else if (char === '}' && --depth === 0) {
Expand All @@ -218,20 +217,11 @@ function objectLiteralAfter(source: string, anchor: string): string {
function topLevelEntries(inner: string): string[] {
const entries: string[] = []
let depth = 0
let quote: string | null = null
let start = 0
for (let i = 0; i < inner.length; i++) {
const char = inner[i]
if (quote) {
if (char === '\\') {
i++
} else if (char === quote) {
quote = null
}
continue
}
if (char === "'" || char === '"' || char === '`') {
quote = char
if (QUOTES.includes(char)) {
i = stringEnd(inner, i)
} else if ('({['.includes(char)) {
depth++
} else if (')}]'.includes(char)) {
Expand Down
9 changes: 7 additions & 2 deletions src/shared/orcad-serve-argv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ export function serveOptionArgs(args: ServeOrcaAppArgs, prefix: '--' | '--serve-
]
}

export function orcadServeArgs(args: ServeOrcaAppArgs, webClientRoot?: string): string[] {
/** `bindHost` exists for tests, which must not listen on every interface. */
export function orcadServeArgs(
args: ServeOrcaAppArgs,
webClientRoot?: string,
bindHost = '0.0.0.0'
): string[] {
return [
'--bind',
'0.0.0.0',
bindHost,
...serveOptionArgs(args, '--'),
...(webClientRoot ? ['--web-client-root', webClientRoot] : [])
]
Expand Down
Loading