opencode-agent-skill 7.7.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +112 -3
  2. package/README.md +396 -281
  3. package/bin/ocskill.mjs +382 -156
  4. package/docs/DETERMINISTIC-TOOLS.md +25 -8
  5. package/docs/ENGINEERING-DESIGN.md +31 -13
  6. package/docs/EVALS.md +34 -12
  7. package/docs/NPM-PUBLISH.md +6 -6
  8. package/docs/OPENCODE-COMPAT.md +11 -8
  9. package/docs/TRACE-SCHEMA.md +15 -2
  10. package/docs/V8-INTELLIGENCE-RELIABILITY.md +206 -0
  11. package/docs/V9-SPEED-INTELLIGENCE.md +102 -0
  12. package/evals/live/tasks.json +6 -6
  13. package/evals/polyglot/fixtures/polyglot-bench/api/generated/client.ts +2 -0
  14. package/evals/polyglot/fixtures/polyglot-bench/api/openapi.json +25 -0
  15. package/evals/polyglot/fixtures/polyglot-bench/db/migrations/20260920_add_order_key.sql +1 -0
  16. package/evals/polyglot/fixtures/polyglot-bench/dotnet/OrderService.cs +8 -0
  17. package/evals/polyglot/fixtures/polyglot-bench/java/PriceService.java +5 -0
  18. package/evals/polyglot/fixtures/polyglot-bench/monorepo/package.json +6 -0
  19. package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/api/package.json +4 -0
  20. package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/web/package.json +7 -0
  21. package/evals/polyglot/fixtures/polyglot-bench/monorepo/pnpm-lock.yaml +5 -0
  22. package/evals/polyglot/fixtures/polyglot-bench/next/app/api/products/route.ts +7 -0
  23. package/evals/polyglot/fixtures/polyglot-bench/python/tenant_auth.py +4 -0
  24. package/evals/polyglot/fixtures/polyglot-bench/react-native/keyboard.ts +3 -0
  25. package/evals/polyglot/graders/polyglot-bench.mjs +101 -0
  26. package/evals/polyglot/tasks.json +54 -0
  27. package/global-config/AGENTS.md +78 -160
  28. package/global-config/agents/integration-verifier.md +1 -1
  29. package/global-config/agents/plan-checker.md +1 -1
  30. package/global-config/commands/run.md +9 -5
  31. package/global-config/plugins/ues-router/capabilities.js +4 -0
  32. package/global-config/plugins/ues-router/index.js +784 -37
  33. package/global-config/plugins/ues-router/router.js +175 -23
  34. package/global-config/plugins/ues-router/runtime-guard.js +265 -0
  35. package/global-config/skills/engineering-orchestrator/references/long-horizon.md +6 -4
  36. package/lib/aci.mjs +128 -0
  37. package/lib/benchmark-confidence.mjs +173 -0
  38. package/lib/cli-utils.mjs +41 -0
  39. package/lib/container-sandbox.mjs +102 -0
  40. package/lib/context-manifest.mjs +300 -22
  41. package/lib/control-center.mjs +36 -3
  42. package/lib/eval-ablation.mjs +104 -0
  43. package/lib/eval-order.mjs +9 -0
  44. package/lib/eval-report.mjs +11 -0
  45. package/lib/eval-telemetry.mjs +8 -2
  46. package/lib/gate-receipt.mjs +52 -0
  47. package/lib/installer.mjs +39 -25
  48. package/lib/learning-engine.mjs +236 -38
  49. package/lib/model-policy.mjs +6 -0
  50. package/lib/opencode-compat.mjs +25 -10
  51. package/lib/orchestrator-policy.mjs +195 -21
  52. package/lib/process-runner.mjs +30 -9
  53. package/lib/runtime-events.mjs +31 -0
  54. package/lib/semantic-index.mjs +318 -0
  55. package/lib/task-engine.mjs +557 -28
  56. package/lib/trajectory.mjs +89 -0
  57. package/lib/windows-shim.mjs +227 -0
  58. package/lib/worktree-sandbox.mjs +85 -3
  59. package/package.json +11 -4
  60. package/scripts/check-release-tag.mjs +22 -0
  61. package/scripts/control-center.mjs +25 -0
  62. package/scripts/eval-ablation.mjs +44 -0
  63. package/scripts/eval-live.mjs +39 -58
  64. package/scripts/eval-matrix.mjs +166 -0
  65. package/scripts/smoke-packed-install.mjs +138 -4
  66. package/scripts/smoke-plain-install.mjs +91 -0
  67. package/scripts/validate-live-suite.mjs +3 -3
  68. package/scripts/validate.mjs +27 -5
package/bin/ocskill.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readFileSync } from "node:fs"
2
+ import { writeFileSync } from "node:fs"
3
3
  import { spawnSync } from "node:child_process"
4
4
  import { fileURLToPath } from "node:url"
5
5
  import path from "node:path"
