opencode-agent-skill 11.0.0 → 13.0.0-beta.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 +55 -0
- package/README.md +119 -14
- package/bin/ocskill.mjs +416 -83
- package/docs/DETERMINISTIC-TOOLS.md +1 -1
- package/docs/ENGINEERING-DESIGN.md +4 -4
- package/docs/EVALS.md +3 -3
- package/docs/GITHUB-RULESET.md +50 -0
- package/docs/NPM-PUBLISH.md +22 -8
- package/docs/OPENCODE-COMPAT.md +14 -4
- package/docs/TRACE-SCHEMA.md +1 -1
- package/docs/V11-PERCEPTION-ADAPTIVE.md +2 -2
- package/docs/V12-WEAK-MODEL-INTELLIGENCE.md +27 -0
- package/docs/V13-PARALLEL-WEAK-MODEL-RUNTIME.md +75 -0
- package/evals/repo-scale/tasks.json +62 -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 +79 -0
- package/global-config/plugins/ues-router/index.js +364 -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/context-engine-v11.mjs +4 -0
- package/lib/context-quality.mjs +59 -0
- package/lib/decision-policy.mjs +23 -0
- package/lib/installer.mjs +49 -16
- package/lib/model-config.mjs +13 -1
- package/lib/model-performance.mjs +113 -0
- package/lib/model-policy.mjs +9 -2
- package/lib/repo-scale-fixture.mjs +45 -0
- package/lib/task-engine.mjs +36 -12
- package/lib/task-graph.mjs +32 -0
- package/lib/text-encoding.mjs +74 -0
- package/lib/work-plan-scope.mjs +49 -0
- package/lib/worktree-sandbox.mjs +141 -12
- package/package.json +8 -4
- package/scripts/check-release-consistency.mjs +260 -0
- package/scripts/smoke-packed-install.mjs +39 -3
- package/scripts/smoke-plain-install.mjs +27 -7
- package/scripts/validate-repo-scale-suite.mjs +27 -0
- package/scripts/validate-v12-foundation.mjs +24 -0
- 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,12 +62,13 @@ 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
|
-
import { readModelPolicy, validateModelID, writeModelPolicy } from "../lib/model-config.mjs"
|
|
68
|
+
import { readModelPolicy, recordModelPerformance, validateModelID, writeModelPolicy } from "../lib/model-config.mjs"
|
|
69
69
|
import { evidenceStoreStatus, gcEvidenceStore, getEvidence, putEvidence } from "../lib/evidence-store.mjs"
|
|
70
70
|
import { inferTaskCapabilities } from "../lib/capability-registry.mjs"
|
|
71
|
+
import { MODEL_TASK_CLASSES } from "../lib/model-performance.mjs"
|
|
71
72
|
import { browserCapability, buildBrowserVerificationPlan } from "../lib/browser-adapter.mjs"
|
|
72
73
|
import { inspectBrowserPage, summarizeBrowserInspection } from "../lib/browser-runtime.mjs"
|
|
73
74
|
import { comparePngFiles, cropPngFile } from "../lib/png-diff.mjs"
|
|
@@ -76,6 +77,7 @@ import { planDynamicWorkflow } from "../lib/dynamic-workflow.mjs"
|
|
|
76
77
|
import { lintSkillCatalog } from "../lib/skill-quality.mjs"
|
|
77
78
|
import { designTokenEvidence, extractDesignTokens, inspectResponsiveLayout } from "../lib/ui-inspector.mjs"
|
|
78
79
|
import {
|
|
80
|
+
cliErrorPayload,
|
|
79
81
|
clipOutput,
|
|
80
82
|
errorMessage,
|
|
81
83
|
optionInt,
|
|
@@ -84,10 +86,22 @@ import {
|
|
|
84
86
|
positionalArg,
|
|
85
87
|
readJsonFile,
|
|
86
88
|
readTextFile,
|
|
89
|
+
usageError,
|
|
87
90
|
} from "../lib/cli-utils.mjs"
|
|
88
91
|
|
|
89
|
-
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
|
+
)
|
|
90
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
|
+
)
|
|
91
105
|
const force = args.includes("--force")
|
|
92
106
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
|
93
107
|
|
|
@@ -106,7 +120,11 @@ Usage:
|
|
|
106
120
|
ocskill impact <query> [dir] Search likely impact paths and matching lines
|
|
107
121
|
ocskill evidence [dir] Collect stack, verification and Git evidence
|
|
108
122
|
ocskill working-tree [dir] Report Git branch/HEAD/dirty state
|
|
109
|
-
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
|
|
110
128
|
ocskill index <status|build|rebuild> [dir]
|
|
111
129
|
Build/reuse the persistent incremental semantic index
|
|
112
130
|
ocskill aci <search|refs|view|text> ...
|
|
@@ -123,7 +141,7 @@ Usage:
|
|
|
123
141
|
ocskill model-policy <role> [--attempt N]
|
|
124
142
|
Resolve light/standard/heavy escalation tier
|
|
125
143
|
ocskill task-policy <text> Classify task mode/risk/context/model tier
|
|
126
|
-
ocskill sandbox <action> ... Create, integrate and clean isolated Git worktree sandboxes
|
|
144
|
+
ocskill sandbox <action> ... Create, integrate, rollback and clean isolated Git worktree sandboxes
|
|
127
145
|
Also supports capability/exec for fail-closed container verification
|
|
128
146
|
ocskill learn <action> ... Analyze eval traces and promote benchmark-validated lessons
|
|
129
147
|
ocskill hermes <action> ... Optional Hermes sidecar/status/task/workflow planning
|
|
@@ -150,12 +168,15 @@ Usage:
|
|
|
150
168
|
ocskill work plan <slug> <plan.json> [dir]
|
|
151
169
|
ocskill work status|resume <slug> [dir]
|
|
152
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>
|
|
153
172
|
ocskill work approve-plan <slug> [dir] --evidence <plan-checker-evidence> [--receipt-file <file>]
|
|
154
173
|
ocskill work start <slug> <task-id> [dir] [--lease-ms N]
|
|
155
174
|
ocskill work attach-session <slug> <task-id> [dir] --run-id <id> --session-id <id> [--execution-dir <dir>] [--sandbox-dir <dir>]
|
|
156
175
|
ocskill work heartbeat <slug> <task-id> [dir] --run-id <id>
|
|
157
176
|
ocskill work recover <slug> [dir] [--force]
|
|
158
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>]
|
|
159
180
|
ocskill work events <slug> [dir] [--limit N]
|
|
160
181
|
ocskill work verify-command <slug> <task-id> [dir] --run-id <id> -- <command> [args...]
|
|
161
182
|
ocskill work complete <slug> <task-id> [dir] --run-id <id> --evidence <text> [--report-file <file>]
|
|
@@ -171,11 +192,101 @@ Usage:
|
|
|
171
192
|
ocskill models set <light|standard|heavy> <provider/model[#variant]>
|
|
172
193
|
ocskill models role <role> <light|standard|heavy>
|
|
173
194
|
ocskill models capability <provider/model> [--vision on|off] [--browser on|off] [--reasoning on|off] [--long-context on|off] [--cost low|medium|high] [--latency fast|medium|slow] [--quality 0..1]
|
|
195
|
+
ocskill models observe <provider/model> --task-class <class> --passed on|off [--retries N] [--tokens N] [--latency-ms N]
|
|
174
196
|
|
|
175
197
|
--force backs up and replaces/removes state owned by another package.
|
|
176
198
|
`)
|
|
177
199
|
}
|
|
178
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
|
+
}
|
|
179
290
|
|
|
180
291
|
function run(executable, commandArgs, options = {}) {
|
|
181
292
|
const common = { stdio: "inherit", ...options }
|
|
@@ -239,9 +350,18 @@ async function install() {
|
|
|
239
350
|
console.log(`[ocskill] Installed resources for v${result.version}`)
|
|
240
351
|
console.log(`[ocskill] OpenCode config: ${result.configDir}`)
|
|
241
352
|
console.log(`[ocskill] Skills: ${result.skills.length}`)
|
|
242
|
-
|
|
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
|
+
}
|
|
243
358
|
console.log(`[ocskill] Subagents: ${result.agents.length}`)
|
|
244
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
|
+
)
|
|
245
365
|
if ((result.plugins || []).length) console.log(`[ocskill] Router plugins: ${result.plugins.length}`)
|
|
246
366
|
for (const warning of result.warnings) console.warn(`[ocskill] WARNING: ${warning}`)
|
|
247
367
|
console.log("[ocskill] Start a new OpenCode session to pick up workflow changes.")
|
|
@@ -266,15 +386,25 @@ async function status() {
|
|
|
266
386
|
console.log(`[ocskill] Sync: ${synced ? "OK" : "OUTDATED - run ocskill install"}`)
|
|
267
387
|
console.log(`[ocskill] Config: ${result.configDir}`)
|
|
268
388
|
console.log(`[ocskill] Skills: ${result.skillsPresent}/${result.skills.length}`)
|
|
269
|
-
|
|
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
|
+
}
|
|
270
394
|
console.log(`[ocskill] Subagents: ${result.agentsPresent}/${(result.agents || []).length}`)
|
|
271
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
|
+
)
|
|
272
401
|
if ((result.plugins || []).length) console.log(`[ocskill] Router plugins: ${result.pluginsPresent}/${result.plugins.length}`)
|
|
273
402
|
console.log(`[ocskill] Workflow: ${result.workflowPresent ? "OK" : "MISSING"}`)
|
|
274
403
|
|
|
275
404
|
if (!synced ||
|
|
276
405
|
result.skillsPresent !== result.skills.length ||
|
|
277
406
|
result.commandsPresent !== result.commands.length ||
|
|
407
|
+
(result.promptAliasesPresent || 0) !== (result.promptAliases || []).length ||
|
|
278
408
|
result.agentsPresent !== (result.agents || []).length ||
|
|
279
409
|
result.pluginsPresent !== (result.plugins || []).length ||
|
|
280
410
|
!result.workflowPresent) {
|
|
@@ -330,8 +460,7 @@ async function inspectRepository() {
|
|
|
330
460
|
async function inspectImpact() {
|
|
331
461
|
const query = args[1]
|
|
332
462
|
if (!query) {
|
|
333
|
-
|
|
334
|
-
process.exitCode = 2
|
|
463
|
+
printCliError(Object.assign(new Error("Usage: ocskill impact <query> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
335
464
|
return
|
|
336
465
|
}
|
|
337
466
|
printJson(await impactMap(positionalArg(args, 2) || process.cwd(), query))
|
|
@@ -354,7 +483,26 @@ async function inspectTests() {
|
|
|
354
483
|
}
|
|
355
484
|
|
|
356
485
|
async function inspectRepoGraph() {
|
|
357
|
-
|
|
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)
|
|
358
506
|
}
|
|
359
507
|
|
|
360
508
|
async function semanticIndexControl() {
|
|
@@ -372,8 +520,7 @@ async function semanticIndexControl() {
|
|
|
372
520
|
}
|
|
373
521
|
throw new Error("Usage: ocskill index <status|build|rebuild> [dir]")
|
|
374
522
|
} catch (error) {
|
|
375
|
-
|
|
376
|
-
process.exitCode = 1
|
|
523
|
+
printCliError(error)
|
|
377
524
|
}
|
|
378
525
|
}
|
|
379
526
|
|
|
@@ -414,8 +561,7 @@ async function aciControl() {
|
|
|
414
561
|
}
|
|
415
562
|
throw new Error("Usage: ocskill aci <search|refs|view|text> ...")
|
|
416
563
|
} catch (error) {
|
|
417
|
-
|
|
418
|
-
process.exitCode = 1
|
|
564
|
+
printCliError(error)
|
|
419
565
|
}
|
|
420
566
|
}
|
|
421
567
|
|
|
@@ -444,8 +590,7 @@ async function traceControl() {
|
|
|
444
590
|
}
|
|
445
591
|
throw new Error("Usage: ocskill trace <show|append> ...")
|
|
446
592
|
} catch (error) {
|
|
447
|
-
|
|
448
|
-
process.exitCode = 1
|
|
593
|
+
printCliError(error)
|
|
449
594
|
}
|
|
450
595
|
}
|
|
451
596
|
|
|
@@ -462,8 +607,7 @@ async function inspectVerificationPlan() {
|
|
|
462
607
|
async function inspectTaskGraph() {
|
|
463
608
|
const file = args[1]
|
|
464
609
|
if (!file) {
|
|
465
|
-
|
|
466
|
-
process.exitCode = 2
|
|
610
|
+
printCliError(Object.assign(new Error("Usage: ocskill task-graph <plan.json>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
467
611
|
return
|
|
468
612
|
}
|
|
469
613
|
try {
|
|
@@ -472,8 +616,7 @@ async function inspectTaskGraph() {
|
|
|
472
616
|
printJson(analysis)
|
|
473
617
|
if (!analysis.valid) process.exitCode = 1
|
|
474
618
|
} catch (error) {
|
|
475
|
-
|
|
476
|
-
process.exitCode = 1
|
|
619
|
+
printCliError(error)
|
|
477
620
|
}
|
|
478
621
|
}
|
|
479
622
|
|
|
@@ -481,8 +624,7 @@ async function inspectContextPack() {
|
|
|
481
624
|
const slug = args[1]
|
|
482
625
|
const taskID = args[2]
|
|
483
626
|
if (!slug || !taskID) {
|
|
484
|
-
|
|
485
|
-
process.exitCode = 2
|
|
627
|
+
printCliError(Object.assign(new Error("Usage: ocskill context-pack <slug> <task-id> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
486
628
|
return
|
|
487
629
|
}
|
|
488
630
|
printJson(await contextPack(positionalArg(args, 3) || process.cwd(), slug, taskID))
|
|
@@ -491,9 +633,56 @@ async function inspectContextPack() {
|
|
|
491
633
|
async function workControl() {
|
|
492
634
|
const action = args[1]
|
|
493
635
|
const slug = args[2]
|
|
494
|
-
if (!action
|
|
495
|
-
|
|
496
|
-
|
|
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
|
+
})
|
|
497
686
|
return
|
|
498
687
|
}
|
|
499
688
|
|
|
@@ -550,6 +739,44 @@ async function workControl() {
|
|
|
550
739
|
}
|
|
551
740
|
return
|
|
552
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
|
+
}
|
|
553
780
|
if (action === "approve-plan") {
|
|
554
781
|
const root = positionalArg(args, 3) || process.cwd()
|
|
555
782
|
const receiptFile = optionValue(args, "--receipt-file")
|
|
@@ -738,19 +965,20 @@ async function workControl() {
|
|
|
738
965
|
return
|
|
739
966
|
}
|
|
740
967
|
|
|
741
|
-
throw
|
|
968
|
+
throw usageError("Unknown work action: " + action)
|
|
742
969
|
} catch (error) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
970
|
+
if (error?.validation && !jsonOutput) printJson(error.validation)
|
|
971
|
+
printCliError(error, {
|
|
972
|
+
command: "work " + String(action || ""),
|
|
973
|
+
recoverable: error?.code === "UES_USAGE",
|
|
974
|
+
})
|
|
746
975
|
}
|
|
747
976
|
}
|
|
748
977
|
|
|
749
978
|
async function modelPolicy() {
|
|
750
979
|
const role = args[1]
|
|
751
980
|
if (!role) {
|
|
752
|
-
|
|
753
|
-
process.exitCode = 2
|
|
981
|
+
printCliError(Object.assign(new Error("Usage: ocskill model-policy <role> [--attempt N]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
754
982
|
return
|
|
755
983
|
}
|
|
756
984
|
const attempt = optionInt(args, "--attempt", 1)
|
|
@@ -784,8 +1012,7 @@ async function modelsControl() {
|
|
|
784
1012
|
const tier = args[2]
|
|
785
1013
|
const model = args[3]
|
|
786
1014
|
if (!["light", "standard", "heavy"].includes(tier) || !validateModelID(model)) {
|
|
787
|
-
|
|
788
|
-
process.exitCode = 2
|
|
1015
|
+
printCliError(Object.assign(new Error("Usage: ocskill models set <light|standard|heavy> <provider/model[#variant]>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
789
1016
|
return
|
|
790
1017
|
}
|
|
791
1018
|
policy = await writeModelPolicy(getConfigDir(), {
|
|
@@ -800,8 +1027,7 @@ async function modelsControl() {
|
|
|
800
1027
|
const role = args[2]
|
|
801
1028
|
const tier = args[3]
|
|
802
1029
|
if (!role || !["light", "standard", "heavy"].includes(tier)) {
|
|
803
|
-
|
|
804
|
-
process.exitCode = 2
|
|
1030
|
+
printCliError(Object.assign(new Error("Usage: ocskill models role <role> <light|standard|heavy>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
805
1031
|
return
|
|
806
1032
|
}
|
|
807
1033
|
policy = await writeModelPolicy(getConfigDir(), {
|
|
@@ -812,11 +1038,30 @@ async function modelsControl() {
|
|
|
812
1038
|
return
|
|
813
1039
|
}
|
|
814
1040
|
|
|
1041
|
+
if (action === "observe") {
|
|
1042
|
+
const model = args[2]
|
|
1043
|
+
if (!validateModelID(model)) {
|
|
1044
|
+
printCliError(Object.assign(new Error("Usage: ocskill models observe <provider/model> --task-class <class> --passed on|off"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1045
|
+
return
|
|
1046
|
+
}
|
|
1047
|
+
const taskClass = optionValue(args, "--task-class") || "general"
|
|
1048
|
+
if (!MODEL_TASK_CLASSES.includes(taskClass)) throw new Error("--task-class must be one of: " + MODEL_TASK_CLASSES.join(", "))
|
|
1049
|
+
const passedRaw = String(optionValue(args, "--passed") || "").toLowerCase()
|
|
1050
|
+
if (!["on","off","true","false","pass","fail"].includes(passedRaw)) throw new Error("--passed must be on/off, true/false, or pass/fail")
|
|
1051
|
+
policy = await recordModelPerformance(getConfigDir(), {
|
|
1052
|
+
model, taskClass, passed: ["on","true","pass"].includes(passedRaw),
|
|
1053
|
+
retries: optionInt(args, "--retries", 0) || 0,
|
|
1054
|
+
tokens: optionInt(args, "--tokens", 0) || 0,
|
|
1055
|
+
latencyMs: optionInt(args, "--latency-ms", 0) || 0,
|
|
1056
|
+
})
|
|
1057
|
+
printJson({ model, taskClass, recorded: true, performance: policy.performance?.[model]?.[taskClass] || null })
|
|
1058
|
+
return
|
|
1059
|
+
}
|
|
1060
|
+
|
|
815
1061
|
if (action === "capability") {
|
|
816
1062
|
const model = args[2]
|
|
817
1063
|
if (!validateModelID(model)) {
|
|
818
|
-
|
|
819
|
-
process.exitCode = 2
|
|
1064
|
+
printCliError(Object.assign(new Error("Usage: ocskill models capability <provider/model> [capability flags]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
820
1065
|
return
|
|
821
1066
|
}
|
|
822
1067
|
const current = policy.capabilities?.[model] || {}
|
|
@@ -854,8 +1099,7 @@ async function modelsControl() {
|
|
|
854
1099
|
return
|
|
855
1100
|
}
|
|
856
1101
|
|
|
857
|
-
|
|
858
|
-
process.exitCode = 2
|
|
1102
|
+
printCliError(Object.assign(new Error("Usage: ocskill models <status|on|off|set|role> ..."), { code: "UES_USAGE", exitCode: 2 }))
|
|
859
1103
|
}
|
|
860
1104
|
|
|
861
1105
|
async function routerControl() {
|
|
@@ -864,13 +1108,14 @@ async function routerControl() {
|
|
|
864
1108
|
const maxValue = maxIndex >= 0 ? Number.parseInt(optionValue(args, "--max") ?? "", 10) : null
|
|
865
1109
|
|
|
866
1110
|
if (!["status", "on", "off"].includes(action)) {
|
|
867
|
-
|
|
868
|
-
process.exitCode = 2
|
|
1111
|
+
printCliError(Object.assign(new Error("Usage: ocskill router [status|on|off] [--max 1..6]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
869
1112
|
return
|
|
870
1113
|
}
|
|
871
1114
|
if (maxIndex >= 0 && (!Number.isInteger(maxValue) || maxValue < 1 || maxValue > 6)) {
|
|
872
|
-
|
|
873
|
-
|
|
1115
|
+
printCliError(Object.assign(new Error("--max must be an integer from 1 through 6"), {
|
|
1116
|
+
code: "UES_USAGE",
|
|
1117
|
+
exitCode: 2,
|
|
1118
|
+
}))
|
|
874
1119
|
return
|
|
875
1120
|
}
|
|
876
1121
|
|
|
@@ -902,8 +1147,7 @@ async function routerControl() {
|
|
|
902
1147
|
async function taskPolicyControl() {
|
|
903
1148
|
const text = args.slice(1).join(" ").trim()
|
|
904
1149
|
if (!text) {
|
|
905
|
-
|
|
906
|
-
process.exitCode = 2
|
|
1150
|
+
printCliError(Object.assign(new Error("Usage: ocskill task-policy <text>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
907
1151
|
return
|
|
908
1152
|
}
|
|
909
1153
|
printJson(classifyEngineeringTask(text))
|
|
@@ -945,7 +1189,11 @@ async function sandboxControl() {
|
|
|
945
1189
|
const taskID = args[3]
|
|
946
1190
|
const root = positionalArg(args, 4) || process.cwd()
|
|
947
1191
|
if (!slug || !taskID) throw new Error("Usage: ocskill sandbox create <slug> <task-id> [dir]")
|
|
948
|
-
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
|
+
}))
|
|
949
1197
|
return
|
|
950
1198
|
}
|
|
951
1199
|
if (action === "integrate") {
|
|
@@ -955,6 +1203,13 @@ async function sandboxControl() {
|
|
|
955
1203
|
printJson(await integrateTaskSandbox(root, dir, { keep: args.includes("--keep") }))
|
|
956
1204
|
return
|
|
957
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
|
+
}
|
|
958
1213
|
if (action === "remove") {
|
|
959
1214
|
const dir = args[2]
|
|
960
1215
|
const root = positionalArg(args, 3) || process.cwd()
|
|
@@ -965,10 +1220,9 @@ async function sandboxControl() {
|
|
|
965
1220
|
}))
|
|
966
1221
|
return
|
|
967
1222
|
}
|
|
968
|
-
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> ...")
|
|
969
1224
|
} catch (error) {
|
|
970
|
-
|
|
971
|
-
process.exitCode = 1
|
|
1225
|
+
printCliError(error)
|
|
972
1226
|
}
|
|
973
1227
|
}
|
|
974
1228
|
|
|
@@ -1005,8 +1259,7 @@ async function learningControl() {
|
|
|
1005
1259
|
}
|
|
1006
1260
|
throw new Error("Usage: ocskill learn <status|analyze|accept|promote> ...")
|
|
1007
1261
|
} catch (error) {
|
|
1008
|
-
|
|
1009
|
-
process.exitCode = 1
|
|
1262
|
+
printCliError(error)
|
|
1010
1263
|
}
|
|
1011
1264
|
}
|
|
1012
1265
|
|
|
@@ -1020,8 +1273,7 @@ async function hermesControl() {
|
|
|
1020
1273
|
const slug = args[2]
|
|
1021
1274
|
const root = positionalArg(args, 3) || process.cwd()
|
|
1022
1275
|
if (!slug) {
|
|
1023
|
-
|
|
1024
|
-
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 }))
|
|
1025
1277
|
return
|
|
1026
1278
|
}
|
|
1027
1279
|
const planFile = path.join(path.resolve(root), ".ues-work", slug, "PLAN.json")
|
|
@@ -1055,8 +1307,7 @@ async function hermesControl() {
|
|
|
1055
1307
|
const taskID = args[3]
|
|
1056
1308
|
const root = positionalArg(args, 4) || process.cwd()
|
|
1057
1309
|
if (!slug || !taskID) {
|
|
1058
|
-
|
|
1059
|
-
process.exitCode = 2
|
|
1310
|
+
printCliError(Object.assign(new Error("Usage: ocskill hermes <prompt|exec> <slug> <task-id> [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1060
1311
|
return
|
|
1061
1312
|
}
|
|
1062
1313
|
const prompt = buildHermesDelegationPrompt(await contextPack(root, slug, taskID))
|
|
@@ -1080,8 +1331,7 @@ async function hermesControl() {
|
|
|
1080
1331
|
if ((result.status ?? 1) !== 0) process.exitCode = result.status ?? 1
|
|
1081
1332
|
return
|
|
1082
1333
|
}
|
|
1083
|
-
|
|
1084
|
-
process.exitCode = 2
|
|
1334
|
+
printCliError(Object.assign(new Error("Usage: ocskill hermes <status|prompt|exec|workflow|exec-workflow> ..."), { code: "UES_USAGE", exitCode: 2 }))
|
|
1085
1335
|
}
|
|
1086
1336
|
|
|
1087
1337
|
async function evidenceStoreControl() {
|
|
@@ -1123,16 +1373,14 @@ async function evidenceStoreControl() {
|
|
|
1123
1373
|
}
|
|
1124
1374
|
throw new Error("Usage: ocskill store <status|put|get|gc> ...")
|
|
1125
1375
|
} catch (error) {
|
|
1126
|
-
|
|
1127
|
-
process.exitCode = 1
|
|
1376
|
+
printCliError(error)
|
|
1128
1377
|
}
|
|
1129
1378
|
}
|
|
1130
1379
|
|
|
1131
1380
|
async function capabilityControl() {
|
|
1132
1381
|
const text = args.slice(1).join(" ").trim()
|
|
1133
1382
|
if (!text) {
|
|
1134
|
-
|
|
1135
|
-
process.exitCode = 2
|
|
1383
|
+
printCliError(Object.assign(new Error("Usage: ocskill capabilities <task text>"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1136
1384
|
return
|
|
1137
1385
|
}
|
|
1138
1386
|
printJson(inferTaskCapabilities(text))
|
|
@@ -1181,8 +1429,7 @@ async function visualControl() {
|
|
|
1181
1429
|
}
|
|
1182
1430
|
throw new Error("Usage: ocskill visual <spec|geometry|compare|crop|viewports> ...")
|
|
1183
1431
|
} catch (error) {
|
|
1184
|
-
|
|
1185
|
-
process.exitCode = 1
|
|
1432
|
+
printCliError(error)
|
|
1186
1433
|
}
|
|
1187
1434
|
}
|
|
1188
1435
|
|
|
@@ -1220,8 +1467,7 @@ async function browserControl() {
|
|
|
1220
1467
|
}
|
|
1221
1468
|
throw new Error("Usage: ocskill browser <capability|plan|inspect> ...")
|
|
1222
1469
|
} catch (error) {
|
|
1223
|
-
|
|
1224
|
-
process.exitCode = 1
|
|
1470
|
+
printCliError(error)
|
|
1225
1471
|
}
|
|
1226
1472
|
}
|
|
1227
1473
|
|
|
@@ -1251,16 +1497,83 @@ async function uiControl() {
|
|
|
1251
1497
|
}
|
|
1252
1498
|
throw new Error("Usage: ocskill ui <tokens|layout> ...")
|
|
1253
1499
|
} catch (error) {
|
|
1254
|
-
|
|
1255
|
-
process.exitCode = 1
|
|
1500
|
+
printCliError(error)
|
|
1256
1501
|
}
|
|
1257
1502
|
}
|
|
1258
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
|
|
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) })
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1259
1573
|
async function workflowPlanControl() {
|
|
1260
1574
|
const file = args[1]
|
|
1261
1575
|
if (!file) {
|
|
1262
|
-
|
|
1263
|
-
process.exitCode = 2
|
|
1576
|
+
printCliError(Object.assign(new Error("Usage: ocskill workflow-plan <PLAN.json> [--max-concurrent N]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1264
1577
|
return
|
|
1265
1578
|
}
|
|
1266
1579
|
try {
|
|
@@ -1274,23 +1587,20 @@ async function workflowPlanControl() {
|
|
|
1274
1587
|
minVisionAgentCost: optionInt(args, "--min-vision-agent-cost", 4),
|
|
1275
1588
|
}))
|
|
1276
1589
|
} catch (error) {
|
|
1277
|
-
|
|
1278
|
-
process.exitCode = 1
|
|
1590
|
+
printCliError(error)
|
|
1279
1591
|
}
|
|
1280
1592
|
}
|
|
1281
1593
|
|
|
1282
1594
|
async function skillsControl() {
|
|
1283
1595
|
const action = args[1] || "lint"
|
|
1284
1596
|
if (action !== "lint") {
|
|
1285
|
-
|
|
1286
|
-
process.exitCode = 2
|
|
1597
|
+
printCliError(Object.assign(new Error("Usage: ocskill skills lint [dir]"), { code: "UES_USAGE", exitCode: 2 }))
|
|
1287
1598
|
return
|
|
1288
1599
|
}
|
|
1289
1600
|
try {
|
|
1290
1601
|
printJson(await lintSkillCatalog(positionalArg(args, 2) || packageRoot))
|
|
1291
1602
|
} catch (error) {
|
|
1292
|
-
|
|
1293
|
-
process.exitCode = 1
|
|
1603
|
+
printCliError(error)
|
|
1294
1604
|
}
|
|
1295
1605
|
}
|
|
1296
1606
|
|
|
@@ -1329,8 +1639,7 @@ async function update() {
|
|
|
1329
1639
|
compared = compareVersions(latestVersion, currentVersion)
|
|
1330
1640
|
} catch (error) {
|
|
1331
1641
|
console.error("[ocskill] npm returned a version that could not be compared safely; refusing update.")
|
|
1332
|
-
|
|
1333
|
-
process.exitCode = 1
|
|
1642
|
+
printCliError(error)
|
|
1334
1643
|
return
|
|
1335
1644
|
}
|
|
1336
1645
|
|
|
@@ -1391,7 +1700,13 @@ async function remove() {
|
|
|
1391
1700
|
if (code !== 0) process.exitCode = code
|
|
1392
1701
|
}
|
|
1393
1702
|
|
|
1394
|
-
|
|
1703
|
+
async function main() {
|
|
1704
|
+
if (helpRequested) {
|
|
1705
|
+
printCommandHelp(command, args[1])
|
|
1706
|
+
return
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
switch (command) {
|
|
1395
1710
|
case "install":
|
|
1396
1711
|
case "sync":
|
|
1397
1712
|
await install()
|
|
@@ -1481,6 +1796,15 @@ switch (command) {
|
|
|
1481
1796
|
case "workflow-plan":
|
|
1482
1797
|
await workflowPlanControl()
|
|
1483
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
|
|
1484
1808
|
case "ui":
|
|
1485
1809
|
await uiControl()
|
|
1486
1810
|
break
|
|
@@ -1519,8 +1843,17 @@ switch (command) {
|
|
|
1519
1843
|
case "-h":
|
|
1520
1844
|
printHelp()
|
|
1521
1845
|
break
|
|
1522
|
-
default:
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
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)
|
|
1526
1859
|
}
|