opencode-agent-skill 12.0.0-beta.0 → 13.0.0-beta.1
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 +48 -0
- package/README.md +110 -11
- package/bin/ocskill.mjs +394 -84
- package/docs/NPM-PUBLISH.md +20 -6
- package/docs/OPENCODE-COMPAT.md +12 -2
- package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +75 -0
- package/global-config/AGENTS.md +4 -0
- package/global-config/commands/resume.md +4 -1
- package/global-config/commands/run.md +9 -7
- package/global-config/plugins/ues-router/capabilities.js +1 -0
- package/global-config/plugins/ues-router/command-runtime.js +111 -0
- package/global-config/plugins/ues-router/index.js +381 -43
- package/global-config/plugins/ues-router/parallel-runtime.js +271 -0
- package/global-config/plugins/ues-router/text-runtime.js +115 -0
- package/global-config/plugins/ues-router/verifier-runtime.js +33 -0
- package/global-config/skills/dynamic-workflow/SKILL.md +7 -6
- package/global-config/skills/dynamic-workflow/references/workflow.md +8 -6
- package/global-config/skills/engineering-orchestrator/references/long-horizon.md +7 -5
- package/lib/cli-utils.mjs +17 -4
- package/lib/installer.mjs +50 -16
- package/lib/task-engine.mjs +19 -9
- package/lib/task-graph.mjs +32 -0
- package/lib/text-encoding.mjs +74 -0
- package/lib/worktree-sandbox.mjs +141 -12
- package/package.json +5 -4
- package/scripts/check-release-consistency.mjs +33 -1
- package/scripts/smoke-packed-install.mjs +39 -3
- package/scripts/smoke-plain-install.mjs +27 -7
- package/scripts/validate.mjs +18 -1
package/bin/ocskill.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { writeFileSync } from "node:fs"
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, 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"
|
|
@@ -62,7 +62,7 @@ import { buildVerificationPlan } from "../lib/verification-plan.mjs"
|
|
|
62
62
|
import { resolveAdaptiveModel, resolveCapabilityModel, resolveModel } from "../lib/model-policy.mjs"
|
|
63
63
|
import { createVerificationReceipt } from "../lib/evidence-receipt.mjs"
|
|
64
64
|
import { classifyEngineeringTask } from "../lib/orchestrator-policy.mjs"
|
|
65
|
-
import { createTaskSandbox, integrateTaskSandbox, listTaskSandboxes, removeTaskSandbox } from "../lib/worktree-sandbox.mjs"
|
|
65
|
+
import { createTaskSandbox, integrateTaskSandbox, listTaskSandboxes, removeTaskSandbox, rollbackTaskSandbox } from "../lib/worktree-sandbox.mjs"
|
|
66
66
|
import { analyzeEvalTraces, saveLearningAnalysis, readLearningState, acceptLearning, promoteLearning } from "../lib/learning-engine.mjs"
|
|
67
67
|
import { hermesStatus, buildHermesDelegationPrompt, buildHermesWorkflowPrompt, hermesOneShotArgs, hermesSidecarPlan } from "../lib/hermes-bridge.mjs"
|
|
68
68
|
import { readModelPolicy, recordModelPerformance, validateModelID, writeModelPolicy } from "../lib/model-config.mjs"
|
|
@@ -77,6 +77,7 @@ import { planDynamicWorkflow } from "../lib/dynamic-workflow.mjs"
|
|
|
77
77
|
import { lintSkillCatalog } from "../lib/skill-quality.mjs"
|
|
78
78
|
import { designTokenEvidence, extractDesignTokens, inspectResponsiveLayout } from "../lib/ui-inspector.mjs"
|
|
79
79
|
import {
|
|
80
|
+
cliErrorPayload,
|
|
80
81
|
clipOutput,
|
|
81
82
|
errorMessage,
|
|
82
83
|
optionInt,
|
|
@@ -85,10 +86,22 @@ import {
|
|
|
85
86
|
positionalArg,
|
|
86
87
|
readJsonFile,
|
|
87
88
|
readTextFile,
|
|
89
|
+
usageError,
|
|
88
90
|
} from "../lib/cli-utils.mjs"
|
|
89
91
|
|
|
90
|
-
const
|
|
92
|
+
const rawArgs = process.argv.slice(2)
|
|
93
|
+
const rawSeparator = rawArgs.indexOf("--")
|
|
94
|
+
const jsonOutput = rawArgs.some((value, index) =>
|
|
95
|
+
value === "--json" && (rawSeparator < 0 || index < rawSeparator),
|
|
96
|
+
)
|
|
97
|
+
const args = rawArgs.filter((value, index) =>
|
|
98
|
+
!(value === "--json" && (rawSeparator < 0 || index < rawSeparator)),
|
|
99
|
+
)
|
|
91
100
|
const command = args[0] || "help"
|
|
101
|
+
const argsSeparator = args.indexOf("--")
|
|
102
|
+
const helpRequested = args.some((value, index) =>
|
|
103
|
+
(value === "--help" || value === "-h") && (argsSeparator < 0 || index < argsSeparator),
|
|
104
|
+
)
|
|
92
105
|
const force = args.includes("--force")
|
|
93
106
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
94
107
|
|
|
@@ -107,7 +120,11 @@ Usage:
|
|
|
107
120
|
ocskill impact <query> [dir] Search likely impact paths and matching lines
|
|
108
121
|
ocskill evidence [dir] Collect stack, verification and Git evidence
|
|
109
122
|
ocskill working-tree [dir] Report Git branch/HEAD/dirty state
|
|
110
|
-
ocskill
|
|
123
|
+
ocskill diff [dir] [--out file] Emit Git diff safely as UTF-8 (Windows-safe)
|
|
124
|
+
ocskill text-read <file> [--start N] [--max N] Read UTF-8/UTF-16 text safely with bounded output
|
|
125
|
+
ocskill normalize-text <file> Convert UTF-8/UTF-16 text files to UTF-8
|
|
126
|
+
ocskill repo-graph [dir] [--compact] [--max-files N]
|
|
127
|
+
Build a bounded source import/dependency graph; compact omits full node/edge payloads
|
|
111
128
|
ocskill index <status|build|rebuild> [dir]
|
|
112
129
|
Build/reuse the persistent incremental semantic index
|
|
113
130
|
ocskill aci <search|refs|view|text> ...
|
|
@@ -124,7 +141,7 @@ Usage:
|
|
|
124
141
|
ocskill model-policy <role> [--attempt N]
|
|
125
142
|
Resolve light/standard/heavy escalation tier
|
|
126
143
|
ocskill task-policy <text> Classify task mode/risk/context/model tier
|
|
127
|
-
ocskill sandbox <action> ... Create, integrate and clean isolated Git worktree sandboxes
|
|
144
|
+
ocskill sandbox <action> ... Create, integrate, rollback and clean isolated Git worktree sandboxes
|
|
128
145
|
Also supports capability/exec for fail-closed container verification
|
|
129
146
|
ocskill learn <action> ... Analyze eval traces and promote benchmark-validated lessons
|
|
130
147
|
ocskill hermes <action> ... Optional Hermes sidecar/status/task/workflow planning
|
|
@@ -151,12 +168,15 @@ Usage:
|
|
|
151
168
|
ocskill work plan <slug> <plan.json> [dir]
|
|
152
169
|
ocskill work status|resume <slug> [dir]
|
|
153
170
|
ocskill work gate-receipt <slug> <plan|integration> [dir] --evidence <text> [--verdict PASS|FAIL|PARTIAL] [--verifier <role>] [--session-id <id>] [--report-file <file>] [--out <file>]
|
|
171
|
+
ocskill work agent-receipt <slug> <task-id> [dir] --run-id <id> --verdict PASS|FAIL --evidence <text>
|
|
154
172
|
ocskill work approve-plan <slug> [dir] --evidence <plan-checker-evidence> [--receipt-file <file>]
|
|
155
173
|
ocskill work start <slug> <task-id> [dir] [--lease-ms N]
|
|
156
174
|
ocskill work attach-session <slug> <task-id> [dir] --run-id <id> --session-id <id> [--execution-dir <dir>] [--sandbox-dir <dir>]
|
|
157
175
|
ocskill work heartbeat <slug> <task-id> [dir] --run-id <id>
|
|
158
176
|
ocskill work recover <slug> [dir] [--force]
|
|
159
177
|
ocskill work recover-task <slug> <task-id> [dir] [--force] [--reason <text>]
|
|
178
|
+
ocskill work checkpoint <slug> <task-id> [dir] --run-id <id> [--reason <text>]
|
|
179
|
+
ocskill work checkpoint-resumed <slug> <task-id> [dir] --run-id <id> [--reason <text>]
|
|
160
180
|
ocskill work events <slug> [dir] [--limit N]
|
|
161
181
|
ocskill work verify-command <slug> <task-id> [dir] --run-id <id> -- <command> [args...]
|
|
162
182
|
ocskill work complete <slug> <task-id> [dir] --run-id <id> --evidence <text> [--report-file <file>]
|
|
@@ -178,6 +198,95 @@ Usage:
|
|
|
178
198
|
`)
|
|
179
199
|
}
|
|
180
200
|
|
|
201
|
+
function printCommandHelp(commandName, subcommand) {
|
|
202
|
+
const workUsage = {
|
|
203
|
+
init: "ocskill work init <slug> [dir] --goal <text>",
|
|
204
|
+
plan: "ocskill work plan <slug> <plan.json> [dir]",
|
|
205
|
+
status: "ocskill work status [slug|dir]",
|
|
206
|
+
resume: "ocskill work resume <slug> [dir]",
|
|
207
|
+
"gate-receipt": "ocskill work gate-receipt <slug> <plan|integration> [dir] --evidence <text>",
|
|
208
|
+
"agent-receipt": "ocskill work agent-receipt <slug> <task-id> [dir] --run-id <id> --verdict PASS|FAIL --evidence <text>",
|
|
209
|
+
"approve-plan": "ocskill work approve-plan <slug> [dir] --evidence <text>",
|
|
210
|
+
start: "ocskill work start <slug> <task-id> [dir]",
|
|
211
|
+
"attach-session": "ocskill work attach-session <slug> <task-id> [dir] --run-id <id> --session-id <id>",
|
|
212
|
+
heartbeat: "ocskill work heartbeat <slug> <task-id> [dir] --run-id <id>",
|
|
213
|
+
recover: "ocskill work recover <slug> [dir]",
|
|
214
|
+
"recover-task": "ocskill work recover-task <slug> <task-id> [dir]",
|
|
215
|
+
checkpoint: "ocskill work checkpoint <slug> <task-id> [dir] --run-id <id> [--reason <text>]",
|
|
216
|
+
"checkpoint-resumed": "ocskill work checkpoint-resumed <slug> <task-id> [dir] --run-id <id> [--reason <text>]",
|
|
217
|
+
events: "ocskill work events <slug> [dir]",
|
|
218
|
+
"verify-command": "ocskill work verify-command <slug> <task-id> [dir] --run-id <id> -- <command> [args...]",
|
|
219
|
+
complete: "ocskill work complete <slug> <task-id> [dir] --run-id <id> --evidence <text>",
|
|
220
|
+
fail: "ocskill work fail <slug> <task-id> [dir] --run-id <id> --reason <text>",
|
|
221
|
+
decision: "ocskill work decision <slug> [dir] --text <decision>",
|
|
222
|
+
block: "ocskill work block <slug> [dir] --text <blocker>",
|
|
223
|
+
unblock: "ocskill work unblock <slug> [dir] --text <blocker>",
|
|
224
|
+
"verify-integration": "ocskill work verify-integration <slug> [dir] --verdict PASS|FAIL|PARTIAL --evidence <text>",
|
|
225
|
+
finalize: "ocskill work finalize <slug> [dir] --evidence <text>",
|
|
226
|
+
}
|
|
227
|
+
if (commandName === "work") {
|
|
228
|
+
if (subcommand && workUsage[subcommand]) console.log("Usage: " + workUsage[subcommand] + "\n")
|
|
229
|
+
else console.log("Usage: ocskill work <action> ...\n\nActions:\n " + Object.keys(workUsage).join("\n "))
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
if (commandName === "sandbox") {
|
|
233
|
+
console.log("Usage: ocskill sandbox <capability|exec|list|create|integrate|rollback|remove> ...\n")
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
if (commandName === "diff") {
|
|
237
|
+
console.log("Usage: ocskill diff [dir] [--base <ref>] [--out <utf8-file>]\n")
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
if (commandName === "text-read") {
|
|
241
|
+
console.log("Usage: ocskill text-read <file> [--start N] [--max N] [--json]\n")
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
if (commandName === "normalize-text") {
|
|
245
|
+
console.log("Usage: ocskill normalize-text <file> [--out <utf8-file>]\n")
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
printHelp()
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function printCliError(error, options = {}) {
|
|
252
|
+
const payload = cliErrorPayload(error, {
|
|
253
|
+
command: options.command || args.filter((value) => value !== "--help" && value !== "-h").join(" "),
|
|
254
|
+
usage: options.usage,
|
|
255
|
+
hint: options.hint,
|
|
256
|
+
recoverable: options.recoverable,
|
|
257
|
+
})
|
|
258
|
+
if (jsonOutput) console.error(JSON.stringify(payload))
|
|
259
|
+
else {
|
|
260
|
+
console.error("[ocskill] " + payload.error.code + ": " + payload.error.message)
|
|
261
|
+
if (payload.error.hint) console.error("[ocskill] Hint: " + payload.error.hint)
|
|
262
|
+
}
|
|
263
|
+
process.exitCode = payload.exitCode
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function pathLikeWorkRoot(value) {
|
|
267
|
+
return !value || value === "." || value === ".." || value.includes("/") || value.includes("\\")
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function listWorkspaces(root) {
|
|
271
|
+
root = path.resolve(root)
|
|
272
|
+
const base = path.join(root, ".ues-work")
|
|
273
|
+
if (!existsSync(base)) return []
|
|
274
|
+
const result = []
|
|
275
|
+
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
|
276
|
+
if (!entry.isDirectory()) continue
|
|
277
|
+
try {
|
|
278
|
+
const state = JSON.parse(readTextFile(path.join(base, entry.name, "STATE.json")))
|
|
279
|
+
result.push({
|
|
280
|
+
slug: entry.name,
|
|
281
|
+
status: state.status || null,
|
|
282
|
+
goal: state.goal || null,
|
|
283
|
+
updatedAt: state.updatedAt || null,
|
|
284
|
+
nextAction: state.nextAction || null,
|
|
285
|
+
})
|
|
286
|
+
} catch {}
|
|
287
|
+
}
|
|
288
|
+
return result.sort((a, b) => a.slug.localeCompare(b.slug))
|
|
289
|
+
}
|
|
181
290
|
|
|
182
291
|
function run(executable, commandArgs, options = {}) {
|
|
183
292
|
const common = { stdio: "inherit", ...options }
|
|
@@ -241,9 +350,18 @@ async function install() {
|
|
|
241
350
|
console.log(`[ocskill] Installed resources for v${result.version}`)
|
|
242
351
|
console.log(`[ocskill] OpenCode config: ${result.configDir}`)
|
|
243
352
|
console.log(`[ocskill] Skills: ${result.skills.length}`)
|
|
244
|
-
|
|
353
|
+
if (Number(result.openCodeMajor) >= 2) {
|
|
354
|
+
console.log(`[ocskill] Prompt aliases: ${(result.promptAliases || []).length} (session.prompt compatibility path)`)
|
|
355
|
+
} else {
|
|
356
|
+
console.log(`[ocskill] Commands: ${result.commands.length}`)
|
|
357
|
+
}
|
|
245
358
|
console.log(`[ocskill] Subagents: ${result.agents.length}`)
|
|
246
359
|
console.log(`[ocskill] OpenCode major: ${result.openCodeMajor}`)
|
|
360
|
+
console.log(
|
|
361
|
+
Number(result.openCodeMajor) >= 2
|
|
362
|
+
? "[ocskill] V13 parallel: runtime capability-gated; open a new OpenCode session and check ues.capabilities."
|
|
363
|
+
: "[ocskill] V13 parallel: unavailable on OpenCode 1.x; CLI/durable workflow remains available.",
|
|
364
|
+
)
|
|
247
365
|
if ((result.plugins || []).length) console.log(`[ocskill] Router plugins: ${result.plugins.length}`)
|
|
248
366
|
for (const warning of result.warnings) console.warn(`[ocskill] WARNING: ${warning}`)
|
|
249
367
|
console.log("[ocskill] Start a new OpenCode session to pick up workflow changes.")
|
|
@@ -268,15 +386,25 @@ async function status() {
|
|
|
268
386
|
console.log(`[ocskill] Sync: ${synced ? "OK" : "OUTDATED - run ocskill install"}`)
|
|
269
387
|
console.log(`[ocskill] Config: ${result.configDir}`)
|
|
270
388
|
console.log(`[ocskill] Skills: ${result.skillsPresent}/${result.skills.length}`)
|
|
271
|
-
|
|
389
|
+
if (Number(result.openCodeMajor) >= 2) {
|
|
390
|
+
console.log(`[ocskill] Prompt aliases: ${result.promptAliasesPresent || 0}/${(result.promptAliases || []).length}`)
|
|
391
|
+
} else {
|
|
392
|
+
console.log(`[ocskill] Commands: ${result.commandsPresent}/${result.commands.length}`)
|
|
393
|
+
}
|
|
272
394
|
console.log(`[ocskill] Subagents: ${result.agentsPresent}/${(result.agents || []).length}`)
|
|
273
395
|
console.log(`[ocskill] OpenCode major: ${result.openCodeMajor ?? "legacy/unknown"}`)
|
|
396
|
+
console.log(
|
|
397
|
+
Number(result.openCodeMajor) >= 2
|
|
398
|
+
? "[ocskill] V13 parallel: runtime capability-gated; verify freshDispatch with ues.capabilities in a new session."
|
|
399
|
+
: "[ocskill] V13 parallel: unavailable on OpenCode 1.x; use serial durable execution or upgrade the runtime.",
|
|
400
|
+
)
|
|
274
401
|
if ((result.plugins || []).length) console.log(`[ocskill] Router plugins: ${result.pluginsPresent}/${result.plugins.length}`)
|
|
275
402
|
console.log(`[ocskill] Workflow: ${result.workflowPresent ? "OK" : "MISSING"}`)
|
|
276
403
|
|
|
277
404
|
if (!synced ||
|
|
278
405
|
result.skillsPresent !== result.skills.length ||
|
|
279
406
|
result.commandsPresent !== result.commands.length ||
|
|
407
|
+
(result.promptAliasesPresent || 0) !== (result.promptAliases || []).length ||
|
|
280
408
|
result.agentsPresent !== (result.agents || []).length ||
|
|
281
409
|
result.pluginsPresent !== (result.plugins || []).length ||
|
|
282
410
|
!result.workflowPresent) {
|
|
@@ -332,8 +460,7 @@ async function inspectRepository() {
|
|
|
332
460
|
async function inspectImpact() {
|
|
333
461
|
const query = args[1]
|
|
334
462
|
if (!query) {
|
|
335
|
-
|
|
336
|
-
process.exitCode = 2
|
|
463
|
+
printCliError(Object.assign(new Error("Usage: ocskill impact <query> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
337
464
|
return
|
|
338
465
|
}
|
|
339
466
|
printJson(await impactMap(positionalArg(args, 2) || process.cwd(), query))
|
|
@@ -356,7 +483,26 @@ async function inspectTests() {
|
|
|
356
483
|
}
|
|
357
484
|
|
|
358
485
|
async function inspectRepoGraph() {
|
|
359
|
-
|
|
486
|
+
const root = positionalArg(args, 1) || process.cwd()
|
|
487
|
+
const parsedMaxFiles = optionInt(args, "--max-files", 2500)
|
|
488
|
+
const maxFiles = Number.isFinite(parsedMaxFiles)
|
|
489
|
+
? Math.max(100, Math.min(parsedMaxFiles, 10000))
|
|
490
|
+
: 2500
|
|
491
|
+
const graph = await buildRepoGraph(root, { maxFiles })
|
|
492
|
+
if (args.includes("--compact")) {
|
|
493
|
+
printJson({
|
|
494
|
+
schemaVersion: graph.schemaVersion,
|
|
495
|
+
root: graph.root,
|
|
496
|
+
scannedFiles: graph.scannedFiles,
|
|
497
|
+
truncated: graph.truncated,
|
|
498
|
+
nodeCount: graph.nodes.length,
|
|
499
|
+
edgeCount: graph.edges.length,
|
|
500
|
+
hotspots: graph.hotspots,
|
|
501
|
+
externalImports: graph.externalImports,
|
|
502
|
+
})
|
|
503
|
+
return
|
|
504
|
+
}
|
|
505
|
+
printJson(graph)
|
|
360
506
|
}
|
|
361
507
|
|
|
362
508
|
async function semanticIndexControl() {
|
|
@@ -374,8 +520,7 @@ async function semanticIndexControl() {
|
|
|
374
520
|
}
|
|
375
521
|
throw new Error("Usage: ocskill index <status|build|rebuild> [dir]")
|
|
376
522
|
} catch (error) {
|
|
377
|
-
|
|
378
|
-
process.exitCode = 1
|
|
523
|
+
printCliError(error)
|
|
379
524
|
}
|
|
380
525
|
}
|
|
381
526
|
|
|
@@ -416,8 +561,7 @@ async function aciControl() {
|
|
|
416
561
|
}
|
|
417
562
|
throw new Error("Usage: ocskill aci <search|refs|view|text> ...")
|
|
418
563
|
} catch (error) {
|
|
419
|
-
|
|
420
|
-
process.exitCode = 1
|
|
564
|
+
printCliError(error)
|
|
421
565
|
}
|
|
422
566
|
}
|
|
423
567
|
|
|
@@ -446,8 +590,7 @@ async function traceControl() {
|
|
|
446
590
|
}
|
|
447
591
|
throw new Error("Usage: ocskill trace <show|append> ...")
|
|
448
592
|
} catch (error) {
|
|
449
|
-
|
|
450
|
-
process.exitCode = 1
|
|
593
|
+
printCliError(error)
|
|
451
594
|
}
|
|
452
595
|
}
|
|
453
596
|
|
|
@@ -464,8 +607,7 @@ async function inspectVerificationPlan() {
|
|
|
464
607
|
async function inspectTaskGraph() {
|
|
465
608
|
const file = args[1]
|
|
466
609
|
if (!file) {
|
|
467
|
-
|
|
468
|
-
process.exitCode = 2
|
|
610
|
+
printCliError(Object.assign(new Error("Usage: ocskill task-graph <plan.json>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
469
611
|
return
|
|
470
612
|
}
|
|
471
613
|
try {
|
|
@@ -474,8 +616,7 @@ async function inspectTaskGraph() {
|
|
|
474
616
|
printJson(analysis)
|
|
475
617
|
if (!analysis.valid) process.exitCode = 1
|
|
476
618
|
} catch (error) {
|
|
477
|
-
|
|
478
|
-
process.exitCode = 1
|
|
619
|
+
printCliError(error)
|
|
479
620
|
}
|
|
480
621
|
}
|
|
481
622
|
|
|
@@ -483,8 +624,7 @@ async function inspectContextPack() {
|
|
|
483
624
|
const slug = args[1]
|
|
484
625
|
const taskID = args[2]
|
|
485
626
|
if (!slug || !taskID) {
|
|
486
|
-
|
|
487
|
-
process.exitCode = 2
|
|
627
|
+
printCliError(Object.assign(new Error("Usage: ocskill context-pack <slug> <task-id> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
488
628
|
return
|
|
489
629
|
}
|
|
490
630
|
printJson(await contextPack(positionalArg(args, 3) || process.cwd(), slug, taskID))
|
|
@@ -493,9 +633,56 @@ async function inspectContextPack() {
|
|
|
493
633
|
async function workControl() {
|
|
494
634
|
const action = args[1]
|
|
495
635
|
const slug = args[2]
|
|
496
|
-
if (!action
|
|
497
|
-
|
|
498
|
-
|
|
636
|
+
if (!action) {
|
|
637
|
+
const error = new Error("Usage: ocskill work <action> ...")
|
|
638
|
+
error.code = "UES_USAGE"
|
|
639
|
+
error.exitCode = 2
|
|
640
|
+
printCliError(error)
|
|
641
|
+
return
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (action === "status" && pathLikeWorkRoot(slug)) {
|
|
645
|
+
const root = path.resolve(slug || process.cwd())
|
|
646
|
+
const workspaces = listWorkspaces(root)
|
|
647
|
+
const active = workspaces.filter((item) => item.status !== "completed")
|
|
648
|
+
const candidate = active.length === 1
|
|
649
|
+
? active[0]
|
|
650
|
+
: active.length === 0 && workspaces.length === 1
|
|
651
|
+
? workspaces[0]
|
|
652
|
+
: null
|
|
653
|
+
if (candidate) {
|
|
654
|
+
const status = await workStatus(root, candidate.slug)
|
|
655
|
+
printJson({
|
|
656
|
+
...status,
|
|
657
|
+
autoResolved: true,
|
|
658
|
+
autoResolvedSlug: candidate.slug,
|
|
659
|
+
requestedRoot: root,
|
|
660
|
+
})
|
|
661
|
+
} else {
|
|
662
|
+
printJson({
|
|
663
|
+
schemaVersion: 1,
|
|
664
|
+
root,
|
|
665
|
+
autoResolved: false,
|
|
666
|
+
workspaces,
|
|
667
|
+
hint: workspaces.length > 1 ? "Pass an explicit work slug because multiple workspaces exist." : null,
|
|
668
|
+
})
|
|
669
|
+
}
|
|
670
|
+
return
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (!slug) {
|
|
674
|
+
const error = usageError("Usage: ocskill work " + action + " <slug> ...")
|
|
675
|
+
printCliError(error)
|
|
676
|
+
return
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(String(slug))) {
|
|
680
|
+
printCliError(usageError(
|
|
681
|
+
"Invalid work slug '" + String(slug) + "'. Use lowercase letters, numbers and dashes only.",
|
|
682
|
+
), {
|
|
683
|
+
usage: "Usage: ocskill work " + action + " <slug> ...",
|
|
684
|
+
hint: "Example slug: recovery-2-foundation",
|
|
685
|
+
})
|
|
499
686
|
return
|
|
500
687
|
}
|
|
501
688
|
|
|
@@ -552,6 +739,44 @@ async function workControl() {
|
|
|
552
739
|
}
|
|
553
740
|
return
|
|
554
741
|
}
|
|
742
|
+
if (action === "agent-receipt") {
|
|
743
|
+
const taskID = args[3]
|
|
744
|
+
const root = positionalArg(args, 4) || process.cwd()
|
|
745
|
+
const runId = optionValue(args, "--run-id")
|
|
746
|
+
const verdict = String(optionValue(args, "--verdict") || "").toUpperCase()
|
|
747
|
+
const evidence = String(optionValue(args, "--evidence") || "").trim()
|
|
748
|
+
const verifier = String(optionValue(args, "--verifier") || "ues-verifier")
|
|
749
|
+
const sessionID = optionValue(args, "--session-id")
|
|
750
|
+
if (!taskID || !runId || !["PASS", "FAIL"].includes(verdict) || !evidence) {
|
|
751
|
+
const error = new Error("Usage: ocskill work agent-receipt <slug> <task-id> [dir] --run-id <id> --verdict PASS|FAIL --evidence <text> [--verifier <role>] [--session-id <id>]")
|
|
752
|
+
error.code = "UES_USAGE"
|
|
753
|
+
error.exitCode = 2
|
|
754
|
+
throw error
|
|
755
|
+
}
|
|
756
|
+
const fingerprint = workspaceFingerprint(root)
|
|
757
|
+
const timestamp = new Date().toISOString()
|
|
758
|
+
const receipt = createVerificationReceipt({
|
|
759
|
+
task: taskID,
|
|
760
|
+
runId,
|
|
761
|
+
command: "ues-agent-verifier",
|
|
762
|
+
args: [verifier, ...(sessionID ? [sessionID] : [])],
|
|
763
|
+
cwd: path.resolve(root),
|
|
764
|
+
exitCode: verdict === "PASS" ? 0 : 1,
|
|
765
|
+
startedAt: timestamp,
|
|
766
|
+
finishedAt: timestamp,
|
|
767
|
+
durationMs: 0,
|
|
768
|
+
stdout: evidence,
|
|
769
|
+
stderr: verdict === "PASS" ? "" : evidence,
|
|
770
|
+
workspaceBefore: fingerprint,
|
|
771
|
+
workspaceAfter: fingerprint,
|
|
772
|
+
})
|
|
773
|
+
receipt.kind = "agent-verifier"
|
|
774
|
+
receipt.verifier = verifier
|
|
775
|
+
receipt.sessionID = sessionID || null
|
|
776
|
+
receipt.evidence = evidence
|
|
777
|
+
printJson(await recordVerificationReceipt(root, slug, taskID, receipt))
|
|
778
|
+
return
|
|
779
|
+
}
|
|
555
780
|
if (action === "approve-plan") {
|
|
556
781
|
const root = positionalArg(args, 3) || process.cwd()
|
|
557
782
|
const receiptFile = optionValue(args, "--receipt-file")
|
|
@@ -740,19 +965,20 @@ async function workControl() {
|
|
|
740
965
|
return
|
|
741
966
|
}
|
|
742
967
|
|
|
743
|
-
throw
|
|
968
|
+
throw usageError("Unknown work action: " + action)
|
|
744
969
|
} catch (error) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
970
|
+
if (error?.validation && !jsonOutput) printJson(error.validation)
|
|
971
|
+
printCliError(error, {
|
|
972
|
+
command: "work " + String(action || ""),
|
|
973
|
+
recoverable: error?.code === "UES_USAGE",
|
|
974
|
+
})
|
|
748
975
|
}
|
|
749
976
|
}
|
|
750
977
|
|
|
751
978
|
async function modelPolicy() {
|
|
752
979
|
const role = args[1]
|
|
753
980
|
if (!role) {
|
|
754
|
-
|
|
755
|
-
process.exitCode = 2
|
|
981
|
+
printCliError(Object.assign(new Error("Usage: ocskill model-policy <role> [--attempt N]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
756
982
|
return
|
|
757
983
|
}
|
|
758
984
|
const attempt = optionInt(args, "--attempt", 1)
|
|
@@ -786,8 +1012,7 @@ async function modelsControl() {
|
|
|
786
1012
|
const tier = args[2]
|
|
787
1013
|
const model = args[3]
|
|
788
1014
|
if (!["light", "standard", "heavy"].includes(tier) || !validateModelID(model)) {
|
|
789
|
-
|
|
790
|
-
process.exitCode = 2
|
|
1015
|
+
printCliError(Object.assign(new Error("Usage: ocskill models set <light|standard|heavy> <provider/model[#variant]>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
791
1016
|
return
|
|
792
1017
|
}
|
|
793
1018
|
policy = await writeModelPolicy(getConfigDir(), {
|
|
@@ -802,8 +1027,7 @@ async function modelsControl() {
|
|
|
802
1027
|
const role = args[2]
|
|
803
1028
|
const tier = args[3]
|
|
804
1029
|
if (!role || !["light", "standard", "heavy"].includes(tier)) {
|
|
805
|
-
|
|
806
|
-
process.exitCode = 2
|
|
1030
|
+
printCliError(Object.assign(new Error("Usage: ocskill models role <role> <light|standard|heavy>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
807
1031
|
return
|
|
808
1032
|
}
|
|
809
1033
|
policy = await writeModelPolicy(getConfigDir(), {
|
|
@@ -817,8 +1041,7 @@ async function modelsControl() {
|
|
|
817
1041
|
if (action === "observe") {
|
|
818
1042
|
const model = args[2]
|
|
819
1043
|
if (!validateModelID(model)) {
|
|
820
|
-
|
|
821
|
-
process.exitCode = 2
|
|
1044
|
+
printCliError(Object.assign(new Error("Usage: ocskill models observe <provider/model> --task-class <class> --passed on|off"), { code: "UES_USAGE", exitCode: 2 }))
|
|
822
1045
|
return
|
|
823
1046
|
}
|
|
824
1047
|
const taskClass = optionValue(args, "--task-class") || "general"
|
|
@@ -838,8 +1061,7 @@ async function modelsControl() {
|
|
|
838
1061
|
if (action === "capability") {
|
|
839
1062
|
const model = args[2]
|
|
840
1063
|
if (!validateModelID(model)) {
|
|
841
|
-
|
|
842
|
-
process.exitCode = 2
|
|
1064
|
+
printCliError(Object.assign(new Error("Usage: ocskill models capability <provider/model> [capability flags]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
843
1065
|
return
|
|
844
1066
|
}
|
|
845
1067
|
const current = policy.capabilities?.[model] || {}
|
|
@@ -877,8 +1099,7 @@ async function modelsControl() {
|
|
|
877
1099
|
return
|
|
878
1100
|
}
|
|
879
1101
|
|
|
880
|
-
|
|
881
|
-
process.exitCode = 2
|
|
1102
|
+
printCliError(Object.assign(new Error("Usage: ocskill models <status|on|off|set|role> ..."), { code: "UES_USAGE", exitCode: 2 }))
|
|
882
1103
|
}
|
|
883
1104
|
|
|
884
1105
|
async function routerControl() {
|
|
@@ -887,13 +1108,14 @@ async function routerControl() {
|
|
|
887
1108
|
const maxValue = maxIndex >= 0 ? Number.parseInt(optionValue(args, "--max") ?? "", 10) : null
|
|
888
1109
|
|
|
889
1110
|
if (!["status", "on", "off"].includes(action)) {
|
|
890
|
-
|
|
891
|
-
process.exitCode = 2
|
|
1111
|
+
printCliError(Object.assign(new Error("Usage: ocskill router [status|on|off] [--max 1..6]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
892
1112
|
return
|
|
893
1113
|
}
|
|
894
1114
|
if (maxIndex >= 0 && (!Number.isInteger(maxValue) || maxValue < 1 || maxValue > 6)) {
|
|
895
|
-
|
|
896
|
-
|
|
1115
|
+
printCliError(Object.assign(new Error("--max must be an integer from 1 through 6"), {
|
|
1116
|
+
code: "UES_USAGE",
|
|
1117
|
+
exitCode: 2,
|
|
1118
|
+
}))
|
|
897
1119
|
return
|
|
898
1120
|
}
|
|
899
1121
|
|
|
@@ -925,8 +1147,7 @@ async function routerControl() {
|
|
|
925
1147
|
async function taskPolicyControl() {
|
|
926
1148
|
const text = args.slice(1).join(" ").trim()
|
|
927
1149
|
if (!text) {
|
|
928
|
-
|
|
929
|
-
process.exitCode = 2
|
|
1150
|
+
printCliError(Object.assign(new Error("Usage: ocskill task-policy <text>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
930
1151
|
return
|
|
931
1152
|
}
|
|
932
1153
|
printJson(classifyEngineeringTask(text))
|
|
@@ -968,7 +1189,11 @@ async function sandboxControl() {
|
|
|
968
1189
|
const taskID = args[3]
|
|
969
1190
|
const root = positionalArg(args, 4) || process.cwd()
|
|
970
1191
|
if (!slug || !taskID) throw new Error("Usage: ocskill sandbox create <slug> <task-id> [dir]")
|
|
971
|
-
printJson(await createTaskSandbox(root, slug, taskID
|
|
1192
|
+
printJson(await createTaskSandbox(root, slug, taskID, {
|
|
1193
|
+
inheritDirtyRoot: args.includes("--inherit-dirty-root"),
|
|
1194
|
+
allowDirtyRoot: args.includes("--allow-dirty-root"),
|
|
1195
|
+
startPoint: optionValue(args, "--start-point") || undefined,
|
|
1196
|
+
}))
|
|
972
1197
|
return
|
|
973
1198
|
}
|
|
974
1199
|
if (action === "integrate") {
|
|
@@ -978,6 +1203,13 @@ async function sandboxControl() {
|
|
|
978
1203
|
printJson(await integrateTaskSandbox(root, dir, { keep: args.includes("--keep") }))
|
|
979
1204
|
return
|
|
980
1205
|
}
|
|
1206
|
+
if (action === "rollback") {
|
|
1207
|
+
const dir = args[2]
|
|
1208
|
+
const root = positionalArg(args, 3) || process.cwd()
|
|
1209
|
+
if (!dir) throw new Error("Usage: ocskill sandbox rollback <worktree-path> [dir] [--keep]")
|
|
1210
|
+
printJson(await rollbackTaskSandbox(root, dir, { keep: args.includes("--keep") }))
|
|
1211
|
+
return
|
|
1212
|
+
}
|
|
981
1213
|
if (action === "remove") {
|
|
982
1214
|
const dir = args[2]
|
|
983
1215
|
const root = positionalArg(args, 3) || process.cwd()
|
|
@@ -988,10 +1220,9 @@ async function sandboxControl() {
|
|
|
988
1220
|
}))
|
|
989
1221
|
return
|
|
990
1222
|
}
|
|
991
|
-
throw new Error("Usage: ocskill sandbox <capability|exec|list|create|integrate|remove> ...")
|
|
1223
|
+
throw new Error("Usage: ocskill sandbox <capability|exec|list|create|integrate|rollback|remove> ...")
|
|
992
1224
|
} catch (error) {
|
|
993
|
-
|
|
994
|
-
process.exitCode = 1
|
|
1225
|
+
printCliError(error)
|
|
995
1226
|
}
|
|
996
1227
|
}
|
|
997
1228
|
|
|
@@ -1028,8 +1259,7 @@ async function learningControl() {
|
|
|
1028
1259
|
}
|
|
1029
1260
|
throw new Error("Usage: ocskill learn <status|analyze|accept|promote> ...")
|
|
1030
1261
|
} catch (error) {
|
|
1031
|
-
|
|
1032
|
-
process.exitCode = 1
|
|
1262
|
+
printCliError(error)
|
|
1033
1263
|
}
|
|
1034
1264
|
}
|
|
1035
1265
|
|
|
@@ -1043,8 +1273,7 @@ async function hermesControl() {
|
|
|
1043
1273
|
const slug = args[2]
|
|
1044
1274
|
const root = positionalArg(args, 3) || process.cwd()
|
|
1045
1275
|
if (!slug) {
|
|
1046
|
-
|
|
1047
|
-
process.exitCode = 2
|
|
1276
|
+
printCliError(Object.assign(new Error("Usage: ocskill hermes <workflow|exec-workflow> <slug> [dir] [--max-concurrent N]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1048
1277
|
return
|
|
1049
1278
|
}
|
|
1050
1279
|
const planFile = path.join(path.resolve(root), ".ues-work", slug, "PLAN.json")
|
|
@@ -1078,8 +1307,7 @@ async function hermesControl() {
|
|
|
1078
1307
|
const taskID = args[3]
|
|
1079
1308
|
const root = positionalArg(args, 4) || process.cwd()
|
|
1080
1309
|
if (!slug || !taskID) {
|
|
1081
|
-
|
|
1082
|
-
process.exitCode = 2
|
|
1310
|
+
printCliError(Object.assign(new Error("Usage: ocskill hermes <prompt|exec> <slug> <task-id> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1083
1311
|
return
|
|
1084
1312
|
}
|
|
1085
1313
|
const prompt = buildHermesDelegationPrompt(await contextPack(root, slug, taskID))
|
|
@@ -1103,8 +1331,7 @@ async function hermesControl() {
|
|
|
1103
1331
|
if ((result.status ?? 1) !== 0) process.exitCode = result.status ?? 1
|
|
1104
1332
|
return
|
|
1105
1333
|
}
|
|
1106
|
-
|
|
1107
|
-
process.exitCode = 2
|
|
1334
|
+
printCliError(Object.assign(new Error("Usage: ocskill hermes <status|prompt|exec|workflow|exec-workflow> ..."), { code: "UES_USAGE", exitCode: 2 }))
|
|
1108
1335
|
}
|
|
1109
1336
|
|
|
1110
1337
|
async function evidenceStoreControl() {
|
|
@@ -1146,16 +1373,14 @@ async function evidenceStoreControl() {
|
|
|
1146
1373
|
}
|
|
1147
1374
|
throw new Error("Usage: ocskill store <status|put|get|gc> ...")
|
|
1148
1375
|
} catch (error) {
|
|
1149
|
-
|
|
1150
|
-
process.exitCode = 1
|
|
1376
|
+
printCliError(error)
|
|
1151
1377
|
}
|
|
1152
1378
|
}
|
|
1153
1379
|
|
|
1154
1380
|
async function capabilityControl() {
|
|
1155
1381
|
const text = args.slice(1).join(" ").trim()
|
|
1156
1382
|
if (!text) {
|
|
1157
|
-
|
|
1158
|
-
process.exitCode = 2
|
|
1383
|
+
printCliError(Object.assign(new Error("Usage: ocskill capabilities <task text>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1159
1384
|
return
|
|
1160
1385
|
}
|
|
1161
1386
|
printJson(inferTaskCapabilities(text))
|
|
@@ -1204,8 +1429,7 @@ async function visualControl() {
|
|
|
1204
1429
|
}
|
|
1205
1430
|
throw new Error("Usage: ocskill visual <spec|geometry|compare|crop|viewports> ...")
|
|
1206
1431
|
} catch (error) {
|
|
1207
|
-
|
|
1208
|
-
process.exitCode = 1
|
|
1432
|
+
printCliError(error)
|
|
1209
1433
|
}
|
|
1210
1434
|
}
|
|
1211
1435
|
|
|
@@ -1243,8 +1467,7 @@ async function browserControl() {
|
|
|
1243
1467
|
}
|
|
1244
1468
|
throw new Error("Usage: ocskill browser <capability|plan|inspect> ...")
|
|
1245
1469
|
} catch (error) {
|
|
1246
|
-
|
|
1247
|
-
process.exitCode = 1
|
|
1470
|
+
printCliError(error)
|
|
1248
1471
|
}
|
|
1249
1472
|
}
|
|
1250
1473
|
|
|
@@ -1274,16 +1497,83 @@ async function uiControl() {
|
|
|
1274
1497
|
}
|
|
1275
1498
|
throw new Error("Usage: ocskill ui <tokens|layout> ...")
|
|
1276
1499
|
} catch (error) {
|
|
1277
|
-
|
|
1278
|
-
|
|
1500
|
+
printCliError(error)
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
async function diffControl() {
|
|
1505
|
+
const root = path.resolve(positionalArg(args, 1) || process.cwd())
|
|
1506
|
+
const base = optionValue(args, "--base")
|
|
1507
|
+
const outputFile = optionValue(args, "--out")
|
|
1508
|
+
const commandArgs = ["diff", "--binary", "--no-ext-diff", ...(base ? [base] : []), "--"]
|
|
1509
|
+
const result = runCapture("git", commandArgs, { cwd: root, maxBuffer: 16 * 1024 * 1024 })
|
|
1510
|
+
if ((result.status ?? 1) !== 0) {
|
|
1511
|
+
const error = new Error((result.stderr || result.stdout || "git diff failed").trim())
|
|
1512
|
+
error.code = "UES_GIT_DIFF"
|
|
1513
|
+
throw error
|
|
1514
|
+
}
|
|
1515
|
+
if (outputFile) {
|
|
1516
|
+
const resolved = path.resolve(outputFile)
|
|
1517
|
+
writeFileSync(resolved, result.stdout || "", "utf8")
|
|
1518
|
+
printJson({ schemaVersion: 1, root, base: base || null, file: resolved, encoding: "utf8", bytes: Buffer.byteLength(result.stdout || "") })
|
|
1519
|
+
return
|
|
1520
|
+
}
|
|
1521
|
+
if (jsonOutput) {
|
|
1522
|
+
printJson({ schemaVersion: 1, root, base: base || null, encoding: "utf8", diff: result.stdout || "" })
|
|
1523
|
+
return
|
|
1279
1524
|
}
|
|
1525
|
+
process.stdout.write(result.stdout || "")
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
async function textReadControl() {
|
|
1529
|
+
const file = positionalArg(args, 1)
|
|
1530
|
+
if (!file) {
|
|
1531
|
+
const error = new Error("Usage: ocskill text-read <file> [--start N] [--max N] [--json]")
|
|
1532
|
+
error.code = "UES_USAGE"
|
|
1533
|
+
error.exitCode = 2
|
|
1534
|
+
throw error
|
|
1535
|
+
}
|
|
1536
|
+
const text = readTextFile(file)
|
|
1537
|
+
const parsedStart = optionInt(args, "--start", 0)
|
|
1538
|
+
const parsedMax = optionInt(args, "--max", 12000)
|
|
1539
|
+
const start = Number.isFinite(parsedStart) ? Math.max(0, parsedStart) : 0
|
|
1540
|
+
const maxChars = Number.isFinite(parsedMax) ? Math.max(256, Math.min(parsedMax, 100000)) : 12000
|
|
1541
|
+
const slice = text.slice(start, start + maxChars)
|
|
1542
|
+
const truncated = start + slice.length < text.length
|
|
1543
|
+
if (jsonOutput) {
|
|
1544
|
+
printJson({
|
|
1545
|
+
schemaVersion: 1,
|
|
1546
|
+
file: path.resolve(file),
|
|
1547
|
+
chars: text.length,
|
|
1548
|
+
start,
|
|
1549
|
+
returnedChars: slice.length,
|
|
1550
|
+
truncated,
|
|
1551
|
+
text: slice,
|
|
1552
|
+
})
|
|
1553
|
+
return
|
|
1554
|
+
}
|
|
1555
|
+
process.stdout.write(slice)
|
|
1556
|
+
if (truncated) process.stdout.write("\n...[UES text-read truncated]...\n")
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
async function normalizeTextControl() {
|
|
1560
|
+
const file = args[1]
|
|
1561
|
+
if (!file) {
|
|
1562
|
+
const error = new Error("Usage: ocskill normalize-text <file> [--out <utf8-file>]")
|
|
1563
|
+
error.code = "UES_USAGE"
|
|
1564
|
+
error.exitCode = 2
|
|
1565
|
+
throw error
|
|
1566
|
+
}
|
|
1567
|
+
const text = readTextFile(file)
|
|
1568
|
+
const output = path.resolve(optionValue(args, "--out") || file)
|
|
1569
|
+
writeFileSync(output, text, "utf8")
|
|
1570
|
+
printJson({ schemaVersion: 1, input: path.resolve(file), output, encoding: "utf8", bytes: Buffer.byteLength(text) })
|
|
1280
1571
|
}
|
|
1281
1572
|
|
|
1282
1573
|
async function workflowPlanControl() {
|
|
1283
1574
|
const file = args[1]
|
|
1284
1575
|
if (!file) {
|
|
1285
|
-
|
|
1286
|
-
process.exitCode = 2
|
|
1576
|
+
printCliError(Object.assign(new Error("Usage: ocskill workflow-plan <PLAN.json> [--max-concurrent N]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1287
1577
|
return
|
|
1288
1578
|
}
|
|
1289
1579
|
try {
|
|
@@ -1297,23 +1587,20 @@ async function workflowPlanControl() {
|
|
|
1297
1587
|
minVisionAgentCost: optionInt(args, "--min-vision-agent-cost", 4),
|
|
1298
1588
|
}))
|
|
1299
1589
|
} catch (error) {
|
|
1300
|
-
|
|
1301
|
-
process.exitCode = 1
|
|
1590
|
+
printCliError(error)
|
|
1302
1591
|
}
|
|
1303
1592
|
}
|
|
1304
1593
|
|
|
1305
1594
|
async function skillsControl() {
|
|
1306
1595
|
const action = args[1] || "lint"
|
|
1307
1596
|
if (action !== "lint") {
|
|
1308
|
-
|
|
1309
|
-
process.exitCode = 2
|
|
1597
|
+
printCliError(Object.assign(new Error("Usage: ocskill skills lint [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1310
1598
|
return
|
|
1311
1599
|
}
|
|
1312
1600
|
try {
|
|
1313
1601
|
printJson(await lintSkillCatalog(positionalArg(args, 2) || packageRoot))
|
|
1314
1602
|
} catch (error) {
|
|
1315
|
-
|
|
1316
|
-
process.exitCode = 1
|
|
1603
|
+
printCliError(error)
|
|
1317
1604
|
}
|
|
1318
1605
|
}
|
|
1319
1606
|
|
|
@@ -1352,8 +1639,7 @@ async function update() {
|
|
|
1352
1639
|
compared = compareVersions(latestVersion, currentVersion)
|
|
1353
1640
|
} catch (error) {
|
|
1354
1641
|
console.error("[ocskill] npm returned a version that could not be compared safely; refusing update.")
|
|
1355
|
-
|
|
1356
|
-
process.exitCode = 1
|
|
1642
|
+
printCliError(error)
|
|
1357
1643
|
return
|
|
1358
1644
|
}
|
|
1359
1645
|
|
|
@@ -1414,7 +1700,13 @@ async function remove() {
|
|
|
1414
1700
|
if (code !== 0) process.exitCode = code
|
|
1415
1701
|
}
|
|
1416
1702
|
|
|
1417
|
-
|
|
1703
|
+
async function main() {
|
|
1704
|
+
if (helpRequested) {
|
|
1705
|
+
printCommandHelp(command, args[1])
|
|
1706
|
+
return
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
switch (command) {
|
|
1418
1710
|
case "install":
|
|
1419
1711
|
case "sync":
|
|
1420
1712
|
await install()
|
|
@@ -1504,6 +1796,15 @@ switch (command) {
|
|
|
1504
1796
|
case "workflow-plan":
|
|
1505
1797
|
await workflowPlanControl()
|
|
1506
1798
|
break
|
|
1799
|
+
case "diff":
|
|
1800
|
+
await diffControl().catch((error) => printCliError(error))
|
|
1801
|
+
break
|
|
1802
|
+
case "text-read":
|
|
1803
|
+
await textReadControl().catch((error) => printCliError(error))
|
|
1804
|
+
break
|
|
1805
|
+
case "normalize-text":
|
|
1806
|
+
await normalizeTextControl().catch((error) => printCliError(error))
|
|
1807
|
+
break
|
|
1507
1808
|
case "ui":
|
|
1508
1809
|
await uiControl()
|
|
1509
1810
|
break
|
|
@@ -1542,8 +1843,17 @@ switch (command) {
|
|
|
1542
1843
|
case "-h":
|
|
1543
1844
|
printHelp()
|
|
1544
1845
|
break
|
|
1545
|
-
default:
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1846
|
+
default: {
|
|
1847
|
+
const error = new Error("Unknown command: " + command)
|
|
1848
|
+
error.code = "UES_USAGE"
|
|
1849
|
+
error.exitCode = 2
|
|
1850
|
+
throw error
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
try {
|
|
1856
|
+
await main()
|
|
1857
|
+
} catch (error) {
|
|
1858
|
+
printCliError(error)
|
|
1549
1859
|
}
|