@@ -15,6 +15,7 @@ import {
15
15
  import { compareVersions } from "../lib/version.mjs"
16
16
  import { resolveLatestPublishedVersion } from "../lib/update-resolver.mjs"
17
17
  import { readRouterConfig, writeRouterConfig } from "../lib/router-config.mjs"
18
+ import { resolveWindowsCommand } from "../lib/windows-shim.mjs"
18
19
  import {
19
20
  detectStack,
20
21
  detectTestCommands,
@@ -24,10 +25,15 @@ import {
24
25
  checkWorkingTree,
25
26
  } from "../lib/repo-inspect.mjs"
26
27
  import { buildRepoGraph } from "../lib/repo-graph.mjs"
28
+ import { buildSemanticIndex, semanticIndexStatus } from "../lib/semantic-index.mjs"
29
+ import { aciReferences, aciSearch, aciTextSearch, aciView } from "../lib/aci.mjs"
30
+ import { appendTrajectoryEvent, readTrajectory } from "../lib/trajectory.mjs"
31
+ import { containerSandboxCapability, runContainerSandbox } from "../lib/container-sandbox.mjs"
27
32
  import { analyzePlan } from "../lib/task-graph.mjs"
28
33
  import {
29
34
  addBlocker,
30
35
  addDecision,
36
+ attachTaskSession,
31
37
  approvePlan,
32
38
  completeTask,
33
39
  contextPack,
@@ -42,18 +48,34 @@ import {
42
48
  workStatus,
43
49
  heartbeatTask,
44
50
  recoverStaleTasks,
51
+ recoverTask,
45
52
  recordVerificationReceipt,
46
53
  workspaceFingerprint,
54
+ createPlanVerificationReceipt,
55
+ createIntegrationVerificationReceipt,
56
+ runtimeEvents,
57
+ checkpointWork,
58
+ markCheckpointResumed,
47
59
  } from "../lib/task-engine.mjs"
48
60
  import { reviewScope } from "../lib/review-scope.mjs"
49
61
  import { buildVerificationPlan } from "../lib/verification-plan.mjs"
50
62
  import { resolveAdaptiveModel, resolveModel } from "../lib/model-policy.mjs"
51
63
  import { createVerificationReceipt } from "../lib/evidence-receipt.mjs"
52
64
  import { classifyEngineeringTask } from "../lib/orchestrator-policy.mjs"
53
- import { createTaskSandbox, listTaskSandboxes, removeTaskSandbox } from "../lib/worktree-sandbox.mjs"
54
- import { analyzeEvalTraces, saveLearningAnalysis, readLearningState, acceptLearning } from "../lib/learning-engine.mjs"
65
+ import { createTaskSandbox, integrateTaskSandbox, listTaskSandboxes, removeTaskSandbox } from "../lib/worktree-sandbox.mjs"
66
+ import { analyzeEvalTraces, saveLearningAnalysis, readLearningState, acceptLearning, promoteLearning } from "../lib/learning-engine.mjs"
55
67
  import { hermesStatus, buildHermesDelegationPrompt, hermesOneShotArgs } from "../lib/hermes-bridge.mjs"
56
68
  import { readModelPolicy, validateModelID, writeModelPolicy } from "../lib/model-config.mjs"
69
+ import {
70
+ clipOutput,
71
+ errorMessage,
72
+ optionInt,
73
+ optionIntOrUndefined,
74
+ optionValue,
75
+ positionalArg,
76
+ readJsonFile,
77
+ readTextFile,
78
+ } from "../lib/cli-utils.mjs"
57
79
 
58
80
  const args = process.argv.slice(2)
59
81
  const command = args[0] || "help"
@@ -76,6 +98,11 @@ Usage:
76
98
  ocskill evidence [dir] Collect stack, verification and Git evidence
77
99
  ocskill working-tree [dir] Report Git branch/HEAD/dirty state
78
100
  ocskill repo-graph [dir] Build a bounded source import/dependency graph
101
+ ocskill index <status|build|rebuild> [dir]
102
+ Build/reuse the persistent incremental semantic index
103
+ ocskill aci <search|refs|view|text> ...
104
+ Bounded evidence-first code search/view interface
105
+ ocskill trace <show|append> ... Inspect or append redacted operational trajectory events
79
106
  ocskill review-scope [base] [dir]
80
107
  Enumerate changed files, review coverage and risk
81
108
  ocskill verification-plan [dir]
@@ -87,8 +114,9 @@ Usage:
87
114
  ocskill model-policy <role> [--attempt N]
88
115
  Resolve light/standard/heavy escalation tier
89
116
  ocskill task-policy <text> Classify task mode/risk/context/model tier
90
- ocskill sandbox <action> ... Manage isolated Git worktree task sandboxes
91
- ocskill learn <action> ... Analyze eval traces and promote accepted lessons
117
+ ocskill sandbox <action> ... Create, integrate and clean isolated Git worktree sandboxes
118
+ Also supports capability/exec for fail-closed container verification
119
+ ocskill learn <action> ... Analyze eval traces and promote benchmark-validated lessons
92
120
  ocskill hermes <action> ... Optional Hermes adapter/status
93
121
  ocskill dashboard [dir] [--serve] [--port N]
94
122
  Generate/serve the local UES Control Center
@@ -105,16 +133,20 @@ Usage:
105
133
  ocskill work init <slug> [dir] --goal <text>
106
134
  ocskill work plan <slug> <plan.json> [dir]
107
135
  ocskill work status|resume <slug> [dir]
108
- ocskill work approve-plan <slug> [dir] --evidence <plan-checker-evidence>
136
+ ocskill work gate-receipt <slug> <plan|integration> [dir] --evidence <text> [--verdict PASS|FAIL|PARTIAL] [--verifier <role>] [--session-id <id>] [--report-file <file>] [--out <file>]
137
+ ocskill work approve-plan <slug> [dir] --evidence <plan-checker-evidence> [--receipt-file <file>]
109
138
  ocskill work start <slug> <task-id> [dir] [--lease-ms N]
110
- ocskill work heartbeat <slug> <task-id> [dir] [--run-id <id>]
139
+ ocskill work attach-session <slug> <task-id> [dir] --run-id <id> --session-id <id> [--execution-dir <dir>] [--sandbox-dir <dir>]
140
+ ocskill work heartbeat <slug> <task-id> [dir] --run-id <id>
111
141
  ocskill work recover <slug> [dir] [--force]
112
- ocskill work verify-command <slug> <task-id> [dir] [--run-id <id>] -- <command> [args...]
113
- ocskill work complete <slug> <task-id> [dir] --evidence <text> [--report-file <file>] [--run-id <id>]
114
- ocskill work fail <slug> <task-id> [dir] --reason <text> [--run-id <id>]
142
+ ocskill work recover-task <slug> <task-id> [dir] [--force] [--reason <text>]
143
+ ocskill work events <slug> [dir] [--limit N]
144
+ ocskill work verify-command <slug> <task-id> [dir] --run-id <id> -- <command> [args...]
145
+ ocskill work complete <slug> <task-id> [dir] --run-id <id> --evidence <text> [--report-file <file>]
146
+ ocskill work fail <slug> <task-id> [dir] --run-id <id> --reason <text>
115
147
  ocskill work decision <slug> [dir] --text <decision>
116
148
  ocskill work block|unblock <slug> [dir] --text <blocker>
117
- ocskill work verify-integration <slug> [dir] --verdict PASS|FAIL|PARTIAL --evidence <text> [--report-file <file>]
149
+ ocskill work verify-integration <slug> [dir] --verdict PASS|FAIL|PARTIAL --evidence <text> [--report-file <file>] [--receipt-file <file>]
118
150
  ocskill work finalize <slug> [dir] --evidence <integration-evidence>
119
151
 
120
152
  Model routing:
@@ -127,38 +159,6 @@ Usage:
127
159
  `)
128
160
  }
129
161
 
130
- function findWindowsCommand(name) {
131
- if (path.isAbsolute(name) && existsSync(name)) return name
132
-
133
- const result = spawnSync("where", [name], { encoding: "utf8" })
134
- if (result.status !== 0 || !result.stdout) return null
135
-
136
- const matches = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
137
- return matches.find((item) => /\.(cmd|bat)$/i.test(item)) || matches[0] || null
138
- }
139
-
140
- function quoteCmd(value) {
141
- if (/^[A-Za-z0-9_@%+=:,./\\-]+$/.test(value)) return value
142
- return `"${value.replaceAll('"', '""')}"`
143
- }
144
-
145
- function findNodeShimEntry(cmdPath) {
146
- const dir = path.dirname(cmdPath)
147
-
148
- if (/^npm(?:\.cmd|\.exe)?$/i.test(path.basename(cmdPath))) {
149
- const entry = path.join(dir, "node_modules", "npm", "bin", "npm-cli.js")
150
- if (existsSync(entry)) return entry
151
- }
152
-
153
- let shim = ""
154
- try {
155
- shim = readFileSync(cmdPath, "utf8")
156
- } catch {}
157
- const match = shim.match(/node_modules[\\/][^\s"]+?\.(?:js|mjs)/gi)?.at(-1)
158
- if (!match) return null
159
- const entry = path.resolve(dir, match)
160
- return existsSync(entry) ? entry : null
161
- }
162
162
 
163
163
  function run(executable, commandArgs, options = {}) {
164
164
  const common = { stdio: "inherit", ...options }
@@ -168,26 +168,22 @@ function run(executable, commandArgs, options = {}) {
168
168
  return result.status ?? 1
169
169
  }
170
170
 
171
- const resolved = findWindowsCommand(executable)
172
- if (!resolved) return 127
173
-
174
- if (/\.(cmd|bat)$/i.test(resolved)) {
175
- const entry = findNodeShimEntry(resolved)
176
- if (entry) {
177
- const result = spawnSync(process.execPath, [entry, ...commandArgs], common)
178
- return result.status ?? 1
179
- }
180
- const line = [resolved, ...commandArgs].map(quoteCmd).join(" ")
181
- const result = spawnSync(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", line], common)
182
- return result.status ?? 1
171
+ const resolved = resolveWindowsCommand(executable)
172
+ if (!resolved) {
173
+ console.error("[ocskill] No safely executable Windows command found for: " + executable)
174
+ return 127
183
175
  }
184
176
 
185
- const result = spawnSync(resolved, commandArgs, common)
177
+ const result = spawnSync(
178
+ resolved.executable,
179
+ [...resolved.argsPrefix, ...commandArgs],
180
+ common,
181
+ )
186
182
  return result.status ?? 1
187
183
  }
188
184
 
189
185
  function hasCommand(name) {
190
- if (process.platform === "win32") return findWindowsCommand(name) !== null
186
+ if (process.platform === "win32") return resolveWindowsCommand(name) !== null
191
187
  return spawnSync("which", [name], { stdio: "ignore" }).status === 0
192
188
  }
193
189
 
@@ -198,22 +194,20 @@ function runCapture(executable, commandArgs, options = {}) {
198
194
  return spawnSync(executable, commandArgs, common)
199
195
  }
200
196
 
201
- const resolved = findWindowsCommand(executable)
202
- if (!resolved) return { status: 127, stdout: "", stderr: `Command not found: ${executable}` }
203
-
204
- if (/\.(cmd|bat)$/i.test(resolved)) {
205
- const entry = findNodeShimEntry(resolved)
206
- if (entry) return spawnSync(process.execPath, [entry, ...commandArgs], common)
207
-
208
- const line = [resolved, ...commandArgs].map(quoteCmd).join(" ")
209
- return spawnSync(
210
- process.env.ComSpec || "cmd.exe",
211
- ["/d", "/s", "/c", line],
212
- common,
213
- )
197
+ const resolved = resolveWindowsCommand(executable)
198
+ if (!resolved) {
199
+ return {
200
+ status: 127,
201
+ stdout: "",
202
+ stderr: `No safely executable Windows command found for: ${executable}`,
203
+ }
214
204
  }
215
205
 
216
- return spawnSync(resolved, commandArgs, common)
206
+ return spawnSync(
207
+ resolved.executable,
208
+ [...resolved.argsPrefix, ...commandArgs],
209
+ common,
210
+ )
217
211
  }
218
212
 
219
213
 
@@ -278,8 +272,12 @@ async function doctor() {
278
272
  console.log(`Node: ${process.version}`)
279
273
  console.log(`Config: ${getConfigDir()}`)
280
274
  console.log(`npm: ${hasCommand("npm") ? "OK" : "MISSING"}`)
281
- console.log(`OpenCode: ${hasCommand("opencode") ? "OK" : "MISSING"}`)
282
- if (hasCommand("opencode")) run("opencode", ["--version"])
275
+ const openCodeAvailable = hasCommand("opencode")
276
+ console.log(`OpenCode: ${openCodeAvailable ? "OK" : "MISSING"}`)
277
+ if (openCodeAvailable) {
278
+ const code = run("opencode", ["--version"])
279
+ if (code !== 0) process.exitCode = code
280
+ }
283
281
  await status()
284
282
  }
285
283
 
@@ -309,7 +307,7 @@ async function evaluateReport() {
309
307
  }
310
308
 
311
309
  async function inspectRepository() {
312
- printJson(await repoMap(args[1] || process.cwd()))
310
+ printJson(await repoMap(positionalArg(args, 1) || process.cwd()))
313
311
  }
314
312
 
315
313
  async function inspectImpact() {
@@ -319,42 +317,129 @@ async function inspectImpact() {
319
317
  process.exitCode = 2
320
318
  return
321
319
  }
322
- printJson(await impactMap(args[2] || process.cwd(), query))
320
+ printJson(await impactMap(positionalArg(args, 2) || process.cwd(), query))
323
321
  }
324
322
 
325
323
  async function inspectEvidence() {
326
- printJson(await collectEvidence(args[1] || process.cwd()))
324
+ printJson(await collectEvidence(positionalArg(args, 1) || process.cwd()))
327
325
  }
328
326
 
329
327
  async function inspectWorkingTree() {
330
- printJson(await checkWorkingTree(args[1] || process.cwd()))
328
+ printJson(await checkWorkingTree(positionalArg(args, 1) || process.cwd()))
331
329
  }
332
330
 
333
331
  async function inspectStack() {
334
- printJson(await detectStack(args[1] || process.cwd()))
332
+ printJson(await detectStack(positionalArg(args, 1) || process.cwd()))
335
333
  }
336
334
 
337
335
  async function inspectTests() {
338
- printJson(await detectTestCommands(args[1] || process.cwd()))
336
+ printJson(await detectTestCommands(positionalArg(args, 1) || process.cwd()))
339
337
  }
340
338
 
341
- function optionValue(name) {
342
- const index = args.indexOf(name)
343
- return index >= 0 ? args[index + 1] : null
339
+ async function inspectRepoGraph() {
340
+ printJson(await buildRepoGraph(positionalArg(args, 1) || process.cwd()))
344
341
  }
345
342
 
346
- async function inspectRepoGraph() {
347
- printJson(await buildRepoGraph(args[1] || process.cwd()))
343
+ async function semanticIndexControl() {
344
+ const action = args[1] || "status"
345
+ const root = positionalArg(args, 2) || process.cwd()
346
+ try {
347
+ if (action === "status") {
348
+ printJson(await semanticIndexStatus(root))
349
+ return
350
+ }
351
+ if (action === "build" || action === "rebuild") {
352
+ const built = await buildSemanticIndex(root, { rebuild: action === "rebuild" })
353
+ printJson({ action, stats: built.stats })
354
+ return
355
+ }
356
+ throw new Error("Usage: ocskill index <status|build|rebuild> [dir]")
357
+ } catch (error) {
358
+ console.error(errorMessage(error))
359
+ process.exitCode = 1
360
+ }
361
+ }
362
+
363
+ async function aciControl() {
364
+ const action = args[1]
365
+ try {
366
+ if (action === "search") {
367
+ const query = args[2]
368
+ const root = positionalArg(args, 3) || process.cwd()
369
+ if (!query) throw new Error("Usage: ocskill aci search <query> [dir] [--limit N]")
370
+ printJson(await aciSearch(root, query, { limit: optionInt(args, "--limit", 20) }))
371
+ return
372
+ }
373
+ if (action === "refs") {
374
+ const symbol = args[2]
375
+ const root = positionalArg(args, 3) || process.cwd()
376
+ if (!symbol) throw new Error("Usage: ocskill aci refs <symbol> [dir] [--limit N]")
377
+ printJson(await aciReferences(root, symbol, { limit: optionInt(args, "--limit", 40) }))
378
+ return
379
+ }
380
+ if (action === "view") {
381
+ const file = args[2]
382
+ const root = positionalArg(args, 3) || process.cwd()
383
+ if (!file) throw new Error("Usage: ocskill aci view <file> [dir] [--line N] [--lines N]")
384
+ printJson(await aciView(root, file, {
385
+ line: optionInt(args, "--line", 1),
386
+ startLine: optionInt(args, "--start-line", 0),
387
+ lines: optionInt(args, "--lines", 120),
388
+ }))
389
+ return
390
+ }
391
+ if (action === "text") {
392
+ const query = args[2]
393
+ const root = positionalArg(args, 3) || process.cwd()
394
+ if (!query) throw new Error("Usage: ocskill aci text <query> [dir] [--limit N]")
395
+ printJson(await aciTextSearch(root, query, { limit: optionInt(args, "--limit", 80) }))
396
+ return
397
+ }
398
+ throw new Error("Usage: ocskill aci <search|refs|view|text> ...")
399
+ } catch (error) {
400
+ console.error(errorMessage(error))
401
+ process.exitCode = 1
402
+ }
403
+ }
404
+
405
+ async function traceControl() {
406
+ const action = args[1] || "show"
407
+ try {
408
+ if (action === "show") {
409
+ const traceID = args[2]
410
+ const root = positionalArg(args, 3) || process.cwd()
411
+ if (!traceID) throw new Error("Usage: ocskill trace show <trace-id> [dir] [--limit N]")
412
+ printJson(await readTrajectory(root, traceID, { limit: optionInt(args, "--limit", 200) }))
413
+ return
414
+ }
415
+ if (action === "append") {
416
+ const traceID = args[2]
417
+ const root = positionalArg(args, 3) || process.cwd()
418
+ const type = optionValue(args, "--type")
419
+ const payload64 = optionValue(args, "--payload-b64")
420
+ if (!traceID || !type) throw new Error("Usage: ocskill trace append <trace-id> [dir] --type <type> [--payload-b64 <base64-json>]")
421
+ let payload = {}
422
+ if (payload64) {
423
+ payload = JSON.parse(Buffer.from(payload64, "base64").toString("utf8"))
424
+ }
425
+ printJson(await appendTrajectoryEvent(root, traceID, type, payload))
426
+ return
427
+ }
428
+ throw new Error("Usage: ocskill trace <show|append> ...")
429
+ } catch (error) {
430
+ console.error(errorMessage(error))
431
+ process.exitCode = 1
432
+ }
348
433
  }
349
434
 
350
435
  async function inspectReviewScope() {
351
- const base = args[1] && !args[1].startsWith("--") ? args[1] : null
352
- const root = args[2] && !args[2].startsWith("--") ? args[2] : process.cwd()
436
+ const base = positionalArg(args, 1)
437
+ const root = positionalArg(args, 2) || process.cwd()
353
438
  printJson(reviewScope(root, base))
354
439
  }
355
440
 
356
441
  async function inspectVerificationPlan() {
357
- printJson(await buildVerificationPlan(args[1] || process.cwd(), optionValue("--base")))
442
+ printJson(await buildVerificationPlan(positionalArg(args, 1) || process.cwd(), optionValue(args, "--base")))
358
443
  }
359
444
 
360
445
  async function inspectTaskGraph() {
@@ -365,12 +450,12 @@ async function inspectTaskGraph() {
365
450
  return
366
451
  }
367
452
  try {
368
- const plan = JSON.parse(readFileSync(path.resolve(file), "utf8"))
453
+ const plan = readJsonFile(file)
369
454
  const analysis = analyzePlan(plan)
370
455
  printJson(analysis)
371
456
  if (!analysis.valid) process.exitCode = 1
372
457
  } catch (error) {
373
- console.error(error instanceof Error ? error.message : error)
458
+ console.error(errorMessage(error))
374
459
  process.exitCode = 1
375
460
  }
376
461
  }
@@ -383,78 +468,166 @@ async function inspectContextPack() {
383
468
  process.exitCode = 2
384
469
  return
385
470
  }
386
- printJson(await contextPack(args[3] || process.cwd(), slug, taskID))
471
+ printJson(await contextPack(positionalArg(args, 3) || process.cwd(), slug, taskID))
387
472
  }
388
473
 
389
474
  async function workControl() {
390
475
  const action = args[1]
391
476
  const slug = args[2]
392
477
  if (!action || !slug) {
393
- console.error("Usage: ocskill work <init|plan|status|resume|approve-plan|start|heartbeat|recover|verify-command|complete|fail|decision|block|unblock|verify-integration|finalize> <slug> ...")
478
+ console.error("Usage: ocskill work <init|plan|status|resume|gate-receipt|approve-plan|start|attach-session|heartbeat|recover|recover-task|events|verify-command|complete|fail|decision|block|unblock|verify-integration|finalize> <slug> ...")
394
479
  process.exitCode = 2
395
480
  return
396
481
  }
397
482
 
398
483
  try {
399
484
  if (action === "init") {
400
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
401
- printJson(await initWork(root, slug, optionValue("--goal")))
485
+ const root = positionalArg(args, 3) || process.cwd()
486
+ printJson(await initWork(root, slug, optionValue(args, "--goal")))
402
487
  return
403
488
  }
404
489
  if (action === "plan") {
405
490
  const planFile = args[3]
406
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
491
+ const root = positionalArg(args, 4) || process.cwd()
407
492
  if (!planFile) throw new Error("Usage: ocskill work plan <slug> <plan.json> [dir]")
408
493
  const result = await importPlan(root, slug, planFile)
409
494
  printJson({ state: result.state, analysis: result.analysis, dir: result.paths.dir })
410
495
  return
411
496
  }
412
497
  if (action === "status") {
413
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
498
+ const root = positionalArg(args, 3) || process.cwd()
414
499
  printJson(await workStatus(root, slug))
415
500
  return
416
501
  }
417
502
  if (action === "resume") {
418
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
503
+ const root = positionalArg(args, 3) || process.cwd()
419
504
  printJson(await resumeWork(root, slug))
420
505
  return
421
506
  }
507
+ if (action === "gate-receipt") {
508
+ const kind = args[3]
509
+ const root = positionalArg(args, 4) || process.cwd()
510
+ if (!["plan", "integration"].includes(kind)) {
511
+ throw new Error("Usage: ocskill work gate-receipt <slug> <plan|integration> [dir] --evidence <text>")
512
+ }
513
+ const reportFile = optionValue(args, "--report-file")
514
+ const report = reportFile ? readTextFile(reportFile) : null
515
+ const input = {
516
+ verdict: optionValue(args, "--verdict") || "PASS",
517
+ verifier: optionValue(args, "--verifier") || undefined,
518
+ sessionID: optionValue(args, "--session-id"),
519
+ runId: optionValue(args, "--run-id"),
520
+ evidence: optionValue(args, "--evidence"),
521
+ report,
522
+ }
523
+ const receipt = kind === "plan"
524
+ ? await createPlanVerificationReceipt(root, slug, input)
525
+ : await createIntegrationVerificationReceipt(root, slug, input)
526
+ const outputFile = optionValue(args, "--out")
527
+ if (outputFile) {
528
+ const resolved = path.resolve(outputFile)
529
+ writeFileSync(resolved, JSON.stringify(receipt, null, 2) + "\n", "utf8")
530
+ printJson({ file: resolved, receipt })
531
+ } else {
532
+ printJson(receipt)
533
+ }
534
+ return
535
+ }
422
536
  if (action === "approve-plan") {
423
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
424
- printJson(await approvePlan(root, slug, optionValue("--evidence")))
537
+ const root = positionalArg(args, 3) || process.cwd()
538
+ const receiptFile = optionValue(args, "--receipt-file")
539
+ const receipt = receiptFile ? readJsonFile(receiptFile) : null
540
+ printJson(await approvePlan(root, slug, optionValue(args, "--evidence"), { receipt }))
425
541
  return
426
542
  }
427
543
  if (action === "start") {
428
544
  const taskID = args[3]
429
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
545
+ const root = positionalArg(args, 4) || process.cwd()
430
546
  if (!taskID) throw new Error("Usage: ocskill work start <slug> <task-id> [dir]")
431
547
  printJson(await startTask(root, slug, taskID, {
432
- leaseMs: Number.parseInt(optionValue("--lease-ms") || "0", 10) || undefined,
548
+ leaseMs: optionIntOrUndefined(args, "--lease-ms"),
433
549
  }))
434
550
  return
435
551
  }
552
+ if (action === "attach-session") {
553
+ const taskID = args[3]
554
+ const root = positionalArg(args, 4) || process.cwd()
555
+ if (!taskID) throw new Error("Usage: ocskill work attach-session <slug> <task-id> [dir] --run-id <id> --session-id <id>")
556
+ printJson(await attachTaskSession(
557
+ root,
558
+ slug,
559
+ taskID,
560
+ optionValue(args, "--run-id"),
561
+ optionValue(args, "--session-id"),
562
+ {
563
+ executionDir: optionValue(args, "--execution-dir"),
564
+ sandboxDir: optionValue(args, "--sandbox-dir"),
565
+ },
566
+ ))
567
+ return
568
+ }
436
569
  if (action === "heartbeat") {
437
570
  const taskID = args[3]
438
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
439
- if (!taskID) throw new Error("Usage: ocskill work heartbeat <slug> <task-id> [dir] [--run-id <id>]")
440
- printJson(await heartbeatTask(root, slug, taskID, optionValue("--run-id"), {
441
- leaseMs: Number.parseInt(optionValue("--lease-ms") || "0", 10) || undefined,
571
+ const root = positionalArg(args, 4) || process.cwd()
572
+ const runId = optionValue(args, "--run-id")
573
+ if (!taskID || !runId) throw new Error("Usage: ocskill work heartbeat <slug> <task-id> [dir] --run-id <id>")
574
+ printJson(await heartbeatTask(root, slug, taskID, runId, {
575
+ leaseMs: optionIntOrUndefined(args, "--lease-ms"),
442
576
  }))
443
577
  return
444
578
  }
445
579
  if (action === "recover") {
446
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
580
+ const root = positionalArg(args, 3) || process.cwd()
447
581
  printJson(await recoverStaleTasks(root, slug, { force: args.includes("--force") }))
448
582
  return
449
583
  }
584
+ if (action === "recover-task") {
585
+ const taskID = args[3]
586
+ const root = positionalArg(args, 4) || process.cwd()
587
+ if (!taskID) throw new Error("Usage: ocskill work recover-task <slug> <task-id> [dir] [--force] [--reason <text>]")
588
+ printJson(await recoverTask(root, slug, taskID, {
589
+ force: args.includes("--force"),
590
+ reason: optionValue(args, "--reason"),
591
+ }))
592
+ return
593
+ }
594
+ if (action === "checkpoint") {
595
+ const taskID = args[3]
596
+ const root = positionalArg(args, 4) || process.cwd()
597
+ if (!taskID) throw new Error("Usage: ocskill work checkpoint <slug> <task-id> [dir] --run-id <id> [--reason <text>]")
598
+ printJson(await checkpointWork(root, slug, {
599
+ taskID,
600
+ runId: optionValue(args, "--run-id"),
601
+ reason: optionValue(args, "--reason") || "pre-compaction",
602
+ }))
603
+ return
604
+ }
605
+ if (action === "checkpoint-resumed") {
606
+ const taskID = args[3]
607
+ const root = positionalArg(args, 4) || process.cwd()
608
+ if (!taskID) throw new Error("Usage: ocskill work checkpoint-resumed <slug> <task-id> [dir] --run-id <id> [--reason <text>]")
609
+ printJson(await markCheckpointResumed(root, slug, {
610
+ taskID,
611
+ runId: optionValue(args, "--run-id"),
612
+ reason: optionValue(args, "--reason"),
613
+ }))
614
+ return
615
+ }
616
+ if (action === "events") {
617
+ const root = positionalArg(args, 3) || process.cwd()
618
+ const limit = optionInt(args, "--limit", 200)
619
+ printJson(await runtimeEvents(root, slug, { limit }))
620
+ return
621
+ }
450
622
  if (action === "verify-command") {
451
623
  const taskID = args[3]
452
- const root = args[4] && args[4] !== "--" && !args[4].startsWith("--") ? args[4] : process.cwd()
624
+ const root = positionalArg(args, 4) || process.cwd()
453
625
  const separator = args.indexOf("--")
454
626
  const executable = separator >= 0 ? args[separator + 1] : null
455
627
  const commandArgs = separator >= 0 ? args.slice(separator + 2) : []
456
- if (!taskID || !executable) {
457
- throw new Error("Usage: ocskill work verify-command <slug> <task-id> [dir] [--run-id <id>] -- <command> [args...]")
628
+ const runId = optionValue(args, "--run-id")
629
+ if (!taskID || !runId || !executable) {
630
+ throw new Error("Usage: ocskill work verify-command <slug> <task-id> [dir] --run-id <id> -- <command> [args...]")
458
631
  }
459
632
  const startedAt = new Date().toISOString()
460
633
  const before = workspaceFingerprint(root)
@@ -465,7 +638,7 @@ async function workControl() {
465
638
  })
466
639
  const receipt = createVerificationReceipt({
467
640
  task: taskID,
468
- runId: optionValue("--run-id"),
641
+ runId,
469
642
  command: executable,
470
643
  args: commandArgs,
471
644
  cwd: path.resolve(root),
@@ -479,15 +652,11 @@ async function workControl() {
479
652
  workspaceAfter: workspaceFingerprint(root),
480
653
  })
481
654
  const recorded = await recordVerificationReceipt(root, slug, taskID, receipt)
482
- const clip = (value) => {
483
- const text = String(value || "")
484
- return text.length <= 8000 ? text : "...[truncated]\n" + text.slice(-8000)
485
- }
486
655
  printJson({
487
656
  receipt: recorded,
488
657
  output: {
489
- stdout: clip(result.stdout),
490
- stderr: clip(result.stderr),
658
+ stdout: clipOutput(result.stdout),
659
+ stderr: clipOutput(result.stderr),
491
660
  },
492
661
  })
493
662
  if ((result.status ?? 1) !== 0) process.exitCode = result.status ?? 1
@@ -495,61 +664,66 @@ async function workControl() {
495
664
  }
496
665
  if (action === "complete") {
497
666
  const taskID = args[3]
498
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
499
- if (!taskID) throw new Error("Usage: ocskill work complete <slug> <task-id> [dir] --evidence <text>")
500
- const reportFile = optionValue("--report-file")
501
- const report = reportFile ? readFileSync(path.resolve(reportFile), "utf8") : null
667
+ const root = positionalArg(args, 4) || process.cwd()
668
+ const runId = optionValue(args, "--run-id")
669
+ if (!taskID || !runId) throw new Error("Usage: ocskill work complete <slug> <task-id> [dir] --run-id <id> --evidence <text>")
670
+ const reportFile = optionValue(args, "--report-file")
671
+ const report = reportFile ? readTextFile(reportFile) : null
502
672
  printJson(await completeTask(root, slug, taskID, {
503
- evidence: optionValue("--evidence"),
673
+ evidence: optionValue(args, "--evidence"),
504
674
  report,
505
- runId: optionValue("--run-id"),
675
+ runId,
506
676
  }))
507
677
  return
508
678
  }
509
679
  if (action === "fail") {
510
680
  const taskID = args[3]
511
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
512
- if (!taskID) throw new Error("Usage: ocskill work fail <slug> <task-id> [dir] --reason <text>")
513
- printJson(await failTask(root, slug, taskID, optionValue("--reason"), { runId: optionValue("--run-id") }))
681
+ const root = positionalArg(args, 4) || process.cwd()
682
+ const runId = optionValue(args, "--run-id")
683
+ if (!taskID || !runId) throw new Error("Usage: ocskill work fail <slug> <task-id> [dir] --run-id <id> --reason <text>")
684
+ printJson(await failTask(root, slug, taskID, optionValue(args, "--reason"), { runId }))
514
685
  return
515
686
  }
516
687
  if (action === "decision") {
517
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
518
- printJson(await addDecision(root, slug, optionValue("--text")))
688
+ const root = positionalArg(args, 3) || process.cwd()
689
+ printJson(await addDecision(root, slug, optionValue(args, "--text")))
519
690
  return
520
691
  }
521
692
  if (action === "block") {
522
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
523
- printJson(await addBlocker(root, slug, optionValue("--text")))
693
+ const root = positionalArg(args, 3) || process.cwd()
694
+ printJson(await addBlocker(root, slug, optionValue(args, "--text")))
524
695
  return
525
696
  }
526
697
  if (action === "unblock") {
527
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
528
- printJson(await resolveBlocker(root, slug, optionValue("--text")))
698
+ const root = positionalArg(args, 3) || process.cwd()
699
+ printJson(await resolveBlocker(root, slug, optionValue(args, "--text")))
529
700
  return
530
701
  }
531
702
  if (action === "verify-integration") {
532
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
533
- const reportFile = optionValue("--report-file")
534
- const report = reportFile ? readFileSync(path.resolve(reportFile), "utf8") : null
703
+ const root = positionalArg(args, 3) || process.cwd()
704
+ const reportFile = optionValue(args, "--report-file")
705
+ const report = reportFile ? readTextFile(reportFile) : null
706
+ const receiptFile = optionValue(args, "--receipt-file")
707
+ const receipt = receiptFile ? readJsonFile(receiptFile) : null
535
708
  printJson(await recordIntegrationVerification(
536
709
  root,
537
710
  slug,
538
- optionValue("--verdict"),
539
- optionValue("--evidence"),
711
+ optionValue(args, "--verdict"),
712
+ optionValue(args, "--evidence"),
540
713
  report,
714
+ { receipt },
541
715
  ))
542
716
  return
543
717
  }
544
718
  if (action === "finalize") {
545
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
546
- printJson(await finalizeWork(root, slug, optionValue("--evidence")))
719
+ const root = positionalArg(args, 3) || process.cwd()
720
+ printJson(await finalizeWork(root, slug, optionValue(args, "--evidence")))
547
721
  return
548
722
  }
549
723
 
550
724
  throw new Error("Unknown work action: " + action)
551
725
  } catch (error) {
552
- console.error(error instanceof Error ? error.message : error)
726
+ console.error(errorMessage(error))
553
727
  if (error?.validation) printJson(error.validation)
554
728
  process.exitCode = 1
555
729
  }
@@ -562,10 +736,10 @@ async function modelPolicy() {
562
736
  process.exitCode = 2
563
737
  return
564
738
  }
565
- const attempt = Number.parseInt(optionValue("--attempt") || "1", 10)
739
+ const attempt = optionInt(args, "--attempt", 1)
566
740
  const policy = await readModelPolicy(getConfigDir())
567
741
  const normalizedAttempt = Number.isInteger(attempt) && attempt > 0 ? attempt : 1
568
- const taskText = optionValue("--text")
742
+ const taskText = optionValue(args, "--text")
569
743
  if (taskText) {
570
744
  printJson(resolveAdaptiveModel(role, normalizedAttempt, classifyEngineeringTask(taskText), policy))
571
745
  return
@@ -627,7 +801,7 @@ async function modelsControl() {
627
801
  async function routerControl() {
628
802
  const action = args[1] || "status"
629
803
  const maxIndex = args.indexOf("--max")
630
- const maxValue = maxIndex >= 0 ? Number.parseInt(args[maxIndex + 1] || "", 10) : null
804
+ const maxValue = maxIndex >= 0 ? Number.parseInt(optionValue(args, "--max") ?? "", 10) : null
631
805
 
632
806
  if (!["status", "on", "off"].includes(action)) {
633
807
  console.error("Usage: ocskill router [status|on|off] [--max 1..6]")
@@ -678,42 +852,76 @@ async function taskPolicyControl() {
678
852
  async function sandboxControl() {
679
853
  const action = args[1] || "list"
680
854
  try {
855
+ if (action === "capability") {
856
+ printJson(containerSandboxCapability(optionValue(args, "--engine")))
857
+ return
858
+ }
859
+ if (action === "exec") {
860
+ const separator = args.indexOf("--")
861
+ const root = positionalArg(args, 2) || process.cwd()
862
+ const executable = separator >= 0 ? args[separator + 1] : null
863
+ const commandArgs = separator >= 0 ? args.slice(separator + 2) : []
864
+ const image = optionValue(args, "--image")
865
+ if (!image || !executable) {
866
+ throw new Error("Usage: ocskill sandbox exec [dir] --image <image> [--engine docker|podman] -- <command> [args...]")
867
+ }
868
+ const result = runContainerSandbox(root, {
869
+ engine: optionValue(args, "--engine"),
870
+ image,
871
+ command: executable,
872
+ args: commandArgs,
873
+ timeoutMs: optionInt(args, "--timeout-ms", 10 * 60_000),
874
+ })
875
+ printJson({ ...result, stdout: clipOutput(result.stdout), stderr: clipOutput(result.stderr) })
876
+ if (result.status !== 0) process.exitCode = result.status
877
+ return
878
+ }
681
879
  if (action === "list") {
682
- printJson(listTaskSandboxes(args[2] || process.cwd()))
880
+ printJson(listTaskSandboxes(positionalArg(args, 2) || process.cwd()))
683
881
  return
684
882
  }
685
883
  if (action === "create") {
686
884
  const slug = args[2]
687
885
  const taskID = args[3]
688
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
886
+ const root = positionalArg(args, 4) || process.cwd()
689
887
  if (!slug || !taskID) throw new Error("Usage: ocskill sandbox create <slug> <task-id> [dir]")
690
888
  printJson(await createTaskSandbox(root, slug, taskID))
691
889
  return
692
890
  }
891
+ if (action === "integrate") {
892
+ const dir = args[2]
893
+ const root = positionalArg(args, 3) || process.cwd()
894
+ if (!dir) throw new Error("Usage: ocskill sandbox integrate <worktree-path> [dir] [--keep]")
895
+ printJson(await integrateTaskSandbox(root, dir, { keep: args.includes("--keep") }))
896
+ return
897
+ }
693
898
  if (action === "remove") {
694
899
  const dir = args[2]
695
- const root = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
696
- if (!dir) throw new Error("Usage: ocskill sandbox remove <worktree-path> [dir] [--force]")
697
- printJson(await removeTaskSandbox(root, dir, { force: args.includes("--force") }))
900
+ const root = positionalArg(args, 3) || process.cwd()
901
+ if (!dir) throw new Error("Usage: ocskill sandbox remove <worktree-path> [dir] [--force] [--delete-branch]")
902
+ printJson(await removeTaskSandbox(root, dir, {
903
+ force: args.includes("--force"),
904
+ deleteBranch: args.includes("--delete-branch"),
905
+ }))
698
906
  return
699
907
  }
700
- throw new Error("Usage: ocskill sandbox <list|create|remove> ...")
908
+ throw new Error("Usage: ocskill sandbox <capability|exec|list|create|integrate|remove> ...")
701
909
  } catch (error) {
702
- console.error(error instanceof Error ? error.message : error)
910
+ console.error(errorMessage(error))
703
911
  process.exitCode = 1
704
912
  }
705
913
  }
706
914
 
707
915
  async function learningControl() {
708
916
  const action = args[1] || "status"
709
- const root = args[2] && !args[2].startsWith("--") ? args[2] : process.cwd()
917
+ const root = positionalArg(args, 2) || process.cwd()
710
918
  try {
711
919
  if (action === "status") {
712
920
  printJson(await readLearningState(root))
713
921
  return
714
922
  }
715
923
  if (action === "analyze") {
716
- const evalDir = optionValue("--eval-dir") || path.join(path.resolve(root), ".ues-evals")
924
+ const evalDir = optionValue(args, "--eval-dir") || path.join(path.resolve(root), ".ues-evals")
717
925
  const analysis = await analyzeEvalTraces(evalDir)
718
926
  const state = await saveLearningAnalysis(root, analysis)
719
927
  printJson({ analysis, state })
@@ -721,14 +929,23 @@ async function learningControl() {
721
929
  }
722
930
  if (action === "accept") {
723
931
  const id = args[2]
724
- const acceptRoot = args[3] && !args[3].startsWith("--") ? args[3] : process.cwd()
932
+ const acceptRoot = positionalArg(args, 3) || process.cwd()
725
933
  if (!id) throw new Error("Usage: ocskill learn accept <proposal-id> [dir]")
726
934
  printJson(await acceptLearning(acceptRoot, id))
727
935
  return
728
936
  }
729
- throw new Error("Usage: ocskill learn <status|analyze|accept> ...")
937
+ if (action === "promote") {
938
+ const id = args[2]
939
+ const promoteRoot = positionalArg(args, 3) || process.cwd()
940
+ if (!id) throw new Error("Usage: ocskill learn promote <proposal-id> [dir] --report <matrix-summary.json>")
941
+ printJson(await promoteLearning(promoteRoot, id, {
942
+ report: optionValue(args, "--report"),
943
+ }))
944
+ return
945
+ }
946
+ throw new Error("Usage: ocskill learn <status|analyze|accept|promote> ...")
730
947
  } catch (error) {
731
- console.error(error instanceof Error ? error.message : error)
948
+ console.error(errorMessage(error))
732
949
  process.exitCode = 1
733
950
  }
734
951
  }
@@ -742,7 +959,7 @@ async function hermesControl() {
742
959
  if (action === "prompt" || action === "exec") {
743
960
  const slug = args[2]
744
961
  const taskID = args[3]
745
- const root = args[4] && !args[4].startsWith("--") ? args[4] : process.cwd()
962
+ const root = positionalArg(args, 4) || process.cwd()
746
963
  if (!slug || !taskID) {
747
964
  console.error("Usage: ocskill hermes <prompt|exec> <slug> <task-id> [dir]")
748
965
  process.exitCode = 2
@@ -796,7 +1013,7 @@ async function update() {
796
1013
  })
797
1014
  } catch (error) {
798
1015
  console.error("[ocskill] Could not determine the latest published npm version; refusing an unsafe self-update.")
799
- console.error(error instanceof Error ? error.message : error)
1016
+ console.error(errorMessage(error))
800
1017
  process.exitCode = error?.exitCode || 1
801
1018
  return
802
1019
  }
@@ -808,7 +1025,7 @@ async function update() {
808
1025
  compared = compareVersions(latestVersion, currentVersion)
809
1026
  } catch (error) {
810
1027
  console.error("[ocskill] npm returned a version that could not be compared safely; refusing update.")
811
- console.error(error instanceof Error ? error.message : error)
1028
+ console.error(errorMessage(error))
812
1029
  process.exitCode = 1
813
1030
  return
814
1031
  }
@@ -906,6 +1123,15 @@ switch (command) {
906
1123
  case "repo-graph":
907
1124
  await inspectRepoGraph()
908
1125
  break
1126
+ case "index":
1127
+ await semanticIndexControl()
1128
+ break
1129
+ case "aci":
1130
+ await aciControl()
1131
+ break
1132
+ case "trace":
1133
+ await traceControl()
1134
+ break
909
1135
  case "review-scope":
910
1136
  await inspectReviewScope()
911
1137
  break