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.
- package/CHANGELOG.md +112 -3
- package/README.md +396 -281
- package/bin/ocskill.mjs +382 -156
- package/docs/DETERMINISTIC-TOOLS.md +25 -8
- package/docs/ENGINEERING-DESIGN.md +31 -13
- package/docs/EVALS.md +34 -12
- package/docs/NPM-PUBLISH.md +6 -6
- package/docs/OPENCODE-COMPAT.md +11 -8
- package/docs/TRACE-SCHEMA.md +15 -2
- package/docs/V8-INTELLIGENCE-RELIABILITY.md +206 -0
- package/docs/V9-SPEED-INTELLIGENCE.md +102 -0
- package/evals/live/tasks.json +6 -6
- package/evals/polyglot/fixtures/polyglot-bench/api/generated/client.ts +2 -0
- package/evals/polyglot/fixtures/polyglot-bench/api/openapi.json +25 -0
- package/evals/polyglot/fixtures/polyglot-bench/db/migrations/20260920_add_order_key.sql +1 -0
- package/evals/polyglot/fixtures/polyglot-bench/dotnet/OrderService.cs +8 -0
- package/evals/polyglot/fixtures/polyglot-bench/java/PriceService.java +5 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/package.json +6 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/api/package.json +4 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/packages/web/package.json +7 -0
- package/evals/polyglot/fixtures/polyglot-bench/monorepo/pnpm-lock.yaml +5 -0
- package/evals/polyglot/fixtures/polyglot-bench/next/app/api/products/route.ts +7 -0
- package/evals/polyglot/fixtures/polyglot-bench/python/tenant_auth.py +4 -0
- package/evals/polyglot/fixtures/polyglot-bench/react-native/keyboard.ts +3 -0
- package/evals/polyglot/graders/polyglot-bench.mjs +101 -0
- package/evals/polyglot/tasks.json +54 -0
- package/global-config/AGENTS.md +78 -160
- package/global-config/agents/integration-verifier.md +1 -1
- package/global-config/agents/plan-checker.md +1 -1
- package/global-config/commands/run.md +9 -5
- package/global-config/plugins/ues-router/capabilities.js +4 -0
- package/global-config/plugins/ues-router/index.js +784 -37
- package/global-config/plugins/ues-router/router.js +175 -23
- package/global-config/plugins/ues-router/runtime-guard.js +265 -0
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +6 -4
- package/lib/aci.mjs +128 -0
- package/lib/benchmark-confidence.mjs +173 -0
- package/lib/cli-utils.mjs +41 -0
- package/lib/container-sandbox.mjs +102 -0
- package/lib/context-manifest.mjs +300 -22
- package/lib/control-center.mjs +36 -3
- package/lib/eval-ablation.mjs +104 -0
- package/lib/eval-order.mjs +9 -0
- package/lib/eval-report.mjs +11 -0
- package/lib/eval-telemetry.mjs +8 -2
- package/lib/gate-receipt.mjs +52 -0
- package/lib/installer.mjs +39 -25
- package/lib/learning-engine.mjs +236 -38
- package/lib/model-policy.mjs +6 -0
- package/lib/opencode-compat.mjs +25 -10
- package/lib/orchestrator-policy.mjs +195 -21
- package/lib/process-runner.mjs +30 -9
- package/lib/runtime-events.mjs +31 -0
- package/lib/semantic-index.mjs +318 -0
- package/lib/task-engine.mjs +557 -28
- package/lib/trajectory.mjs +89 -0
- package/lib/windows-shim.mjs +227 -0
- package/lib/worktree-sandbox.mjs +85 -3
- package/package.json +11 -4
- package/scripts/check-release-tag.mjs +22 -0
- package/scripts/control-center.mjs +25 -0
- package/scripts/eval-ablation.mjs +44 -0
- package/scripts/eval-live.mjs +39 -58
- package/scripts/eval-matrix.mjs +166 -0
- package/scripts/smoke-packed-install.mjs +138 -4
- package/scripts/smoke-plain-install.mjs +91 -0
- package/scripts/validate-live-suite.mjs +3 -3
- package/scripts/validate.mjs +27 -5
package/bin/ocskill.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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> ...
|
|
91
|
-
|
|
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
|
|
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
|
|
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
|
|
113
|
-
ocskill work
|
|
114
|
-
ocskill work
|
|
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 =
|
|
172
|
-
if (!resolved)
|
|
173
|
-
|
|
174
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
202
|
-
if (!resolved)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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(
|
|
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
|
-
|
|
282
|
-
|
|
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
|
|
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
|
|
320
|
+
printJson(await impactMap(positionalArg(args, 2) || process.cwd(), query))
|
|
323
321
|
}
|
|
324
322
|
|
|
325
323
|
async function inspectEvidence() {
|
|
326
|
-
printJson(await collectEvidence(args
|
|
324
|
+
printJson(await collectEvidence(positionalArg(args, 1) || process.cwd()))
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
async function inspectWorkingTree() {
|
|
330
|
-
printJson(await checkWorkingTree(args
|
|
328
|
+
printJson(await checkWorkingTree(positionalArg(args, 1) || process.cwd()))
|
|
331
329
|
}
|
|
332
330
|
|
|
333
331
|
async function inspectStack() {
|
|
334
|
-
printJson(await detectStack(args
|
|
332
|
+
printJson(await detectStack(positionalArg(args, 1) || process.cwd()))
|
|
335
333
|
}
|
|
336
334
|
|
|
337
335
|
async function inspectTests() {
|
|
338
|
-
printJson(await detectTestCommands(args
|
|
336
|
+
printJson(await detectTestCommands(positionalArg(args, 1) || process.cwd()))
|
|
339
337
|
}
|
|
340
338
|
|
|
341
|
-
function
|
|
342
|
-
|
|
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
|
|
347
|
-
|
|
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
|
|
352
|
-
const root = args
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
424
|
-
|
|
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
|
|
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:
|
|
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
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
457
|
-
|
|
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
|
|
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:
|
|
490
|
-
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
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
const
|
|
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
|
|
675
|
+
runId,
|
|
506
676
|
}))
|
|
507
677
|
return
|
|
508
678
|
}
|
|
509
679
|
if (action === "fail") {
|
|
510
680
|
const taskID = args[3]
|
|
511
|
-
const root = args
|
|
512
|
-
|
|
513
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
533
|
-
const reportFile = optionValue("--report-file")
|
|
534
|
-
const report = reportFile ?
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
696
|
-
if (!dir) throw new Error("Usage: ocskill sandbox remove <worktree-path> [dir] [--force]")
|
|
697
|
-
printJson(await removeTaskSandbox(root, dir, {
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|