@open-agent-toolkit/cli 0.1.33 → 0.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/assets/docs/cli-utilities/config-and-local-state.md +20 -0
  2. package/assets/docs/cli-utilities/configuration.md +17 -6
  3. package/assets/docs/cli-utilities/index.md +5 -0
  4. package/assets/docs/cli-utilities/tool-packs.md +1 -1
  5. package/assets/docs/cli-utilities/workflow-gates.md +163 -0
  6. package/assets/docs/contributing/design-principles.md +1 -1
  7. package/assets/docs/contributing/skills.md +25 -0
  8. package/assets/docs/reference/cli-reference.md +3 -0
  9. package/assets/docs/reference/file-locations.md +1 -0
  10. package/assets/docs/reference/oat-directory-structure.md +3 -0
  11. package/assets/public-package-versions.json +4 -4
  12. package/assets/skills/oat-project-implement/SKILL.md +23 -1
  13. package/assets/skills/oat-project-plan/SKILL.md +23 -1
  14. package/dist/app/create-program.d.ts.map +1 -1
  15. package/dist/app/create-program.js +3 -6
  16. package/dist/app/help-config.d.ts +12 -0
  17. package/dist/app/help-config.d.ts.map +1 -0
  18. package/dist/app/help-config.js +15 -0
  19. package/dist/commands/doctor/index.d.ts.map +1 -1
  20. package/dist/commands/doctor/index.js +2 -1
  21. package/dist/commands/gate/index.d.ts +35 -0
  22. package/dist/commands/gate/index.d.ts.map +1 -0
  23. package/dist/commands/gate/index.js +500 -0
  24. package/dist/commands/index.d.ts.map +1 -1
  25. package/dist/commands/index.js +6 -0
  26. package/dist/commands/init/index.d.ts.map +1 -1
  27. package/dist/commands/init/index.js +2 -1
  28. package/dist/commands/init/tools/brainstorm/index.d.ts.map +1 -1
  29. package/dist/commands/init/tools/brainstorm/index.js +2 -1
  30. package/dist/commands/init/tools/core/index.d.ts.map +1 -1
  31. package/dist/commands/init/tools/core/index.js +18 -0
  32. package/dist/commands/init/tools/docs/index.d.ts.map +1 -1
  33. package/dist/commands/init/tools/docs/index.js +2 -1
  34. package/dist/commands/init/tools/ideas/index.d.ts.map +1 -1
  35. package/dist/commands/init/tools/ideas/index.js +2 -1
  36. package/dist/commands/init/tools/project-management/index.d.ts.map +1 -1
  37. package/dist/commands/init/tools/project-management/index.js +19 -0
  38. package/dist/commands/init/tools/research/index.d.ts.map +1 -1
  39. package/dist/commands/init/tools/research/index.js +2 -1
  40. package/dist/commands/init/tools/utility/index.d.ts.map +1 -1
  41. package/dist/commands/init/tools/utility/index.js +2 -1
  42. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  43. package/dist/commands/init/tools/workflows/index.js +2 -1
  44. package/dist/commands/internal/validate-oat-skills.d.ts +3 -0
  45. package/dist/commands/internal/validate-oat-skills.d.ts.map +1 -1
  46. package/dist/commands/internal/validate-oat-skills.js +44 -2
  47. package/dist/commands/project/split/evaluate-signals.d.ts.map +1 -1
  48. package/dist/commands/project/split/evaluate-signals.js +11 -1
  49. package/dist/commands/project/split/run.d.ts.map +1 -1
  50. package/dist/commands/project/split/run.js +14 -0
  51. package/dist/commands/project/split/validate-plan.d.ts.map +1 -1
  52. package/dist/commands/project/split/validate-plan.js +30 -6
  53. package/dist/commands/project/validate-plan/index.d.ts +6 -1
  54. package/dist/commands/project/validate-plan/index.d.ts.map +1 -1
  55. package/dist/commands/project/validate-plan/index.js +36 -9
  56. package/dist/commands/providers/inspect/inspect.d.ts.map +1 -1
  57. package/dist/commands/providers/inspect/inspect.js +2 -1
  58. package/dist/commands/providers/list/list.d.ts.map +1 -1
  59. package/dist/commands/providers/list/list.js +2 -1
  60. package/dist/commands/providers/set/index.d.ts.map +1 -1
  61. package/dist/commands/providers/set/index.js +6 -2
  62. package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
  63. package/dist/commands/remove/skill/remove-skill.js +2 -1
  64. package/dist/commands/remove/skills/remove-skills.d.ts.map +1 -1
  65. package/dist/commands/remove/skills/remove-skills.js +2 -1
  66. package/dist/commands/repo/pr-comments/triage-collection/triage-comments.d.ts +1 -0
  67. package/dist/commands/repo/pr-comments/triage-collection/triage-comments.d.ts.map +1 -1
  68. package/dist/commands/repo/pr-comments/triage-collection/triage-comments.js +25 -13
  69. package/dist/commands/shared/scope-option.d.ts +21 -0
  70. package/dist/commands/shared/scope-option.d.ts.map +1 -0
  71. package/dist/commands/shared/scope-option.js +24 -0
  72. package/dist/commands/status/index.d.ts.map +1 -1
  73. package/dist/commands/status/index.js +2 -1
  74. package/dist/commands/sync/index.d.ts.map +1 -1
  75. package/dist/commands/sync/index.js +2 -1
  76. package/dist/commands/tools/info/index.d.ts.map +1 -1
  77. package/dist/commands/tools/info/index.js +2 -1
  78. package/dist/commands/tools/install/index.d.ts.map +1 -1
  79. package/dist/commands/tools/install/index.js +2 -0
  80. package/dist/commands/tools/list/index.d.ts.map +1 -1
  81. package/dist/commands/tools/list/index.js +2 -1
  82. package/dist/commands/tools/outdated/index.d.ts.map +1 -1
  83. package/dist/commands/tools/outdated/index.js +2 -1
  84. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  85. package/dist/commands/tools/remove/index.js +2 -1
  86. package/dist/commands/tools/update/index.d.ts.map +1 -1
  87. package/dist/commands/tools/update/index.js +6 -2
  88. package/dist/config/oat-config.d.ts +22 -0
  89. package/dist/config/oat-config.d.ts.map +1 -1
  90. package/dist/config/oat-config.js +136 -0
  91. package/dist/config/resolve.d.ts +3 -1
  92. package/dist/config/resolve.d.ts.map +1 -1
  93. package/dist/config/resolve.js +103 -1
  94. package/dist/validation/skills.d.ts +2 -0
  95. package/dist/validation/skills.d.ts.map +1 -1
  96. package/dist/validation/skills.js +39 -0
  97. package/package.json +2 -2
