@kisev/skills-opencode 2.4.1 → 3.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/README.md +6 -4
- package/README.ru.md +7 -7
- package/dist/assets/agents/manager.md +9 -7
- package/dist/assets/migration-inventory.json +16 -10
- package/dist/catalog.d.ts +3 -3
- package/dist/catalog.js +2 -4
- package/dist/cli-output.d.ts +2 -0
- package/dist/cli-output.js +22 -4
- package/dist/cli.js +153 -126
- package/dist/doctor.js +0 -1
- package/dist/index.d.ts +0 -136
- package/dist/index.js +1 -95
- package/dist/installer.d.ts +0 -1
- package/dist/installer.js +15 -11
- package/dist/lifecycle.d.ts +14 -1
- package/dist/lifecycle.js +67 -24
- package/dist/reconcile.d.ts +43 -5
- package/dist/reconcile.js +539 -71
- package/dist/registry.d.ts +2 -4
- package/dist/registry.js +5 -43
- package/package.json +1 -1
- package/dist/assets/commands/agent-profiles.md +0 -9
- package/dist/assets/commands/capabilities.md +0 -9
- package/dist/assets/commands/doctor.md +0 -9
- package/dist/assets/commands/doit.md +0 -10
- package/dist/assets/commands/lsp-report.md +0 -10
- package/dist/assets/commands/reconcile.md +0 -9
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { AgentProfileError, applyAgentProfileChange, availableModels, availableModelVariants, FIXED_AGENT_ROLES, listAgentProfiles, previewAgentProfileChange, validateAgentName, validateModel, validateVariant, } from "./agent-profiles.js";
|
|
3
|
-
import { renderDoctor, renderInventory, renderPlan, renderReconcile, shellCommand, terminalSafe, } from "./cli-output.js";
|
|
3
|
+
import { renderDoctor, renderInventory, renderPlan, renderReconcile, scopeArguments, shellCommand, terminalSafe, } from "./cli-output.js";
|
|
4
4
|
import { collectDoctorFacts, doctorExitCode } from "./doctor.js";
|
|
5
5
|
import { CATALOG } from "./catalog.js";
|
|
6
|
-
import { apply, defaultSelection, InstallerError, normalizeSelection,
|
|
6
|
+
import { apply, defaultSelection, InstallerError, normalizeSelection, preview, SELECTABLE_PLUGINS, SKILL_COMMANDS, } from "./installer.js";
|
|
7
7
|
import { LifecycleError } from "./lifecycle.js";
|
|
8
8
|
import { skillsInstallerSpec } from "./package-metadata.js";
|
|
9
9
|
import { applyReconcile, previewReconcile } from "./reconcile.js";
|
|
10
10
|
import { promptText, selectOption, selectOptions } from "./terminal-wizard.js";
|
|
11
|
-
function parseOptions(values
|
|
12
|
-
const options = {
|
|
11
|
+
function parseOptions(values) {
|
|
12
|
+
const options = {
|
|
13
|
+
scope: "project",
|
|
14
|
+
global: false,
|
|
15
|
+
dryRun: false,
|
|
16
|
+
json: false,
|
|
17
|
+
selectionFlag: false,
|
|
18
|
+
};
|
|
13
19
|
for (let index = 0; index < values.length; index += 1) {
|
|
14
20
|
const value = values[index];
|
|
15
21
|
if (!value.startsWith("--")) {
|
|
@@ -17,13 +23,11 @@ function parseOptions(values, requireScope = true) {
|
|
|
17
23
|
throw new InstallerError("invalid_input", `Unexpected argument: ${value}`);
|
|
18
24
|
options.name = value;
|
|
19
25
|
}
|
|
20
|
-
else if (value === "--
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
throw new InstallerError("invalid_input", "--scope may be supplied once");
|
|
26
|
-
options.scope = scope;
|
|
26
|
+
else if (value === "--global") {
|
|
27
|
+
if (options.global)
|
|
28
|
+
throw new InstallerError("invalid_input", "--global may be supplied once");
|
|
29
|
+
options.global = true;
|
|
30
|
+
options.scope = "global";
|
|
27
31
|
}
|
|
28
32
|
else if (value === "--dry-run") {
|
|
29
33
|
if (options.dryRun)
|
|
@@ -62,7 +66,7 @@ function parseOptions(values, requireScope = true) {
|
|
|
62
66
|
throw new InstallerError("invalid_input", "--json may be supplied once");
|
|
63
67
|
options.json = true;
|
|
64
68
|
}
|
|
65
|
-
else if (["--commands", "--skill-commands", "--
|
|
69
|
+
else if (["--commands", "--skill-commands", "--agents", "--plugins"].includes(value)) {
|
|
66
70
|
const raw = values[++index];
|
|
67
71
|
if (!raw)
|
|
68
72
|
throw new InstallerError("invalid_input", `${value} requires a comma-separated value`);
|
|
@@ -74,10 +78,7 @@ function parseOptions(values, requireScope = true) {
|
|
|
74
78
|
.map((item) => item.trim())
|
|
75
79
|
.filter(Boolean);
|
|
76
80
|
options.selectionFlag = true;
|
|
77
|
-
if (value === "--
|
|
78
|
-
options.commands = [...(options.commands ?? []), ...names];
|
|
79
|
-
}
|
|
80
|
-
else if (value === "--skill-commands") {
|
|
81
|
+
if (value === "--skill-commands") {
|
|
81
82
|
options.commands = [...(options.commands ?? []), ...names];
|
|
82
83
|
}
|
|
83
84
|
else {
|
|
@@ -88,8 +89,6 @@ function parseOptions(values, requireScope = true) {
|
|
|
88
89
|
throw new InstallerError("invalid_input", `Unknown argument: ${value}`);
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
|
-
if (requireScope && !options.scope)
|
|
92
|
-
throw new InstallerError("invalid_input", "--scope is required");
|
|
93
92
|
return options;
|
|
94
93
|
}
|
|
95
94
|
function helpRows(rows) {
|
|
@@ -109,7 +108,7 @@ function rootHelp() {
|
|
|
109
108
|
"",
|
|
110
109
|
"Commands:",
|
|
111
110
|
...helpRows([
|
|
112
|
-
["install", "Select and deploy
|
|
111
|
+
["install", "Select and deploy skill commands, agents, and plugin wrappers."],
|
|
113
112
|
[
|
|
114
113
|
"uninstall",
|
|
115
114
|
"Archive and remove exact-owned assets while preserving conflicts and user files.",
|
|
@@ -127,7 +126,7 @@ function rootHelp() {
|
|
|
127
126
|
"",
|
|
128
127
|
"Common options:",
|
|
129
128
|
...helpRows([
|
|
130
|
-
["--
|
|
129
|
+
["--global", "Use global scope; project scope is the default."],
|
|
131
130
|
["--dry-run", "Preview a mutation and issue a one-time confirmation digest."],
|
|
132
131
|
["--confirm <digest>", "Apply the exact unexpired preview after final revalidation."],
|
|
133
132
|
["--json", "Emit stable machine-readable output when supported."],
|
|
@@ -137,9 +136,8 @@ function rootHelp() {
|
|
|
137
136
|
"",
|
|
138
137
|
"Install selection:",
|
|
139
138
|
...helpRows([
|
|
140
|
-
["--commands <list|none>", "Select
|
|
139
|
+
["--commands <list|none>", "Select adapters for installed portable skills."],
|
|
141
140
|
["--skill-commands <list|none>", "Select adapters for installed portable skills."],
|
|
142
|
-
["--package-commands <list|none>", "Select adapters for package tools."],
|
|
143
141
|
["--agents <list|none>", "Select fixed agents."],
|
|
144
142
|
["--plugins <list|none>", "Select optional plugin wrappers."],
|
|
145
143
|
]),
|
|
@@ -163,20 +161,19 @@ function rootHelp() {
|
|
|
163
161
|
"",
|
|
164
162
|
"Scope behavior:",
|
|
165
163
|
...helpRows([
|
|
166
|
-
["
|
|
167
|
-
["global", "Targets ~/.config/opencode and can run from any directory."],
|
|
164
|
+
["default", "Targets .opencode under the current directory; run from the project root."],
|
|
165
|
+
["--global", "Targets ~/.config/opencode and can run from any directory."],
|
|
168
166
|
]),
|
|
169
167
|
"",
|
|
170
168
|
"Examples:",
|
|
171
169
|
` ${shellCommand(["capabilities", "--json"])}`,
|
|
172
|
-
` ${shellCommand(["install", "--
|
|
173
|
-
` ${shellCommand(["doctor", "--
|
|
170
|
+
` ${shellCommand(["install", "--global", "--dry-run"])}`,
|
|
171
|
+
` ${shellCommand(["doctor", "--global"])}`,
|
|
174
172
|
` ${shellCommand([
|
|
175
173
|
"agent",
|
|
176
174
|
"model-set",
|
|
177
175
|
"worker",
|
|
178
|
-
"--
|
|
179
|
-
"global",
|
|
176
|
+
"--global",
|
|
180
177
|
"--model",
|
|
181
178
|
"openai/gpt-5",
|
|
182
179
|
"--variant",
|
|
@@ -233,15 +230,14 @@ function contextualHelp(arguments_) {
|
|
|
233
230
|
const [domain, operation] = arguments_.filter((value) => value !== "--help");
|
|
234
231
|
if (domain === "install")
|
|
235
232
|
return commandHelp("install", "Select and deploy package-owned OpenCode integration assets.", [
|
|
236
|
-
"skills-opencode install --
|
|
237
|
-
"skills-opencode install --
|
|
233
|
+
"skills-opencode install [--global] --dry-run [selection options]",
|
|
234
|
+
"skills-opencode install [--global] --confirm <digest> [selection options]",
|
|
238
235
|
], [
|
|
239
|
-
["--
|
|
236
|
+
["--global", "Use global scope; project scope is the default."],
|
|
240
237
|
["--dry-run", "Preview operations and issue a one-time confirmation digest."],
|
|
241
238
|
["--confirm <digest>", "Apply the exact unexpired preview."],
|
|
242
|
-
["--commands <list|none>", "Select adapters
|
|
239
|
+
["--commands <list|none>", "Select installed-skill adapters."],
|
|
243
240
|
["--skill-commands <list|none>", "Select installed-skill adapters."],
|
|
244
|
-
["--package-commands <list|none>", "Select package-tool adapters."],
|
|
245
241
|
["--agents <list|none>", "Select fixed agents."],
|
|
246
242
|
["--plugins <list|none>", "Select optional plugin wrappers."],
|
|
247
243
|
["--json", "Emit stable machine-readable output."],
|
|
@@ -253,11 +249,9 @@ function contextualHelp(arguments_) {
|
|
|
253
249
|
"Writes occur only after confirmation; the installer never edits opencode.json.",
|
|
254
250
|
"Portable skills are installed separately; restart OpenCode after asset changes.",
|
|
255
251
|
], [
|
|
256
|
-
shellCommand(["install", "--
|
|
252
|
+
shellCommand(["install", "--global", "--dry-run"]),
|
|
257
253
|
shellCommand([
|
|
258
254
|
"install",
|
|
259
|
-
"--scope",
|
|
260
|
-
"project",
|
|
261
255
|
"--commands",
|
|
262
256
|
"doctor,reconcile,agent-profiles",
|
|
263
257
|
"--agents",
|
|
@@ -269,10 +263,10 @@ function contextualHelp(arguments_) {
|
|
|
269
263
|
]);
|
|
270
264
|
if (domain === "uninstall")
|
|
271
265
|
return commandHelp("uninstall", "Remove package-owned integration assets safely.", [
|
|
272
|
-
"skills-opencode uninstall --
|
|
273
|
-
"skills-opencode uninstall --
|
|
266
|
+
"skills-opencode uninstall [--global] --dry-run",
|
|
267
|
+
"skills-opencode uninstall [--global] --confirm <digest>",
|
|
274
268
|
], [
|
|
275
|
-
["--
|
|
269
|
+
["--global", "Use global scope; project scope is the default."],
|
|
276
270
|
["--dry-run", "Preview removals, archives, and conflicts."],
|
|
277
271
|
["--confirm <digest>", "Apply the exact unexpired preview."],
|
|
278
272
|
["--json", "Emit stable machine-readable output."],
|
|
@@ -282,22 +276,19 @@ function contextualHelp(arguments_) {
|
|
|
282
276
|
"Preserves modified and user-owned files, worktrees, runtime state, and portable skills.",
|
|
283
277
|
"Remove the plugin config entry and npm dependency only after managed assets.",
|
|
284
278
|
], [
|
|
285
|
-
shellCommand(["uninstall", "--
|
|
286
|
-
shellCommand(["uninstall", "--
|
|
279
|
+
shellCommand(["uninstall", "--global", "--dry-run"]),
|
|
280
|
+
shellCommand(["uninstall", "--dry-run"]),
|
|
287
281
|
]);
|
|
288
282
|
if (domain === "doctor")
|
|
289
|
-
return commandHelp("doctor", "Inspect integration health without changing state.", ["skills-opencode doctor --
|
|
290
|
-
["--
|
|
283
|
+
return commandHelp("doctor", "Inspect integration health without changing state.", ["skills-opencode doctor [--global] [--json]"], [
|
|
284
|
+
["--global", "Inspect global scope; project scope is the default."],
|
|
291
285
|
["--json", "Emit the complete stable machine-readable report."],
|
|
292
286
|
["--help", "Show this command help and exit."],
|
|
293
287
|
], [
|
|
294
288
|
"Creates no receipts and starts no recovery, plugin factories, or LSP servers.",
|
|
295
289
|
"Reports versions, ownership, drift, collisions, config, archives, tools, and LSP facts.",
|
|
296
290
|
"Exit status: 0 clean, 1 findings, 2 invalid input or incomplete probing.",
|
|
297
|
-
], [
|
|
298
|
-
shellCommand(["doctor", "--scope", "global"]),
|
|
299
|
-
shellCommand(["doctor", "--scope", "global", "--json"]),
|
|
300
|
-
]);
|
|
291
|
+
], [shellCommand(["doctor"]), shellCommand(["doctor", "--global", "--json"])]);
|
|
301
292
|
if (domain === "capabilities")
|
|
302
293
|
return commandHelp("capabilities", "Print the versioned package capability catalog.", ["skills-opencode capabilities [--json]"], [
|
|
303
294
|
["--json", "Explicitly request stable JSON output; JSON is the default."],
|
|
@@ -308,38 +299,35 @@ function contextualHelp(arguments_) {
|
|
|
308
299
|
], [shellCommand(["capabilities", "--json"])]);
|
|
309
300
|
if (domain === "reconcile")
|
|
310
301
|
return commandHelp("reconcile", "Classify current and historical assets and retire exact-owned entries.", [
|
|
311
|
-
"skills-opencode reconcile --
|
|
312
|
-
"skills-opencode reconcile --
|
|
302
|
+
"skills-opencode reconcile [--global] --dry-run",
|
|
303
|
+
"skills-opencode reconcile [--global] --confirm <digest>",
|
|
313
304
|
], [
|
|
314
|
-
["--
|
|
305
|
+
["--global", "Reconcile global scope; project scope is the default."],
|
|
315
306
|
["--dry-run", "Preview classifications, archives, and blockers."],
|
|
316
307
|
["--confirm <digest>", "Apply the exact unexpired preview."],
|
|
317
308
|
["--json", "Emit stable machine-readable output."],
|
|
318
309
|
["--help", "Show this command help and exit."],
|
|
319
310
|
], [
|
|
320
311
|
"Preview is read-only and blocks Apply on modified managed files or ownership conflicts.",
|
|
321
|
-
"Confirmed reconcile archives
|
|
322
|
-
"
|
|
312
|
+
"Confirmed reconcile archives exact-owned retired package assets.",
|
|
313
|
+
"Marked retired portable skills are removed by the pinned skills CLI.",
|
|
323
314
|
], [
|
|
324
|
-
shellCommand(["reconcile", "--
|
|
325
|
-
shellCommand(["reconcile", "--
|
|
315
|
+
shellCommand(["reconcile", "--global", "--dry-run"]),
|
|
316
|
+
shellCommand(["reconcile", "--dry-run", "--json"]),
|
|
326
317
|
]);
|
|
327
318
|
if (domain === "agent" && operation === "list")
|
|
328
|
-
return commandHelp("agent list", "List agent profiles, models, ownership, collisions, and drift.", ["skills-opencode agent list --
|
|
329
|
-
["--
|
|
319
|
+
return commandHelp("agent list", "List agent profiles, models, ownership, collisions, and drift.", ["skills-opencode agent list [--global] [--json]"], [
|
|
320
|
+
["--global", "Inspect global scope; project scope is the default."],
|
|
330
321
|
["--json", "Emit stable machine-readable inventory."],
|
|
331
322
|
["--help", "Show this command help and exit."],
|
|
332
|
-
], ["Read-only inventory; creates no receipts and changes no files or configuration."], [
|
|
333
|
-
shellCommand(["agent", "list", "--scope", "global"]),
|
|
334
|
-
shellCommand(["agent", "list", "--scope", "project", "--json"]),
|
|
335
|
-
]);
|
|
323
|
+
], ["Read-only inventory; creates no receipts and changes no files or configuration."], [shellCommand(["agent", "list", "--global"]), shellCommand(["agent", "list", "--json"])]);
|
|
336
324
|
if (domain === "agent" && operation === "configure")
|
|
337
325
|
return commandHelp("agent configure", "Choose an agent model interactively or with explicit options.", [
|
|
338
|
-
"skills-opencode agent configure [name] --
|
|
339
|
-
"skills-opencode agent configure <name> --
|
|
340
|
-
"skills-opencode agent configure <name> --
|
|
326
|
+
"skills-opencode agent configure [name] [--global] --dry-run",
|
|
327
|
+
"skills-opencode agent configure <name> [--global] --model <provider/model> [--variant <id>] --dry-run",
|
|
328
|
+
"skills-opencode agent configure <name> [--global] --model <provider/model> [--variant <id>] --confirm <digest>",
|
|
341
329
|
], [
|
|
342
|
-
["--
|
|
330
|
+
["--global", "Use global scope; project scope is the default."],
|
|
343
331
|
["--provider <id>", "Provider when --model is not provider/model."],
|
|
344
332
|
["--model <id>", "Exact provider/model or model paired with --provider."],
|
|
345
333
|
["--variant <id>", "Set an optional model variant."],
|
|
@@ -353,13 +341,12 @@ function contextualHelp(arguments_) {
|
|
|
353
341
|
"Uses the cached OpenCode model catalog and makes no LLM call.",
|
|
354
342
|
"The preview normally prints an agent model-set Apply command.",
|
|
355
343
|
], [
|
|
356
|
-
shellCommand(["agent", "configure", "manager", "--
|
|
344
|
+
shellCommand(["agent", "configure", "manager", "--global", "--dry-run"]),
|
|
357
345
|
shellCommand([
|
|
358
346
|
"agent",
|
|
359
347
|
"configure",
|
|
360
348
|
"worker",
|
|
361
|
-
"--
|
|
362
|
-
"global",
|
|
349
|
+
"--global",
|
|
363
350
|
"--model",
|
|
364
351
|
"openai/gpt-5",
|
|
365
352
|
"--variant",
|
|
@@ -369,10 +356,10 @@ function contextualHelp(arguments_) {
|
|
|
369
356
|
]);
|
|
370
357
|
if (domain === "agent" && operation === "model-set")
|
|
371
358
|
return commandHelp("agent model-set", "Set one agent model and optional variant directly.", [
|
|
372
|
-
"skills-opencode agent model-set <name> --
|
|
373
|
-
"skills-opencode agent model-set <name> --
|
|
359
|
+
"skills-opencode agent model-set <name> [--global] --model <provider/model> [--variant <id>] --dry-run",
|
|
360
|
+
"skills-opencode agent model-set <name> [--global] --model <provider/model> [--variant <id>] --confirm <digest>",
|
|
374
361
|
], [
|
|
375
|
-
["--
|
|
362
|
+
["--global", "Use global scope; project scope is the default."],
|
|
376
363
|
["--provider <id>", "Provider when --model is not provider/model."],
|
|
377
364
|
["--model <id>", "Exact provider/model or model paired with --provider."],
|
|
378
365
|
["--variant <id>", "Set an optional model variant."],
|
|
@@ -390,8 +377,7 @@ function contextualHelp(arguments_) {
|
|
|
390
377
|
"agent",
|
|
391
378
|
"model-set",
|
|
392
379
|
"worker",
|
|
393
|
-
"--
|
|
394
|
-
"global",
|
|
380
|
+
"--global",
|
|
395
381
|
"--model",
|
|
396
382
|
"openai/gpt-5",
|
|
397
383
|
"--variant",
|
|
@@ -402,8 +388,7 @@ function contextualHelp(arguments_) {
|
|
|
402
388
|
"agent",
|
|
403
389
|
"model-set",
|
|
404
390
|
"manager",
|
|
405
|
-
"--
|
|
406
|
-
"global",
|
|
391
|
+
"--global",
|
|
407
392
|
"--model",
|
|
408
393
|
"openai/gpt-5",
|
|
409
394
|
"--clear-variant",
|
|
@@ -412,10 +397,10 @@ function contextualHelp(arguments_) {
|
|
|
412
397
|
]);
|
|
413
398
|
if (domain === "agent" && operation === "reconcile")
|
|
414
399
|
return commandHelp("agent reconcile", "Re-render managed agent files from saved profile configuration.", [
|
|
415
|
-
"skills-opencode agent reconcile --
|
|
416
|
-
"skills-opencode agent reconcile --
|
|
400
|
+
"skills-opencode agent reconcile [--global] --dry-run",
|
|
401
|
+
"skills-opencode agent reconcile [--global] --confirm <digest>",
|
|
417
402
|
], [
|
|
418
|
-
["--
|
|
403
|
+
["--global", "Use global scope; project scope is the default."],
|
|
419
404
|
["--dry-run", "Preview rendered agent changes and conflicts."],
|
|
420
405
|
["--confirm <digest>", "Apply the exact unexpired preview."],
|
|
421
406
|
["--json", "Emit stable machine-readable output."],
|
|
@@ -424,8 +409,8 @@ function contextualHelp(arguments_) {
|
|
|
424
409
|
"Uses saved models and variants while preserving package prompts and permissions.",
|
|
425
410
|
"Preserves user-owned files and collisions; writes only after confirmation.",
|
|
426
411
|
], [
|
|
427
|
-
shellCommand(["agent", "reconcile", "--
|
|
428
|
-
shellCommand(["agent", "reconcile", "--
|
|
412
|
+
shellCommand(["agent", "reconcile", "--global", "--dry-run"]),
|
|
413
|
+
shellCommand(["agent", "reconcile", "--dry-run", "--json"]),
|
|
429
414
|
]);
|
|
430
415
|
if (domain === "agent")
|
|
431
416
|
return groupHelp("agent", "Inspect and manage fixed agents and additional critics.", "skills-opencode agent <command> [options]", [
|
|
@@ -437,17 +422,14 @@ function contextualHelp(arguments_) {
|
|
|
437
422
|
"Prompts and permissions remain package-owned.",
|
|
438
423
|
"Profile configuration changes models, variants, and additional critics.",
|
|
439
424
|
"Mutations use preview and exact confirmation.",
|
|
440
|
-
], [
|
|
441
|
-
shellCommand(["agent", "list", "--scope", "global"]),
|
|
442
|
-
shellCommand(["agent", "model-set", "--help"]),
|
|
443
|
-
]);
|
|
425
|
+
], [shellCommand(["agent", "list", "--global"]), shellCommand(["agent", "model-set", "--help"])]);
|
|
444
426
|
if (domain === "critic" && operation === "add")
|
|
445
427
|
return commandHelp("critic add", "Add an additional named critic with a selected model.", [
|
|
446
|
-
"skills-opencode critic add [name] --
|
|
447
|
-
"skills-opencode critic add <name> --
|
|
448
|
-
"skills-opencode critic add <name> --
|
|
428
|
+
"skills-opencode critic add [name] [--global] --dry-run",
|
|
429
|
+
"skills-opencode critic add <name> [--global] --model <provider/model> [--variant <id>] --dry-run",
|
|
430
|
+
"skills-opencode critic add <name> [--global] --model <provider/model> [--variant <id>] --confirm <digest>",
|
|
449
431
|
], [
|
|
450
|
-
["--
|
|
432
|
+
["--global", "Use global scope; project scope is the default."],
|
|
451
433
|
["--provider <id>", "Provider when --model is not provider/model."],
|
|
452
434
|
["--model <id>", "Exact provider/model or model paired with --provider."],
|
|
453
435
|
["--variant <id>", "Set an optional model variant."],
|
|
@@ -464,20 +446,19 @@ function contextualHelp(arguments_) {
|
|
|
464
446
|
"critic",
|
|
465
447
|
"add",
|
|
466
448
|
"security",
|
|
467
|
-
"--
|
|
468
|
-
"global",
|
|
449
|
+
"--global",
|
|
469
450
|
"--model",
|
|
470
451
|
"anthropic/claude-sonnet-4-6",
|
|
471
452
|
"--dry-run",
|
|
472
453
|
]),
|
|
473
|
-
shellCommand(["critic", "add", "performance", "--
|
|
454
|
+
shellCommand(["critic", "add", "performance", "--global", "--dry-run"]),
|
|
474
455
|
]);
|
|
475
456
|
if (domain === "critic" && operation === "remove")
|
|
476
457
|
return commandHelp("critic remove", "Remove a package-managed additional critic.", [
|
|
477
|
-
"skills-opencode critic remove <name> --
|
|
478
|
-
"skills-opencode critic remove <name> --
|
|
458
|
+
"skills-opencode critic remove <name> [--global] --dry-run",
|
|
459
|
+
"skills-opencode critic remove <name> [--global] --confirm <digest>",
|
|
479
460
|
], [
|
|
480
|
-
["--
|
|
461
|
+
["--global", "Use global scope; project scope is the default."],
|
|
481
462
|
["--dry-run", "Preview critic removal and pool changes."],
|
|
482
463
|
["--confirm <digest>", "Apply the exact unexpired preview."],
|
|
483
464
|
["--json", "Emit stable machine-readable output."],
|
|
@@ -487,8 +468,8 @@ function contextualHelp(arguments_) {
|
|
|
487
468
|
"Preserves the fixed critic and user-owned files.",
|
|
488
469
|
"Updates manager and review critic pools after confirmation.",
|
|
489
470
|
], [
|
|
490
|
-
shellCommand(["critic", "remove", "security", "--
|
|
491
|
-
shellCommand(["critic", "remove", "security", "--
|
|
471
|
+
shellCommand(["critic", "remove", "security", "--global", "--dry-run"]),
|
|
472
|
+
shellCommand(["critic", "remove", "security", "--dry-run"]),
|
|
492
473
|
]);
|
|
493
474
|
if (domain === "critic")
|
|
494
475
|
return groupHelp("critic", "Manage additional package-owned critic profiles.", "skills-opencode critic <command> [options]", [
|
|
@@ -504,9 +485,6 @@ function contextualHelp(arguments_) {
|
|
|
504
485
|
]);
|
|
505
486
|
return undefined;
|
|
506
487
|
}
|
|
507
|
-
function help(arguments_ = []) {
|
|
508
|
-
return contextualHelp(arguments_) ?? rootHelp();
|
|
509
|
-
}
|
|
510
488
|
async function interactiveInstallerSelection() {
|
|
511
489
|
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
512
490
|
throw new InstallerError("terminal_required", "install requires explicit selection flags outside a terminal");
|
|
@@ -514,7 +492,6 @@ async function interactiveInstallerSelection() {
|
|
|
514
492
|
"Portable skills are installed separately through npx skills.",
|
|
515
493
|
"This installer does not install, update, or remove portable skills.",
|
|
516
494
|
"Skill command adapters are OpenCode slash commands that load an already-installed skill with the same name.",
|
|
517
|
-
"Package command adapters invoke package tools.",
|
|
518
495
|
"Selecting a command adapter does not select or install its skill.",
|
|
519
496
|
"\n",
|
|
520
497
|
].join("\n"));
|
|
@@ -525,10 +502,7 @@ async function interactiveInstallerSelection() {
|
|
|
525
502
|
return selected;
|
|
526
503
|
};
|
|
527
504
|
const defaults = defaultSelection();
|
|
528
|
-
const commands =
|
|
529
|
-
...(await group("Skill command adapters", SKILL_COMMANDS, SKILL_COMMANDS)),
|
|
530
|
-
...(await group("Package command adapters", PACKAGE_COMMANDS, PACKAGE_COMMANDS)),
|
|
531
|
-
];
|
|
505
|
+
const commands = await group("Skill command adapters", SKILL_COMMANDS, SKILL_COMMANDS);
|
|
532
506
|
const agents = await group("Fixed agents", defaults.agents, defaults.agents);
|
|
533
507
|
const plugins = await group("Selectable plugins", SELECTABLE_PLUGINS, []);
|
|
534
508
|
return normalizeSelection({
|
|
@@ -717,13 +691,13 @@ async function runProfile(request, options) {
|
|
|
717
691
|
}
|
|
718
692
|
function profileConfirmationArguments(request, scope, digest) {
|
|
719
693
|
if (request.action === "reconcile")
|
|
720
|
-
return ["agent", "reconcile",
|
|
694
|
+
return ["agent", "reconcile", ...scopeArguments(scope), "--confirm", digest];
|
|
721
695
|
if (request.action === "critic-remove")
|
|
722
|
-
return ["critic", "remove", request.name,
|
|
696
|
+
return ["critic", "remove", request.name, ...scopeArguments(scope), "--confirm", digest];
|
|
723
697
|
const command = request.action === "critic-add"
|
|
724
698
|
? ["critic", "add", request.name]
|
|
725
699
|
: ["agent", "model-set", request.name];
|
|
726
|
-
command.push(
|
|
700
|
+
command.push(...scopeArguments(scope), "--model", request.model);
|
|
727
701
|
if (request.variant)
|
|
728
702
|
command.push("--variant", request.variant);
|
|
729
703
|
else if (request.action === "model-set")
|
|
@@ -732,11 +706,36 @@ function profileConfirmationArguments(request, scope, digest) {
|
|
|
732
706
|
return command;
|
|
733
707
|
}
|
|
734
708
|
async function run(arguments_) {
|
|
735
|
-
|
|
736
|
-
|
|
709
|
+
const removedScope = arguments_.find((value) => value === "--scope" || value.startsWith("--scope="));
|
|
710
|
+
if (removedScope)
|
|
711
|
+
throw new InstallerError("invalid_input", "--scope has been removed; omit it for project scope or use --global");
|
|
712
|
+
if (arguments_.filter((value) => value === "--global").length > 1)
|
|
713
|
+
throw new InstallerError("invalid_input", "--global may be supplied once");
|
|
714
|
+
if (arguments_[0] === "capabilities" && arguments_.includes("--global"))
|
|
715
|
+
throw new InstallerError("invalid_input", "capabilities accepts only --json");
|
|
716
|
+
if (arguments_.includes("--help")) {
|
|
717
|
+
const [domain, operation] = arguments_.filter((value) => !value.startsWith("--"));
|
|
718
|
+
if ((domain === "agent" &&
|
|
719
|
+
operation &&
|
|
720
|
+
!["list", "configure", "model-set", "reconcile"].includes(operation)) ||
|
|
721
|
+
(domain === "critic" && operation && !["add", "remove"].includes(operation)))
|
|
722
|
+
throw new InstallerError("invalid_input", `Unknown command: ${domain} ${operation}`);
|
|
723
|
+
const page = contextualHelp(arguments_);
|
|
724
|
+
if (!page && arguments_[0] !== "--help")
|
|
725
|
+
throw new InstallerError("invalid_input", `Unknown command: ${arguments_[0]}`);
|
|
726
|
+
for (const value of arguments_.filter((item) => item.startsWith("--") && item !== "--help"))
|
|
727
|
+
if (!(page ?? rootHelp()).includes(value))
|
|
728
|
+
throw new InstallerError("invalid_input", `Unknown argument: ${value}`);
|
|
729
|
+
process.stdout.write(page ?? rootHelp());
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (arguments_.length === 0) {
|
|
733
|
+
process.stdout.write(rootHelp());
|
|
737
734
|
return;
|
|
738
735
|
}
|
|
739
736
|
if (arguments_.includes("--version")) {
|
|
737
|
+
if (arguments_.some((value) => value !== "--version" && value !== "--json"))
|
|
738
|
+
throw new InstallerError("invalid_input", "--version accepts only --json");
|
|
740
739
|
process.stdout.write(arguments_.includes("--json")
|
|
741
740
|
? `${JSON.stringify({ status: "ok", version: CATALOG.version })}\n`
|
|
742
741
|
: `${CATALOG.version}\n`);
|
|
@@ -752,8 +751,9 @@ async function run(arguments_) {
|
|
|
752
751
|
options.name ||
|
|
753
752
|
options.provider ||
|
|
754
753
|
options.model ||
|
|
755
|
-
options.variant !== undefined
|
|
756
|
-
|
|
754
|
+
options.variant !== undefined ||
|
|
755
|
+
options.selectionFlag)
|
|
756
|
+
throw new InstallerError("invalid_input", "doctor accepts only --global and --json");
|
|
757
757
|
const report = await collectDoctorFacts(options.scope);
|
|
758
758
|
if (options.json)
|
|
759
759
|
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
@@ -763,15 +763,18 @@ async function run(arguments_) {
|
|
|
763
763
|
return;
|
|
764
764
|
}
|
|
765
765
|
if (domain === "capabilities") {
|
|
766
|
-
|
|
766
|
+
if (operation)
|
|
767
|
+
rest.unshift(operation);
|
|
768
|
+
const options = parseOptions(rest);
|
|
767
769
|
if (options.dryRun ||
|
|
768
770
|
options.confirm ||
|
|
769
771
|
options.name ||
|
|
770
772
|
options.provider ||
|
|
771
773
|
options.model ||
|
|
772
774
|
options.variant !== undefined ||
|
|
775
|
+
options.global ||
|
|
773
776
|
options.selectionFlag)
|
|
774
|
-
throw new InstallerError("invalid_input", "capabilities accepts only --
|
|
777
|
+
throw new InstallerError("invalid_input", "capabilities accepts only --json");
|
|
775
778
|
process.stdout.write(`${JSON.stringify({ schema_version: 1, status: "ok", ...CATALOG }, null, 2)}\n`);
|
|
776
779
|
return;
|
|
777
780
|
}
|
|
@@ -779,8 +782,12 @@ async function run(arguments_) {
|
|
|
779
782
|
if (operation)
|
|
780
783
|
rest.unshift(operation);
|
|
781
784
|
const options = parseOptions(rest);
|
|
782
|
-
if (options.name ||
|
|
783
|
-
|
|
785
|
+
if (options.name ||
|
|
786
|
+
options.provider ||
|
|
787
|
+
options.model ||
|
|
788
|
+
options.variant !== undefined ||
|
|
789
|
+
options.selectionFlag)
|
|
790
|
+
throw new InstallerError("invalid_input", "reconcile accepts only --global, --dry-run, --confirm, and --json");
|
|
784
791
|
requireConfirmationMode(options);
|
|
785
792
|
if (options.dryRun) {
|
|
786
793
|
const plan = await previewReconcile(options.scope);
|
|
@@ -792,8 +799,7 @@ async function run(arguments_) {
|
|
|
792
799
|
confirmationCommand: plan.confirmable
|
|
793
800
|
? shellCommand([
|
|
794
801
|
"reconcile",
|
|
795
|
-
|
|
796
|
-
options.scope,
|
|
802
|
+
...scopeArguments(options.scope),
|
|
797
803
|
"--confirm",
|
|
798
804
|
plan.confirmation_digest ?? plan.digest,
|
|
799
805
|
])
|
|
@@ -815,9 +821,15 @@ async function run(arguments_) {
|
|
|
815
821
|
else
|
|
816
822
|
throw new InstallerError("invalid_input", `Unexpected argument: ${operation}`);
|
|
817
823
|
const options = parseOptions(rest);
|
|
818
|
-
if (options.name || options.provider || options.model || options.variant !== undefined)
|
|
819
|
-
throw new InstallerError("invalid_input", "Installer accepts only scope and confirmation options");
|
|
820
824
|
const action = domain;
|
|
825
|
+
if (options.name ||
|
|
826
|
+
options.provider ||
|
|
827
|
+
options.model ||
|
|
828
|
+
options.variant !== undefined ||
|
|
829
|
+
(action === "uninstall" && options.selectionFlag))
|
|
830
|
+
throw new InstallerError("invalid_input", action === "install"
|
|
831
|
+
? "install does not accept model options or positional arguments"
|
|
832
|
+
: "uninstall accepts only --global, --dry-run, --confirm, and --json");
|
|
821
833
|
if (action === "install" &&
|
|
822
834
|
options.selectionFlag &&
|
|
823
835
|
(options.commands === undefined ||
|
|
@@ -839,8 +851,7 @@ async function run(arguments_) {
|
|
|
839
851
|
applied: false,
|
|
840
852
|
confirmationCommand: shellCommand([
|
|
841
853
|
action,
|
|
842
|
-
|
|
843
|
-
options.scope,
|
|
854
|
+
...scopeArguments(options.scope),
|
|
844
855
|
...selectionArguments(plan.selection),
|
|
845
856
|
"--confirm",
|
|
846
857
|
plan.digest,
|
|
@@ -863,8 +874,9 @@ async function run(arguments_) {
|
|
|
863
874
|
options.name ||
|
|
864
875
|
options.provider ||
|
|
865
876
|
options.model ||
|
|
866
|
-
options.variant !== undefined
|
|
867
|
-
|
|
877
|
+
options.variant !== undefined ||
|
|
878
|
+
options.selectionFlag)
|
|
879
|
+
throw new InstallerError("invalid_input", "agent list accepts only --global and --json");
|
|
868
880
|
const inventory = await listAgentProfiles(options.scope);
|
|
869
881
|
if (options.json)
|
|
870
882
|
process.stdout.write(`${JSON.stringify({ status: "ok", inventory }, null, 2)}\n`);
|
|
@@ -874,6 +886,8 @@ async function run(arguments_) {
|
|
|
874
886
|
}
|
|
875
887
|
if (domain === "agent" && operation === "configure") {
|
|
876
888
|
const options = parseOptions(rest);
|
|
889
|
+
if (options.selectionFlag)
|
|
890
|
+
throw new InstallerError("invalid_input", "agent configure does not accept selection options");
|
|
877
891
|
requireConfirmationMode(options);
|
|
878
892
|
const selected = options.provider && options.model && options.name
|
|
879
893
|
? {
|
|
@@ -889,6 +903,8 @@ async function run(arguments_) {
|
|
|
889
903
|
}
|
|
890
904
|
if (domain === "agent" && operation === "model-set") {
|
|
891
905
|
const options = parseOptions(rest);
|
|
906
|
+
if (options.selectionFlag)
|
|
907
|
+
throw new InstallerError("invalid_input", "agent model-set does not accept selection options");
|
|
892
908
|
const name = validateAgentName(options.name ?? "");
|
|
893
909
|
const model = exactModel(options);
|
|
894
910
|
if (!model)
|
|
@@ -898,17 +914,25 @@ async function run(arguments_) {
|
|
|
898
914
|
}
|
|
899
915
|
if (domain === "agent" && operation === "reconcile") {
|
|
900
916
|
const options = parseOptions(rest);
|
|
901
|
-
if (options.name ||
|
|
902
|
-
|
|
917
|
+
if (options.name ||
|
|
918
|
+
options.provider ||
|
|
919
|
+
options.model ||
|
|
920
|
+
options.variant !== undefined ||
|
|
921
|
+
options.selectionFlag)
|
|
922
|
+
throw new InstallerError("invalid_input", "agent reconcile accepts only --global, --dry-run, --confirm, and --json");
|
|
903
923
|
await runProfile({ action: "reconcile" }, options);
|
|
904
924
|
return;
|
|
905
925
|
}
|
|
906
926
|
if (domain === "critic" && (operation === "add" || operation === "remove")) {
|
|
907
927
|
const options = parseOptions(rest);
|
|
928
|
+
if (options.selectionFlag)
|
|
929
|
+
throw new InstallerError("invalid_input", `critic ${operation} does not accept selection options`);
|
|
908
930
|
const name = options.name === "critic" || options.name?.startsWith("critic-")
|
|
909
931
|
? options.name
|
|
910
932
|
: `critic-${options.name ?? ""}`;
|
|
911
933
|
if (operation === "add") {
|
|
934
|
+
if (options.variant === null)
|
|
935
|
+
throw new InstallerError("invalid_input", "critic add does not accept --clear-variant");
|
|
912
936
|
const model = exactModel(options);
|
|
913
937
|
if (!model) {
|
|
914
938
|
const selected = await interactiveSelection(options, "critic-add");
|
|
@@ -924,13 +948,16 @@ async function run(arguments_) {
|
|
|
924
948
|
}
|
|
925
949
|
}
|
|
926
950
|
else {
|
|
927
|
-
if (options.provider ||
|
|
951
|
+
if (options.provider ||
|
|
952
|
+
options.model ||
|
|
953
|
+
options.variant !== undefined ||
|
|
954
|
+
options.selectionFlag)
|
|
928
955
|
throw new InstallerError("invalid_input", "critic remove does not accept model options");
|
|
929
956
|
await runProfile({ action: "critic-remove", name }, options);
|
|
930
957
|
}
|
|
931
958
|
return;
|
|
932
959
|
}
|
|
933
|
-
throw new InstallerError("invalid_input", "Use install, uninstall, agent list|configure|model-set|reconcile, or critic add|remove");
|
|
960
|
+
throw new InstallerError("invalid_input", "Use install, uninstall, doctor, capabilities, reconcile, agent list|configure|model-set|reconcile, or critic add|remove");
|
|
934
961
|
}
|
|
935
962
|
async function main() {
|
|
936
963
|
try {
|