Files
orca/src/cli/dispatch.ts
T
Brennan Benson 31f643ca42 Add version-matched skill guides to the CLI (#8624)
* Add version-matched bundled skill guides

* Clarify skill freshness rollout PRs

* Add canonical skills show alias

* fix(skills): address guide review feedback

* fix(skills): make guide commands cross-platform

* fix(skills): apply the ORCA convention to the emulator guides

Review follow-up: the emulator guides still instructed literal
`orca emulator ...` in sh fences with no Linux disambiguation, so on
unmanaged Linux they could launch the GNOME screen reader — the exact
failure the executable-selection preamble prevents. Both emulator
guides now carry the preamble and ORCA placeholder across fences,
tables, and prose, and the cross-platform safety test covers all four
converted guides. Also replaces computer-use's "unless a block names a
shell" carve-out, which contradicted its own POSIX example, with the
unconditional placeholder rule.
2026-07-14 02:17:55 -07:00

92 lines
3.3 KiB
TypeScript

import type { RuntimeClient } from './runtime-client'
import { RuntimeClientError } from './runtime-client'
import { CORE_HANDLERS } from './handlers/core'
import { AUTOMATION_HANDLERS } from './handlers/automations'
import { PROJECT_HANDLERS } from './handlers/project'
import { REPO_HANDLERS } from './handlers/repo'
import { WORKTREE_HANDLERS } from './handlers/worktree'
import { FILE_HANDLERS } from './handlers/file'
import { TERMINAL_HANDLERS } from './handlers/terminal'
import { BROWSER_NAV_HANDLERS } from './handlers/browser-nav'
import { BROWSER_INTERACT_HANDLERS } from './handlers/browser-interact'
import { BROWSER_TAB_HANDLERS } from './handlers/browser-tab'
import { BROWSER_PROFILE_HANDLERS } from './handlers/browser-profile'
import { BROWSER_COOKIE_HANDLERS } from './handlers/browser-cookie'
import { BROWSER_CAPTURE_HANDLERS } from './handlers/browser-capture'
import { BROWSER_ENV_HANDLERS } from './handlers/browser-env'
import { BROWSER_STORAGE_HANDLERS } from './handlers/browser-storage'
import { ORCHESTRATION_HANDLERS } from './handlers/orchestration'
import { COMPUTER_HANDLERS } from './handlers/computer'
import { ENVIRONMENT_HANDLERS } from './handlers/environment'
import { AGENT_HOOK_HANDLERS } from './handlers/agent-hooks'
import { DIAGNOSTICS_HANDLERS } from './handlers/diagnostics'
import { INTROSPECTION_HANDLERS } from './handlers/introspection'
import { EMULATOR_HANDLERS } from './handlers/emulator'
import { LINEAR_HANDLERS } from './handlers/linear'
import { VM_HANDLERS } from './handlers/vm'
import { SKILL_HANDLERS } from './handlers/skills'
export type HandlerContext = {
flags: Map<string, string | boolean>
client: RuntimeClient
cwd: string
json: boolean
rawArgs?: string[]
}
export type CommandHandler = (ctx: HandlerContext) => Promise<void>
function buildHandlers(): Map<string, CommandHandler> {
const table = new Map<string, CommandHandler>()
const groups = [
CORE_HANDLERS,
AUTOMATION_HANDLERS,
PROJECT_HANDLERS,
REPO_HANDLERS,
WORKTREE_HANDLERS,
FILE_HANDLERS,
TERMINAL_HANDLERS,
BROWSER_NAV_HANDLERS,
BROWSER_INTERACT_HANDLERS,
BROWSER_TAB_HANDLERS,
BROWSER_PROFILE_HANDLERS,
BROWSER_COOKIE_HANDLERS,
BROWSER_CAPTURE_HANDLERS,
BROWSER_ENV_HANDLERS,
BROWSER_STORAGE_HANDLERS,
ORCHESTRATION_HANDLERS,
EMULATOR_HANDLERS,
COMPUTER_HANDLERS,
AGENT_HOOK_HANDLERS,
DIAGNOSTICS_HANDLERS,
INTROSPECTION_HANDLERS,
ENVIRONMENT_HANDLERS,
LINEAR_HANDLERS,
VM_HANDLERS,
SKILL_HANDLERS
]
for (const group of groups) {
for (const [key, handler] of Object.entries(group)) {
if (table.has(key)) {
throw new Error(`Duplicate CLI handler registration for "${key}"`)
}
table.set(key, handler)
}
}
return table
}
const HANDLERS = buildHandlers()
// Why: exposes only the canonical command keys (not the handler internals) so the
// registry-parity guard can check specs↔handlers without rebuilding the table.
export const HANDLER_COMMAND_KEYS: ReadonlySet<string> = new Set(HANDLERS.keys())
export async function dispatch(commandPath: string[], ctx: HandlerContext): Promise<void> {
const handler = HANDLERS.get(commandPath.join(' '))
if (!handler) {
throw new RuntimeClientError('invalid_argument', `Unknown command: ${commandPath.join(' ')}`)
}
await handler(ctx)
}