@@ -0,0 +1,500 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { join } from 'node:path';
3
+ import { buildCommandContext, } from '../../app/command-context.js';
4
+ import { readGlobalOptions } from '../shared/shared.utils.js';
5
+ import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
6
+ import { resolveEffectiveConfig, resolveExecTargets, resolveGate, } from '../../config/resolve.js';
7
+ import { resolveProjectRoot } from '../../fs/paths.js';
8
+ import { Command } from 'commander';
9
+ const DEFAULT_DEPENDENCIES = {
10
+ buildCommandContext,
11
+ resolveProjectRoot,
12
+ readOatConfig,
13
+ writeOatConfig,
14
+ readOatLocalConfig,
15
+ writeOatLocalConfig,
16
+ readUserConfig,
17
+ writeUserConfig,
18
+ resolveEffectiveConfig,
19
+ runProcess: runChildProcess,
20
+ processEnv: process.env,
21
+ };
22
+ const VALID_ON_FAILURE = ['block', 'prompt', 'warn'];
23
+ const VALID_WRITE_LAYERS = [
24
+ 'shared',
25
+ 'local',
26
+ 'user',
27
+ ];
28
+ const VALID_CROSS_PROVIDER_AVOIDS = [
29
+ 'same-runtime',
30
+ 'none',
31
+ ];
32
+ async function runChildProcess(command, args, options) {
33
+ return new Promise((resolve, reject) => {
34
+ const child = spawn(command, args, {
35
+ cwd: options.cwd,
36
+ env: options.env,
37
+ stdio: options.stdio,
38
+ });
39
+ child.on('error', reject);
40
+ child.on('close', (code) => {
41
+ resolve({ exitCode: code ?? 1 });
42
+ });
43
+ });
44
+ }
45
+ function isGateWriteLayer(value) {
46
+ return VALID_WRITE_LAYERS.includes(value);
47
+ }
48
+ function writeError(context, error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ if (context.json) {
51
+ context.logger.json({ status: 'error', message });
52
+ }
53
+ else {
54
+ context.logger.error(message);
55
+ }
56
+ process.exitCode = 1;
57
+ }
58
+ function writeJsonValue(context, payload) {
59
+ if (context.json) {
60
+ context.logger.json(payload);
61
+ return;
62
+ }
63
+ context.logger.info(JSON.stringify(payload, null, 2));
64
+ }
65
+ function writeSuccess(context, payload) {
66
+ if (context.json) {
67
+ context.logger.json({ status: 'ok', ...payload });
68
+ return;
69
+ }
70
+ context.logger.info(JSON.stringify({ status: 'ok', ...payload }, null, 2));
71
+ }
72
+ function trimRequired(value, label) {
73
+ const trimmed = value.trim();
74
+ if (!trimmed) {
75
+ throw new Error(`${label} must be a non-empty string.`);
76
+ }
77
+ return trimmed;
78
+ }
79
+ function parseLayer(value) {
80
+ const layer = value?.trim() || 'user';
81
+ if (!isGateWriteLayer(layer)) {
82
+ throw new Error('--layer must be one of shared | local | user; auto is not supported for gate writes.');
83
+ }
84
+ return layer;
85
+ }
86
+ function parseCrossProviderAvoid(value) {
87
+ const avoid = value?.trim() || 'same-runtime';
88
+ if (!VALID_CROSS_PROVIDER_AVOIDS.includes(avoid)) {
89
+ throw new Error('--avoid must be one of same-runtime | none.');
90
+ }
91
+ return avoid;
92
+ }
93
+ function parseOnFailure(value) {
94
+ if (!value || !VALID_ON_FAILURE.includes(value)) {
95
+ throw new Error('--on-failure must be one of block | prompt | warn.');
96
+ }
97
+ return value;
98
+ }
99
+ function parsePositiveInteger(value, flag, defaultValue) {
100
+ if (value === undefined) {
101
+ return defaultValue;
102
+ }
103
+ const parsed = Number(value);
104
+ if (!Number.isInteger(parsed) || parsed < 1) {
105
+ throw new Error(`${flag} must be an integer greater than or equal to 1.`);
106
+ }
107
+ return parsed;
108
+ }
109
+ function parseNumericFlag(value, flag, defaultValue) {
110
+ if (value === undefined) {
111
+ return defaultValue;
112
+ }
113
+ const parsed = Number(value);
114
+ if (!Number.isFinite(parsed)) {
115
+ throw new Error(`${flag} must be a finite number.`);
116
+ }
117
+ return parsed;
118
+ }
119
+ function parseArgvJson(value, flag) {
120
+ let parsed;
121
+ try {
122
+ parsed = JSON.parse(value);
123
+ }
124
+ catch (error) {
125
+ const detail = error instanceof Error ? `: ${error.message}` : '';
126
+ throw new Error(`${flag} must be valid JSON${detail}`, { cause: error });
127
+ }
128
+ if (!Array.isArray(parsed) ||
129
+ parsed.length === 0 ||
130
+ !parsed.every((item) => typeof item === 'string') ||
131
+ !parsed[0]?.trim()) {
132
+ throw new Error(`${flag} must be a non-empty JSON array of strings whose first item is not empty.`);
133
+ }
134
+ return [...parsed];
135
+ }
136
+ function parseOptionalArgvJson(value, flag) {
137
+ return value === undefined ? undefined : parseArgvJson(value, flag);
138
+ }
139
+ function parseGateConfig(options) {
140
+ if (options.disable) {
141
+ return null;
142
+ }
143
+ return {
144
+ command: trimRequired(options.command ?? '', '--command'),
145
+ onFailure: parseOnFailure(options.onFailure),
146
+ maxAttempts: parsePositiveInteger(options.maxAttempts, '--max-attempts', 2),
147
+ ...(options.description?.trim()
148
+ ? { description: options.description.trim() }
149
+ : {}),
150
+ };
151
+ }
152
+ function parseExecTargetConfig(options) {
153
+ if (options.disable) {
154
+ return null;
155
+ }
156
+ const baseCommandJson = options.baseCommandJson;
157
+ if (baseCommandJson === undefined) {
158
+ throw new Error('--base-command-json is required unless --disable is set.');
159
+ }
160
+ return {
161
+ runtime: trimRequired(options.runtime ?? '', '--runtime'),
162
+ baseCommand: parseArgvJson(baseCommandJson, '--base-command-json'),
163
+ priority: parseNumericFlag(options.priority, '--priority', 0),
164
+ ...(options.hostDetectionJson !== undefined
165
+ ? {
166
+ hostDetectionCommand: parseOptionalArgvJson(options.hostDetectionJson, '--host-detection-json'),
167
+ }
168
+ : {}),
169
+ ...(options.availabilityJson !== undefined
170
+ ? {
171
+ availabilityCommand: parseOptionalArgvJson(options.availabilityJson, '--availability-json'),
172
+ }
173
+ : {}),
174
+ };
175
+ }
176
+ function updateWorkflowGates(config, update) {
177
+ return {
178
+ ...config,
179
+ workflow: {
180
+ ...config.workflow,
181
+ gates: update(config.workflow?.gates ?? {}),
182
+ },
183
+ };
184
+ }
185
+ function setSkillGate(config, skillName, gate) {
186
+ return updateWorkflowGates(config, (gates) => ({
187
+ ...gates,
188
+ skills: {
189
+ ...gates.skills,
190
+ [skillName]: gate,
191
+ },
192
+ }));
193
+ }
194
+ function unsetSkillGate(config, skillName) {
195
+ return updateWorkflowGates(config, (gates) => {
196
+ const skills = { ...gates.skills };
197
+ delete skills[skillName];
198
+ return {
199
+ ...gates,
200
+ skills,
201
+ };
202
+ });
203
+ }
204
+ function setExecTarget(config, targetId, target) {
205
+ return updateWorkflowGates(config, (gates) => ({
206
+ ...gates,
207
+ execTargets: {
208
+ ...gates.execTargets,
209
+ [targetId]: target,
210
+ },
211
+ }));
212
+ }
213
+ function unsetExecTarget(config, targetId) {
214
+ return updateWorkflowGates(config, (gates) => {
215
+ const execTargets = { ...gates.execTargets };
216
+ delete execTargets[targetId];
217
+ return {
218
+ ...gates,
219
+ execTargets,
220
+ };
221
+ });
222
+ }
223
+ async function readEffectiveConfig(context, dependencies) {
224
+ const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
225
+ const userConfigDir = join(context.home, '.oat');
226
+ return dependencies.resolveEffectiveConfig(repoRoot, userConfigDir, dependencies.processEnv);
227
+ }
228
+ function sortedExecTargetEntries(registry) {
229
+ return Object.entries(registry)
230
+ .map(([id, target]) => ({ id, target }))
231
+ .sort((left, right) => {
232
+ const priority = right.target.priority - left.target.priority;
233
+ return priority === 0 ? left.id.localeCompare(right.id) : priority;
234
+ });
235
+ }
236
+ function cloneExecTarget(target) {
237
+ return {
238
+ runtime: target.runtime,
239
+ baseCommand: [...target.baseCommand],
240
+ priority: target.priority,
241
+ ...(target.hostDetectionCommand
242
+ ? { hostDetectionCommand: [...target.hostDetectionCommand] }
243
+ : {}),
244
+ ...(target.availabilityCommand
245
+ ? { availabilityCommand: [...target.availabilityCommand] }
246
+ : {}),
247
+ };
248
+ }
249
+ function argvHead(argv) {
250
+ return [argv[0] ?? '', argv.slice(1)];
251
+ }
252
+ function listExecTargetCandidates(registry, currentRuntime, avoid) {
253
+ const shouldAvoidSameRuntime = avoid === 'same-runtime' && currentRuntime !== 'unknown';
254
+ return sortedExecTargetEntries(registry)
255
+ .filter(({ target }) => !shouldAvoidSameRuntime || target.runtime !== currentRuntime)
256
+ .map(({ id, target }) => ({ id, target: cloneExecTarget(target) }));
257
+ }
258
+ export function selectExecTarget(registry, currentRuntime, avoid) {
259
+ return listExecTargetCandidates(registry, currentRuntime, avoid)[0] ?? null;
260
+ }
261
+ async function checkArgv(argv, purpose, context, dependencies) {
262
+ const [command, args] = argvHead(argv);
263
+ if (!command) {
264
+ return false;
265
+ }
266
+ try {
267
+ const result = await dependencies.runProcess(command, args, {
268
+ cwd: context.cwd,
269
+ env: dependencies.processEnv,
270
+ purpose,
271
+ stdio: 'ignore',
272
+ });
273
+ return result.exitCode === 0;
274
+ }
275
+ catch {
276
+ return false;
277
+ }
278
+ }
279
+ async function resolveCurrentRuntime(currentRuntime, context, dependencies) {
280
+ const override = currentRuntime?.trim();
281
+ if (override) {
282
+ return override;
283
+ }
284
+ for (const { target } of sortedExecTargetEntries(BUILTIN_EXEC_TARGETS)) {
285
+ if (target.hostDetectionCommand &&
286
+ (await checkArgv(target.hostDetectionCommand, 'host-detection', context, dependencies))) {
287
+ return target.runtime;
288
+ }
289
+ }
290
+ return 'unknown';
291
+ }
292
+ async function selectAvailableExecTarget(registry, currentRuntime, avoid, context, dependencies) {
293
+ for (const candidate of listExecTargetCandidates(registry, currentRuntime, avoid)) {
294
+ const availabilityCommand = candidate.target.availabilityCommand;
295
+ if (!availabilityCommand ||
296
+ (await checkArgv(availabilityCommand, 'availability', context, dependencies))) {
297
+ return candidate;
298
+ }
299
+ }
300
+ return null;
301
+ }
302
+ async function executeTarget(selected, prompt, context, dependencies) {
303
+ const [command, baseArgs] = argvHead(selected.target.baseCommand);
304
+ if (!command) {
305
+ throw new Error(`Exec target "${selected.id}" has an empty base command.`);
306
+ }
307
+ try {
308
+ const result = await dependencies.runProcess(command, [...baseArgs, ...prompt], {
309
+ cwd: context.cwd,
310
+ env: dependencies.processEnv,
311
+ purpose: 'execute',
312
+ stdio: 'inherit',
313
+ });
314
+ return result.exitCode;
315
+ }
316
+ catch (error) {
317
+ const message = error instanceof Error ? error.message : String(error);
318
+ throw new Error(`Failed to launch exec target "${selected.id}" (${command}): ${message}`, { cause: error });
319
+ }
320
+ }
321
+ function noEligibleTargetMessage(currentRuntime, avoid) {
322
+ return `No eligible gate exec target found for current runtime "${currentRuntime}" with --avoid ${avoid}. Install or configure an alternate runtime, rerun with --avoid none, or pin a target with --target <id>.`;
323
+ }
324
+ async function updateConfigLayer(context, layer, dependencies, mutate) {
325
+ const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
326
+ const userConfigDir = join(context.home, '.oat');
327
+ if (layer === 'shared') {
328
+ const config = await dependencies.readOatConfig(repoRoot);
329
+ await dependencies.writeOatConfig(repoRoot, mutate(config));
330
+ return;
331
+ }
332
+ if (layer === 'local') {
333
+ const config = await dependencies.readOatLocalConfig(repoRoot);
334
+ await dependencies.writeOatLocalConfig(repoRoot, mutate(config));
335
+ return;
336
+ }
337
+ const config = await dependencies.readUserConfig(userConfigDir);
338
+ await dependencies.writeUserConfig(userConfigDir, mutate(config));
339
+ }
340
+ async function runResolve(skillName, context, dependencies) {
341
+ try {
342
+ const effective = await readEffectiveConfig(context, dependencies);
343
+ writeJsonValue(context, resolveGate(effective, skillName));
344
+ process.exitCode = 0;
345
+ }
346
+ catch (error) {
347
+ writeError(context, error);
348
+ }
349
+ }
350
+ async function runGateSet(skillName, options, context, dependencies) {
351
+ try {
352
+ const layer = parseLayer(options.layer);
353
+ const normalizedSkill = trimRequired(skillName, '<skill>');
354
+ const gate = parseGateConfig(options);
355
+ await updateConfigLayer(context, layer, dependencies, (config) => setSkillGate(config, normalizedSkill, gate));
356
+ writeSuccess(context, { layer, skill: normalizedSkill, gate });
357
+ process.exitCode = 0;
358
+ }
359
+ catch (error) {
360
+ writeError(context, error);
361
+ }
362
+ }
363
+ async function runGateUnset(skillName, options, context, dependencies) {
364
+ try {
365
+ const layer = parseLayer(options.layer);
366
+ const normalizedSkill = trimRequired(skillName, '<skill>');
367
+ await updateConfigLayer(context, layer, dependencies, (config) => unsetSkillGate(config, normalizedSkill));
368
+ writeSuccess(context, { layer, skill: normalizedSkill });
369
+ process.exitCode = 0;
370
+ }
371
+ catch (error) {
372
+ writeError(context, error);
373
+ }
374
+ }
375
+ async function runTargetSet(targetId, options, context, dependencies) {
376
+ try {
377
+ const layer = parseLayer(options.layer);
378
+ const normalizedTargetId = trimRequired(targetId, '<id>');
379
+ const target = parseExecTargetConfig(options);
380
+ await updateConfigLayer(context, layer, dependencies, (config) => setExecTarget(config, normalizedTargetId, target));
381
+ writeSuccess(context, { layer, target: normalizedTargetId, value: target });
382
+ process.exitCode = 0;
383
+ }
384
+ catch (error) {
385
+ writeError(context, error);
386
+ }
387
+ }
388
+ async function runTargetUnset(targetId, options, context, dependencies) {
389
+ try {
390
+ const layer = parseLayer(options.layer);
391
+ const normalizedTargetId = trimRequired(targetId, '<id>');
392
+ await updateConfigLayer(context, layer, dependencies, (config) => unsetExecTarget(config, normalizedTargetId));
393
+ writeSuccess(context, { layer, target: normalizedTargetId });
394
+ process.exitCode = 0;
395
+ }
396
+ catch (error) {
397
+ writeError(context, error);
398
+ }
399
+ }
400
+ async function runCrossProviderExec(prompt, options, context, dependencies) {
401
+ try {
402
+ const effective = await readEffectiveConfig(context, dependencies);
403
+ const targets = resolveExecTargets(effective);
404
+ const explicitTarget = options.target?.trim();
405
+ if (explicitTarget) {
406
+ const target = targets[explicitTarget];
407
+ if (!target) {
408
+ throw new Error(`Unknown exec target "${explicitTarget}".`);
409
+ }
410
+ process.exitCode = await executeTarget({ id: explicitTarget, target: cloneExecTarget(target) }, prompt, context, dependencies);
411
+ return;
412
+ }
413
+ const avoid = parseCrossProviderAvoid(options.avoid);
414
+ const currentRuntime = await resolveCurrentRuntime(options.currentRuntime, context, dependencies);
415
+ const selected = await selectAvailableExecTarget(targets, currentRuntime, avoid, context, dependencies);
416
+ if (!selected) {
417
+ throw new Error(noEligibleTargetMessage(currentRuntime, avoid));
418
+ }
419
+ process.exitCode = await executeTarget(selected, prompt, context, dependencies);
420
+ }
421
+ catch (error) {
422
+ writeError(context, error);
423
+ }
424
+ }
425
+ export function createGateCommand(overrides = {}) {
426
+ const dependencies = {
427
+ ...DEFAULT_DEPENDENCIES,
428
+ ...overrides,
429
+ };
430
+ const cmd = new Command('gate').description('Resolve and manage workflow gate configuration');
431
+ cmd
432
+ .command('resolve')
433
+ .description('Print the resolved gate configuration for a skill')
434
+ .argument('<skill>', 'Gate-aware skill name')
435
+ .action(async (skillName, _options, command) => {
436
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
437
+ await runResolve(skillName, context, dependencies);
438
+ });
439
+ cmd
440
+ .command('set')
441
+ .description('Set a skill gate in a concrete config layer')
442
+ .argument('<skill>', 'Gate-aware skill name')
443
+ .option('--command <command>', 'Gate command to run')
444
+ .option('--description <description>', 'Gate purpose and follow-up notes')
445
+ .option('--on-failure <mode>', 'Failure behavior: block, prompt, or warn')
446
+ .option('--max-attempts <count>', 'Maximum block remediation attempts')
447
+ .option('--disable', 'Disable this skill gate in the selected layer')
448
+ .option('--layer <layer>', 'Config layer to write: shared, local, or user')
449
+ .action(async (skillName, options, command) => {
450
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
451
+ await runGateSet(skillName, options, context, dependencies);
452
+ });
453
+ cmd
454
+ .command('unset')
455
+ .description('Remove a skill gate entry from a concrete config layer')
456
+ .argument('<skill>', 'Gate-aware skill name')
457
+ .option('--layer <layer>', 'Config layer to write: shared, local, or user')
458
+ .action(async (skillName, options, command) => {
459
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
460
+ await runGateUnset(skillName, options, context, dependencies);
461
+ });
462
+ cmd
463
+ .command('cross-provider-exec')
464
+ .description('Run a prompt through an alternate configured runtime target')
465
+ .option('--target <id>', 'Run this exact exec target')
466
+ .option('--avoid <mode>', 'Avoidance mode: same-runtime or none')
467
+ .option('--current-runtime <runtime>', 'Override detected runtime for testing or manual routing')
468
+ .argument('<prompt...>', 'Prompt arguments appended to the target command')
469
+ .action(async (prompt, options, command) => {
470
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
471
+ await runCrossProviderExec(prompt, options, context, dependencies);
472
+ });
473
+ const target = new Command('target').description('Manage gate execution targets');
474
+ target
475
+ .command('set')
476
+ .description('Set an exec target in a concrete config layer')
477
+ .argument('<id>', 'Exec target id')
478
+ .option('--runtime <runtime>', 'Logical runtime family')
479
+ .option('--base-command-json <json>', 'JSON argv array for the base command')
480
+ .option('--host-detection-json <json>', 'JSON argv array for host detection')
481
+ .option('--availability-json <json>', 'JSON argv array for availability')
482
+ .option('--priority <number>', 'Target priority, higher wins')
483
+ .option('--disable', 'Disable this exec target in the selected layer')
484
+ .option('--layer <layer>', 'Config layer to write: shared, local, or user')
485
+ .action(async (targetId, options, command) => {
486
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
487
+ await runTargetSet(targetId, options, context, dependencies);
488
+ });
489
+ target
490
+ .command('unset')
491
+ .description('Remove an exec target entry from a concrete config layer')
492
+ .argument('<id>', 'Exec target id')
493
+ .option('--layer <layer>', 'Config layer to write: shared, local, or user')
494
+ .action(async (targetId, options, command) => {
495
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
496
+ await runTargetUnset(targetId, options, context, dependencies);
497
+ });
498
+ cmd.addCommand(target);
499
+ return cmd;
500
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBzC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0BvD"}
@@ -1,9 +1,11 @@
1
+ import { applyHelpConfiguration } from '../app/help-config.js';
1
2
  import { createBacklogCommand } from './backlog/index.js';
2
3
  import { createCleanupCommand } from './cleanup/index.js';
3
4
  import { createConfigCommand } from './config/index.js';
4
5
  import { createDecisionCommand } from './decision/index.js';
5
6
  import { createDocsCommand } from './docs/index.js';
6
7
  import { createDoctorCommand } from './doctor/index.js';
8
+ import { createGateCommand } from './gate/index.js';
7
9
  import { createIndexCommand } from './index-cmd/index.js';
8
10
  import { createInitCommand } from './init/index.js';
9
11
  import { createInstructionsCommand } from './instructions/index.js';
@@ -26,6 +28,7 @@ export function registerCommands(program) {
26
28
  program.addCommand(createStatusCommand());
27
29
  program.addCommand(createSyncCommand());
28
30
  program.addCommand(createConfigCommand());
31
+ program.addCommand(createGateCommand());
29
32
  program.addCommand(createLocalCommand());
30
33
  program.addCommand(createProvidersCommand());
31
34
  program.addCommand(createRemoveCommand());
@@ -41,4 +44,7 @@ export function registerCommands(program) {
41
44
  program.addCommand(createStateCommand());
42
45
  program.addCommand(createToolsCommand());
43
46
  program.addCommand(createInternalCommand());
47
+ // Commander's .addCommand() does not inherit help config from the parent.
48
+ // Apply showGlobalOptions recursively after all commands are registered.
49
+ applyHelpConfiguration(program);
44
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/init/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/init/index.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ import { addLocalPaths } from '../local/manage.js';
8
8
  import { adoptStrayToCanonical, isAdoptionConflictError, } from '../shared/adopt-stray.js';
9
9
  import { detectCodexRoleStrays, regenerateCodexAfterAdoption, } from '../shared/codex-strays.js';
10
10
  import { PROVIDER_CONFIG_REMEDIATION } from '../shared/messages.js';
11
+ import { withScopeOption } from '../shared/scope-option.js';
11
12
  import { confirmAction, inputWithDefault, selectManyWithAbort, selectWithAbort, } from '../shared/shared.prompts.js';
12
13
  import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
13
14
  import { DEFAULT_SYNC_CONFIG, loadSyncConfig, saveSyncConfig, } from '../../config/index.js';
@@ -565,7 +566,7 @@ export function createInitCommand(overrides = {}) {
565
566
  ...createDependencies(),
566
567
  ...overrides,
567
568
  };
568
- return new Command('init')
569
+ return withScopeOption(new Command('init'))
569
570
  .description('Initialize canonical directories, manifest, and tool packs')
570
571
  .option('--hook', 'Install optional pre-commit hook')
571
572
  .option('--no-hook', 'Skip optional pre-commit hook install')
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/brainstorm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAM9B,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,+BAA+B;IACvC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,iBAAiB,EAAE,CACjB,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AA+KD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,GACvD,OAAO,CA2BT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/brainstorm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAM9B,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,+BAA+B;IACvC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,iBAAiB,EAAE,CACjB,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AA+KD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,GACvD,OAAO,CA2BT"}
@@ -1,5 +1,6 @@
1
1
  import { buildCommandContext, } from '../../../../app/command-context.js';
2
2
  import { resolvePackDefaultScope } from '../../../init/tools/shared/skill-manifest.js';
3
+ import { withScopeOption } from '../../../shared/scope-option.js';
3
4
  import { confirmAction, } from '../../../shared/shared.prompts.js';
4
5
  import { readGlobalOptions } from '../../../shared/shared.utils.js';
5
6
  import { canonicalPathsForPack, setInstalledCanonicalPaths, } from '../../../tools/shared/install-sync-context.js';
@@ -132,7 +133,7 @@ export function createInitToolsBrainstormCommand(overrides = {}) {
132
133
  ...DEFAULT_DEPENDENCIES,
133
134
  ...overrides,
134
135
  };
135
- return new Command('brainstorm')
136
+ return withScopeOption(new Command('brainstorm'))
136
137
  .description('Install OAT brainstorm skill (always-on entry point with visual companion)')
137
138
  .option('--force', 'Overwrite existing files where applicable')
138
139
  .action(async (options, command) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,WAAW,EAEX,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,SAAS,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC1E;AAqED,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAkBT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,WAAW,EAEX,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,SAAS,GAAG,MAAM,EACzB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,KACT,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC1E;AAqED,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsCT"}
@@ -65,6 +65,24 @@ export function createInitToolsCoreCommand(overrides = {}) {
65
65
  .option('--force', 'Overwrite existing files where applicable')
66
66
  .action(async (options, command) => {
67
67
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
68
+ // Core always installs at user scope. If the caller explicitly passed a
69
+ // conflicting --scope on an ancestor (init or tools install), reject it
70
+ // rather than silently ignoring it. A matching --scope user, or no
71
+ // explicit --scope, proceeds unchanged.
72
+ if (command.getOptionValueSourceWithGlobals('scope') === 'cli') {
73
+ const opts = command.optsWithGlobals();
74
+ if (opts.scope !== 'user') {
75
+ const msg = 'the core pack always installs at user scope; remove --scope or pass --scope user';
76
+ if (context.json) {
77
+ context.logger.json({ status: 'error', message: msg });
78
+ }
79
+ else {
80
+ context.logger.error(msg);
81
+ }
82
+ process.exitCode = 1;
83
+ return;
84
+ }
85
+ }
68
86
  const didInstall = await runInitToolsCore(context, options, dependencies);
69
87
  if (didInstall) {
70
88
  setInstalledCanonicalPaths(command, canonicalPathsForPack('core'));
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,KAAK,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuID,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAeT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/docs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,gBAAgB,CAAC;AAMxB,KAAK,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuID,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAeT"}
@@ -1,4 +1,5 @@
1
1
  import { buildCommandContext, } from '../../../../app/command-context.js';
2
+ import { withScopeOption } from '../../../shared/scope-option.js';
2
3
  import { confirmAction, selectManyWithAbort, } from '../../../shared/shared.prompts.js';
3
4
  import { readGlobalOptions } from '../../../shared/shared.utils.js';
4
5
  import { canonicalSkillPaths, setInstalledCanonicalPaths, } from '../../../tools/shared/install-sync-context.js';
@@ -102,7 +103,7 @@ export function createInitToolsDocsCommand(overrides = {}) {
102
103
  ...DEFAULT_DEPENDENCIES,
103
104
  ...overrides,
104
105
  };
105
- return new Command('docs')
106
+ return withScopeOption(new Command('docs'))
106
107
  .description('Install OAT docs workflow skills')
107
108
  .option('--force', 'Overwrite existing files where applicable')
108
109
  .action(async (options, command) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/ideas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAMzB,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,0BAA0B;IAClC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuGD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CAsBT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/ideas/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAMzB,KAAK,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAEvC,UAAU,0BAA0B;IAClC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,gBAAgB,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAuGD,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CAsBT"}