mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 00:03:20 +00:00
fix(codex): narrow app-server unsupported detection
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
"../src/main/claude/hook-settings.ts",
|
||||
"../src/main/claude/hook-service.ts",
|
||||
"../src/main/codex/codex-app-server-capability-cache.ts",
|
||||
"../src/main/codex/codex-app-server-capability-signal.ts",
|
||||
"../src/main/codex/codex-app-server-client.ts",
|
||||
"../src/main/codex/codex-app-server-grant-bridge.ts",
|
||||
"../src/main/codex/codex-app-server-grant-envelope.ts",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// Why: only an argv parse failure that names app-server proves the RPC surface
|
||||
// is absent; unrelated stderr must remain transient rather than poison the cache.
|
||||
export function stderrIndicatesMissingAppServer(stderrTail: string): boolean {
|
||||
return /^(?=.*\bapp-server\b).*(?:unrecognized subcommand|unexpected argument|invalid subcommand)/im.test(
|
||||
stderrTail
|
||||
)
|
||||
}
|
||||
@@ -49,6 +49,11 @@ if (config.scenario === 'no-subcommand') {
|
||||
process.stderr.write("error: unrecognized subcommand 'app-server'\\n")
|
||||
process.exit(2)
|
||||
}
|
||||
if (config.scenario === 'transient-stderr') {
|
||||
process.stderr.write('config loader: unexpected argument in value\\n')
|
||||
process.exit(1)
|
||||
}
|
||||
if (config.scenario === 'silent-exit-0') process.exit(0)
|
||||
process.stdin.setEncoding('utf8')
|
||||
process.stdin.on('data', (chunk) => {
|
||||
buffer += chunk
|
||||
@@ -278,6 +283,32 @@ describe('runCodexHookTrustGrantSession', () => {
|
||||
expect(isCodexAppServerUnsupportedError(error)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not classify unrelated stderr as a missing app-server capability', async () => {
|
||||
const { request } = createStubRequest({
|
||||
scenario: 'transient-stderr',
|
||||
hooks: [],
|
||||
expectedTrustKeys: ['k'],
|
||||
managedCommand: MANAGED_COMMAND
|
||||
})
|
||||
|
||||
const error = await runCodexHookTrustGrantSession(request).catch((caught: unknown) => caught)
|
||||
expect(error).toBeInstanceOf(Error)
|
||||
expect(isCodexAppServerUnsupportedError(error)).toBe(false)
|
||||
})
|
||||
|
||||
it('treats a silent exit zero before initialize as transient', async () => {
|
||||
const { request } = createStubRequest({
|
||||
scenario: 'silent-exit-0',
|
||||
hooks: [],
|
||||
expectedTrustKeys: ['k'],
|
||||
managedCommand: MANAGED_COMMAND
|
||||
})
|
||||
|
||||
const error = await runCodexHookTrustGrantSession(request).catch((caught: unknown) => caught)
|
||||
expect(error).toBeInstanceOf(Error)
|
||||
expect(isCodexAppServerUnsupportedError(error)).toBe(false)
|
||||
})
|
||||
|
||||
it('kills a hung server at the session deadline', async () => {
|
||||
const keys = ['/home/a/.codex/hooks.json:session_start:0:0']
|
||||
const { request, pidFile } = createStubRequest({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'
|
||||
import { normalizeHookTrustKeyForLookup } from './config-toml-trust'
|
||||
import { waitForProcessExitUntil } from './codex-process-exit-deadline'
|
||||
import { stderrIndicatesMissingAppServer } from './codex-app-server-capability-signal'
|
||||
|
||||
// Why: Codex gates hooks on a `trusted_hash` it computes from a private
|
||||
// canonical-JSON identity. Orca used to replicate that algorithm
|
||||
@@ -94,12 +95,6 @@ function isMethodNotFoundError(error: { code?: number; message?: string }): bool
|
||||
return error.code === JSON_RPC_METHOD_NOT_FOUND || /method not found/i.test(error.message ?? '')
|
||||
}
|
||||
|
||||
// Why: a CLI predating the app-server subcommand fails argv parsing before
|
||||
// speaking any JSON-RPC; that shape is a capability signal, not a transient.
|
||||
function stderrIndicatesMissingAppServer(stderrTail: string): boolean {
|
||||
return /unrecognized subcommand|unexpected argument|invalid subcommand/i.test(stderrTail)
|
||||
}
|
||||
|
||||
function collectHookListings(result: unknown): CodexHookListing[] {
|
||||
const data =
|
||||
result && typeof result === 'object' && Array.isArray((result as { data?: unknown }).data)
|
||||
|
||||
Reference in New Issue
Block a user