@fission-ai/openspec 0.23.0 → 1.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 +111 -382
- package/dist/cli/index.js +120 -6
- package/dist/commands/workflow/index.d.ts +17 -0
- package/dist/commands/workflow/index.js +12 -0
- package/dist/commands/workflow/instructions.d.ts +29 -0
- package/dist/commands/workflow/instructions.js +381 -0
- package/dist/commands/workflow/new-change.d.ts +11 -0
- package/dist/commands/workflow/new-change.js +44 -0
- package/dist/commands/workflow/schemas.d.ts +10 -0
- package/dist/commands/workflow/schemas.js +34 -0
- package/dist/commands/workflow/shared.d.ts +52 -0
- package/dist/commands/workflow/shared.js +111 -0
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.js +58 -0
- package/dist/commands/workflow/templates.d.ts +16 -0
- package/dist/commands/workflow/templates.js +68 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +5 -1
- package/dist/core/artifact-graph/instruction-loader.js +8 -19
- package/dist/core/command-generation/adapters/amazon-q.d.ts +13 -0
- package/dist/core/command-generation/adapters/amazon-q.js +26 -0
- package/dist/core/command-generation/adapters/antigravity.d.ts +13 -0
- package/dist/core/command-generation/adapters/antigravity.js +26 -0
- package/dist/core/command-generation/adapters/auggie.d.ts +13 -0
- package/dist/core/command-generation/adapters/auggie.js +27 -0
- package/dist/core/command-generation/adapters/claude.d.ts +13 -0
- package/dist/core/command-generation/adapters/claude.js +50 -0
- package/dist/core/command-generation/adapters/cline.d.ts +14 -0
- package/dist/core/command-generation/adapters/cline.js +27 -0
- package/dist/core/command-generation/adapters/codebuddy.d.ts +13 -0
- package/dist/core/command-generation/adapters/codebuddy.js +28 -0
- package/dist/core/command-generation/adapters/codex.d.ts +13 -0
- package/dist/core/command-generation/adapters/codex.js +27 -0
- package/dist/core/command-generation/adapters/continue.d.ts +13 -0
- package/dist/core/command-generation/adapters/continue.js +28 -0
- package/dist/core/command-generation/adapters/costrict.d.ts +13 -0
- package/dist/core/command-generation/adapters/costrict.js +27 -0
- package/dist/core/command-generation/adapters/crush.d.ts +13 -0
- package/dist/core/command-generation/adapters/crush.js +30 -0
- package/dist/core/command-generation/adapters/cursor.d.ts +14 -0
- package/dist/core/command-generation/adapters/cursor.js +44 -0
- package/dist/core/command-generation/adapters/factory.d.ts +13 -0
- package/dist/core/command-generation/adapters/factory.js +27 -0
- package/dist/core/command-generation/adapters/gemini.d.ts +13 -0
- package/dist/core/command-generation/adapters/gemini.js +26 -0
- package/dist/core/command-generation/adapters/github-copilot.d.ts +13 -0
- package/dist/core/command-generation/adapters/github-copilot.js +26 -0
- package/dist/core/command-generation/adapters/iflow.d.ts +13 -0
- package/dist/core/command-generation/adapters/iflow.js +29 -0
- package/dist/core/command-generation/adapters/index.d.ts +27 -0
- package/dist/core/command-generation/adapters/index.js +27 -0
- package/dist/core/command-generation/adapters/kilocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/kilocode.js +23 -0
- package/dist/core/command-generation/adapters/opencode.d.ts +13 -0
- package/dist/core/command-generation/adapters/opencode.js +26 -0
- package/dist/core/command-generation/adapters/qoder.d.ts +13 -0
- package/dist/core/command-generation/adapters/qoder.js +30 -0
- package/dist/core/command-generation/adapters/qwen.d.ts +13 -0
- package/dist/core/command-generation/adapters/qwen.js +26 -0
- package/dist/core/command-generation/adapters/roocode.d.ts +14 -0
- package/dist/core/command-generation/adapters/roocode.js +27 -0
- package/dist/core/command-generation/adapters/windsurf.d.ts +14 -0
- package/dist/core/command-generation/adapters/windsurf.js +51 -0
- package/dist/core/command-generation/generator.d.ts +21 -0
- package/dist/core/command-generation/generator.js +27 -0
- package/dist/core/command-generation/index.d.ts +22 -0
- package/dist/core/command-generation/index.js +24 -0
- package/dist/core/command-generation/registry.d.ts +36 -0
- package/dist/core/command-generation/registry.js +88 -0
- package/dist/core/command-generation/types.d.ts +55 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +21 -21
- package/dist/core/init.d.ts +16 -36
- package/dist/core/init.js +323 -534
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +501 -0
- package/dist/core/shared/index.d.ts +8 -0
- package/dist/core/shared/index.js +8 -0
- package/dist/core/shared/skill-generation.d.ts +41 -0
- package/dist/core/shared/skill-generation.js +76 -0
- package/dist/core/shared/tool-detection.d.ts +66 -0
- package/dist/core/shared/tool-detection.js +140 -0
- package/dist/core/templates/index.d.ts +7 -16
- package/dist/core/templates/index.js +8 -36
- package/dist/core/templates/skill-templates.d.ts +13 -0
- package/dist/core/templates/skill-templates.js +627 -21
- package/dist/core/update.d.ts +38 -0
- package/dist/core/update.js +280 -62
- package/dist/prompts/searchable-multi-select.d.ts +27 -0
- package/dist/prompts/searchable-multi-select.js +149 -0
- package/dist/ui/ascii-patterns.d.ts +16 -0
- package/dist/ui/ascii-patterns.js +133 -0
- package/dist/ui/welcome-screen.d.ts +10 -0
- package/dist/ui/welcome-screen.js +146 -0
- package/dist/utils/file-system.d.ts +11 -0
- package/dist/utils/file-system.js +65 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- package/package.json +1 -1
- package/dist/commands/artifact-workflow.d.ts +0 -17
- package/dist/commands/artifact-workflow.js +0 -915
- package/dist/core/configurators/agents.d.ts +0 -8
- package/dist/core/configurators/agents.js +0 -15
- package/dist/core/configurators/base.d.ts +0 -7
- package/dist/core/configurators/base.js +0 -2
- package/dist/core/configurators/claude.d.ts +0 -8
- package/dist/core/configurators/claude.js +0 -15
- package/dist/core/configurators/cline.d.ts +0 -8
- package/dist/core/configurators/cline.js +0 -15
- package/dist/core/configurators/codebuddy.d.ts +0 -8
- package/dist/core/configurators/codebuddy.js +0 -15
- package/dist/core/configurators/costrict.d.ts +0 -8
- package/dist/core/configurators/costrict.js +0 -15
- package/dist/core/configurators/iflow.d.ts +0 -8
- package/dist/core/configurators/iflow.js +0 -15
- package/dist/core/configurators/qoder.d.ts +0 -30
- package/dist/core/configurators/qoder.js +0 -42
- package/dist/core/configurators/qwen.d.ts +0 -24
- package/dist/core/configurators/qwen.js +0 -37
- package/dist/core/configurators/registry.d.ts +0 -9
- package/dist/core/configurators/registry.js +0 -43
- package/dist/core/configurators/slash/amazon-q.d.ts +0 -9
- package/dist/core/configurators/slash/amazon-q.js +0 -46
- package/dist/core/configurators/slash/antigravity.d.ts +0 -9
- package/dist/core/configurators/slash/antigravity.js +0 -23
- package/dist/core/configurators/slash/auggie.d.ts +0 -9
- package/dist/core/configurators/slash/auggie.js +0 -31
- package/dist/core/configurators/slash/base.d.ts +0 -19
- package/dist/core/configurators/slash/base.js +0 -69
- package/dist/core/configurators/slash/claude.d.ts +0 -9
- package/dist/core/configurators/slash/claude.js +0 -37
- package/dist/core/configurators/slash/cline.d.ts +0 -9
- package/dist/core/configurators/slash/cline.js +0 -23
- package/dist/core/configurators/slash/codebuddy.d.ts +0 -9
- package/dist/core/configurators/slash/codebuddy.js +0 -34
- package/dist/core/configurators/slash/codex.d.ts +0 -14
- package/dist/core/configurators/slash/codex.js +0 -109
- package/dist/core/configurators/slash/continue.d.ts +0 -9
- package/dist/core/configurators/slash/continue.js +0 -46
- package/dist/core/configurators/slash/costrict.d.ts +0 -9
- package/dist/core/configurators/slash/costrict.js +0 -31
- package/dist/core/configurators/slash/crush.d.ts +0 -9
- package/dist/core/configurators/slash/crush.js +0 -37
- package/dist/core/configurators/slash/cursor.d.ts +0 -9
- package/dist/core/configurators/slash/cursor.js +0 -37
- package/dist/core/configurators/slash/factory.d.ts +0 -10
- package/dist/core/configurators/slash/factory.js +0 -35
- package/dist/core/configurators/slash/gemini.d.ts +0 -9
- package/dist/core/configurators/slash/gemini.js +0 -22
- package/dist/core/configurators/slash/github-copilot.d.ts +0 -9
- package/dist/core/configurators/slash/github-copilot.js +0 -34
- package/dist/core/configurators/slash/iflow.d.ts +0 -9
- package/dist/core/configurators/slash/iflow.js +0 -37
- package/dist/core/configurators/slash/kilocode.d.ts +0 -9
- package/dist/core/configurators/slash/kilocode.js +0 -17
- package/dist/core/configurators/slash/opencode.d.ts +0 -12
- package/dist/core/configurators/slash/opencode.js +0 -72
- package/dist/core/configurators/slash/qoder.d.ts +0 -35
- package/dist/core/configurators/slash/qoder.js +0 -76
- package/dist/core/configurators/slash/qwen.d.ts +0 -32
- package/dist/core/configurators/slash/qwen.js +0 -49
- package/dist/core/configurators/slash/registry.d.ts +0 -8
- package/dist/core/configurators/slash/registry.js +0 -78
- package/dist/core/configurators/slash/roocode.d.ts +0 -9
- package/dist/core/configurators/slash/roocode.js +0 -23
- package/dist/core/configurators/slash/toml-base.d.ts +0 -10
- package/dist/core/configurators/slash/toml-base.js +0 -53
- package/dist/core/configurators/slash/windsurf.d.ts +0 -9
- package/dist/core/configurators/slash/windsurf.js +0 -23
- package/dist/core/templates/agents-root-stub.d.ts +0 -2
- package/dist/core/templates/agents-root-stub.js +0 -17
- package/dist/core/templates/agents-template.d.ts +0 -2
- package/dist/core/templates/agents-template.js +0 -458
- package/dist/core/templates/claude-template.d.ts +0 -2
- package/dist/core/templates/claude-template.js +0 -2
- package/dist/core/templates/cline-template.d.ts +0 -2
- package/dist/core/templates/cline-template.js +0 -2
- package/dist/core/templates/costrict-template.d.ts +0 -2
- package/dist/core/templates/costrict-template.js +0 -2
- package/dist/core/templates/project-template.d.ts +0 -8
- package/dist/core/templates/project-template.js +0 -32
- package/dist/core/templates/slash-command-templates.d.ts +0 -4
- package/dist/core/templates/slash-command-templates.js +0 -49
package/dist/cli/index.js
CHANGED
|
@@ -15,8 +15,8 @@ import { ShowCommand } from '../commands/show.js';
|
|
|
15
15
|
import { CompletionCommand } from '../commands/completion.js';
|
|
16
16
|
import { FeedbackCommand } from '../commands/feedback.js';
|
|
17
17
|
import { registerConfigCommand } from '../commands/config.js';
|
|
18
|
-
import { registerArtifactWorkflowCommands } from '../commands/artifact-workflow.js';
|
|
19
18
|
import { registerSchemaCommand } from '../commands/schema.js';
|
|
19
|
+
import { statusCommand, instructionsCommand, applyInstructionsCommand, templatesCommand, schemasCommand, newChangeCommand, DEFAULT_SCHEMA, } from '../commands/workflow/index.js';
|
|
20
20
|
import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
|
|
21
21
|
const program = new Command();
|
|
22
22
|
const require = createRequire(import.meta.url);
|
|
@@ -63,12 +63,13 @@ program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
|
63
63
|
program.hook('postAction', async () => {
|
|
64
64
|
await shutdown();
|
|
65
65
|
});
|
|
66
|
-
const availableToolIds = AI_TOOLS.filter((tool) => tool.
|
|
66
|
+
const availableToolIds = AI_TOOLS.filter((tool) => tool.skillsDir).map((tool) => tool.value);
|
|
67
67
|
const toolsOptionDescription = `Configure AI tools non-interactively. Use "all", "none", or a comma-separated list of: ${availableToolIds.join(', ')}`;
|
|
68
68
|
program
|
|
69
69
|
.command('init [path]')
|
|
70
70
|
.description('Initialize OpenSpec in your project')
|
|
71
71
|
.option('--tools <tools>', toolsOptionDescription)
|
|
72
|
+
.option('--force', 'Auto-cleanup legacy files without prompting')
|
|
72
73
|
.action(async (targetPath = '.', options) => {
|
|
73
74
|
try {
|
|
74
75
|
// Validate that the path is a valid directory
|
|
@@ -94,6 +95,7 @@ program
|
|
|
94
95
|
const { InitCommand } = await import('../core/init.js');
|
|
95
96
|
const initCommand = new InitCommand({
|
|
96
97
|
tools: options?.tools,
|
|
98
|
+
force: options?.force,
|
|
97
99
|
});
|
|
98
100
|
await initCommand.execute(targetPath);
|
|
99
101
|
}
|
|
@@ -103,13 +105,36 @@ program
|
|
|
103
105
|
process.exit(1);
|
|
104
106
|
}
|
|
105
107
|
});
|
|
108
|
+
// Hidden alias: 'experimental' -> 'init' for backwards compatibility
|
|
109
|
+
program
|
|
110
|
+
.command('experimental', { hidden: true })
|
|
111
|
+
.description('Alias for init (deprecated)')
|
|
112
|
+
.option('--tool <tool-id>', 'Target AI tool (maps to --tools)')
|
|
113
|
+
.option('--no-interactive', 'Disable interactive prompts')
|
|
114
|
+
.action(async (options) => {
|
|
115
|
+
try {
|
|
116
|
+
console.log('Note: "openspec experimental" is deprecated. Use "openspec init" instead.');
|
|
117
|
+
const { InitCommand } = await import('../core/init.js');
|
|
118
|
+
const initCommand = new InitCommand({
|
|
119
|
+
tools: options?.tool,
|
|
120
|
+
interactive: options?.noInteractive === true ? false : undefined,
|
|
121
|
+
});
|
|
122
|
+
await initCommand.execute('.');
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.log();
|
|
126
|
+
ora().fail(`Error: ${error.message}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
106
130
|
program
|
|
107
131
|
.command('update [path]')
|
|
108
132
|
.description('Update OpenSpec instruction files')
|
|
109
|
-
.
|
|
133
|
+
.option('--force', 'Force update even when tools are up to date')
|
|
134
|
+
.action(async (targetPath = '.', options) => {
|
|
110
135
|
try {
|
|
111
136
|
const resolvedPath = path.resolve(targetPath);
|
|
112
|
-
const updateCommand = new UpdateCommand();
|
|
137
|
+
const updateCommand = new UpdateCommand({ force: options?.force });
|
|
113
138
|
await updateCommand.execute(resolvedPath);
|
|
114
139
|
}
|
|
115
140
|
catch (error) {
|
|
@@ -360,7 +385,96 @@ program
|
|
|
360
385
|
process.exitCode = 1;
|
|
361
386
|
}
|
|
362
387
|
});
|
|
363
|
-
//
|
|
364
|
-
|
|
388
|
+
// ═══════════════════════════════════════════════════════════
|
|
389
|
+
// Workflow Commands (formerly experimental)
|
|
390
|
+
// ═══════════════════════════════════════════════════════════
|
|
391
|
+
// Status command
|
|
392
|
+
program
|
|
393
|
+
.command('status')
|
|
394
|
+
.description('Display artifact completion status for a change')
|
|
395
|
+
.option('--change <id>', 'Change name to show status for')
|
|
396
|
+
.option('--schema <name>', 'Schema override (auto-detected from config.yaml)')
|
|
397
|
+
.option('--json', 'Output as JSON')
|
|
398
|
+
.action(async (options) => {
|
|
399
|
+
try {
|
|
400
|
+
await statusCommand(options);
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
console.log();
|
|
404
|
+
ora().fail(`Error: ${error.message}`);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
// Instructions command
|
|
409
|
+
program
|
|
410
|
+
.command('instructions [artifact]')
|
|
411
|
+
.description('Output enriched instructions for creating an artifact or applying tasks')
|
|
412
|
+
.option('--change <id>', 'Change name')
|
|
413
|
+
.option('--schema <name>', 'Schema override (auto-detected from config.yaml)')
|
|
414
|
+
.option('--json', 'Output as JSON')
|
|
415
|
+
.action(async (artifactId, options) => {
|
|
416
|
+
try {
|
|
417
|
+
// Special case: "apply" is not an artifact, but a command to get apply instructions
|
|
418
|
+
if (artifactId === 'apply') {
|
|
419
|
+
await applyInstructionsCommand(options);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
await instructionsCommand(artifactId, options);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
console.log();
|
|
427
|
+
ora().fail(`Error: ${error.message}`);
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
// Templates command
|
|
432
|
+
program
|
|
433
|
+
.command('templates')
|
|
434
|
+
.description('Show resolved template paths for all artifacts in a schema')
|
|
435
|
+
.option('--schema <name>', `Schema to use (default: ${DEFAULT_SCHEMA})`)
|
|
436
|
+
.option('--json', 'Output as JSON mapping artifact IDs to template paths')
|
|
437
|
+
.action(async (options) => {
|
|
438
|
+
try {
|
|
439
|
+
await templatesCommand(options);
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.log();
|
|
443
|
+
ora().fail(`Error: ${error.message}`);
|
|
444
|
+
process.exit(1);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
// Schemas command
|
|
448
|
+
program
|
|
449
|
+
.command('schemas')
|
|
450
|
+
.description('List available workflow schemas with descriptions')
|
|
451
|
+
.option('--json', 'Output as JSON (for agent use)')
|
|
452
|
+
.action(async (options) => {
|
|
453
|
+
try {
|
|
454
|
+
await schemasCommand(options);
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
console.log();
|
|
458
|
+
ora().fail(`Error: ${error.message}`);
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
// New command group with change subcommand
|
|
463
|
+
const newCmd = program.command('new').description('Create new items');
|
|
464
|
+
newCmd
|
|
465
|
+
.command('change <name>')
|
|
466
|
+
.description('Create a new change directory')
|
|
467
|
+
.option('--description <text>', 'Description to add to README.md')
|
|
468
|
+
.option('--schema <name>', `Workflow schema to use (default: ${DEFAULT_SCHEMA})`)
|
|
469
|
+
.action(async (name, options) => {
|
|
470
|
+
try {
|
|
471
|
+
await newChangeCommand(name, options);
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
console.log();
|
|
475
|
+
ora().fail(`Error: ${error.message}`);
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
365
479
|
program.parse();
|
|
366
480
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for the artifact-driven workflow: status, instructions, templates, schemas, new change.
|
|
5
|
+
*/
|
|
6
|
+
export { statusCommand } from './status.js';
|
|
7
|
+
export type { StatusOptions } from './status.js';
|
|
8
|
+
export { instructionsCommand, applyInstructionsCommand } from './instructions.js';
|
|
9
|
+
export type { InstructionsOptions } from './instructions.js';
|
|
10
|
+
export { templatesCommand } from './templates.js';
|
|
11
|
+
export type { TemplatesOptions } from './templates.js';
|
|
12
|
+
export { schemasCommand } from './schemas.js';
|
|
13
|
+
export type { SchemasOptions } from './schemas.js';
|
|
14
|
+
export { newChangeCommand } from './new-change.js';
|
|
15
|
+
export type { NewChangeOptions } from './new-change.js';
|
|
16
|
+
export { DEFAULT_SCHEMA } from './shared.js';
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Commands for the artifact-driven workflow: status, instructions, templates, schemas, new change.
|
|
5
|
+
*/
|
|
6
|
+
export { statusCommand } from './status.js';
|
|
7
|
+
export { instructionsCommand, applyInstructionsCommand } from './instructions.js';
|
|
8
|
+
export { templatesCommand } from './templates.js';
|
|
9
|
+
export { schemasCommand } from './schemas.js';
|
|
10
|
+
export { newChangeCommand } from './new-change.js';
|
|
11
|
+
export { DEFAULT_SCHEMA } from './shared.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructions Command
|
|
3
|
+
*
|
|
4
|
+
* Generates enriched instructions for creating artifacts or applying tasks.
|
|
5
|
+
* Includes both artifact instructions and apply instructions.
|
|
6
|
+
*/
|
|
7
|
+
import { type ArtifactInstructions } from '../../core/artifact-graph/index.js';
|
|
8
|
+
import { type ApplyInstructions } from './shared.js';
|
|
9
|
+
export interface InstructionsOptions {
|
|
10
|
+
change?: string;
|
|
11
|
+
schema?: string;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ApplyInstructionsOptions {
|
|
15
|
+
change?: string;
|
|
16
|
+
schema?: string;
|
|
17
|
+
json?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function instructionsCommand(artifactId: string | undefined, options: InstructionsOptions): Promise<void>;
|
|
20
|
+
export declare function printInstructionsText(instructions: ArtifactInstructions, isBlocked: boolean): void;
|
|
21
|
+
/**
|
|
22
|
+
* Generates apply instructions for implementing tasks from a change.
|
|
23
|
+
* Schema-aware: reads apply phase configuration from schema to determine
|
|
24
|
+
* required artifacts, tracking file, and instruction.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateApplyInstructions(projectRoot: string, changeName: string, schemaName?: string): Promise<ApplyInstructions>;
|
|
27
|
+
export declare function applyInstructionsCommand(options: ApplyInstructionsOptions): Promise<void>;
|
|
28
|
+
export declare function printApplyInstructionsText(instructions: ApplyInstructions): void;
|
|
29
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instructions Command
|
|
3
|
+
*
|
|
4
|
+
* Generates enriched instructions for creating artifacts or applying tasks.
|
|
5
|
+
* Includes both artifact instructions and apply instructions.
|
|
6
|
+
*/
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { loadChangeContext, generateInstructions, resolveSchema, } from '../../core/artifact-graph/index.js';
|
|
11
|
+
import { validateChangeExists, validateSchemaExists, } from './shared.js';
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
// Artifact Instructions Command
|
|
14
|
+
// -----------------------------------------------------------------------------
|
|
15
|
+
export async function instructionsCommand(artifactId, options) {
|
|
16
|
+
const spinner = ora('Generating instructions...').start();
|
|
17
|
+
try {
|
|
18
|
+
const projectRoot = process.cwd();
|
|
19
|
+
const changeName = await validateChangeExists(options.change, projectRoot);
|
|
20
|
+
// Validate schema if explicitly provided
|
|
21
|
+
if (options.schema) {
|
|
22
|
+
validateSchemaExists(options.schema, projectRoot);
|
|
23
|
+
}
|
|
24
|
+
// loadChangeContext will auto-detect schema from metadata if not provided
|
|
25
|
+
const context = loadChangeContext(projectRoot, changeName, options.schema);
|
|
26
|
+
if (!artifactId) {
|
|
27
|
+
spinner.stop();
|
|
28
|
+
const validIds = context.graph.getAllArtifacts().map((a) => a.id);
|
|
29
|
+
throw new Error(`Missing required argument <artifact>. Valid artifacts:\n ${validIds.join('\n ')}`);
|
|
30
|
+
}
|
|
31
|
+
const artifact = context.graph.getArtifact(artifactId);
|
|
32
|
+
if (!artifact) {
|
|
33
|
+
spinner.stop();
|
|
34
|
+
const validIds = context.graph.getAllArtifacts().map((a) => a.id);
|
|
35
|
+
throw new Error(`Artifact '${artifactId}' not found in schema '${context.schemaName}'. Valid artifacts:\n ${validIds.join('\n ')}`);
|
|
36
|
+
}
|
|
37
|
+
const instructions = generateInstructions(context, artifactId, projectRoot);
|
|
38
|
+
const isBlocked = instructions.dependencies.some((d) => !d.done);
|
|
39
|
+
spinner.stop();
|
|
40
|
+
if (options.json) {
|
|
41
|
+
console.log(JSON.stringify(instructions, null, 2));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
printInstructionsText(instructions, isBlocked);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
spinner.stop();
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function printInstructionsText(instructions, isBlocked) {
|
|
52
|
+
const { artifactId, changeName, schemaName, changeDir, outputPath, description, instruction, context, rules, template, dependencies, unlocks, } = instructions;
|
|
53
|
+
// Opening tag
|
|
54
|
+
console.log(`<artifact id="${artifactId}" change="${changeName}" schema="${schemaName}">`);
|
|
55
|
+
console.log();
|
|
56
|
+
// Warning for blocked artifacts
|
|
57
|
+
if (isBlocked) {
|
|
58
|
+
const missing = dependencies.filter((d) => !d.done).map((d) => d.id);
|
|
59
|
+
console.log('<warning>');
|
|
60
|
+
console.log('This artifact has unmet dependencies. Complete them first or proceed with caution.');
|
|
61
|
+
console.log(`Missing: ${missing.join(', ')}`);
|
|
62
|
+
console.log('</warning>');
|
|
63
|
+
console.log();
|
|
64
|
+
}
|
|
65
|
+
// Task directive
|
|
66
|
+
console.log('<task>');
|
|
67
|
+
console.log(`Create the ${artifactId} artifact for change "${changeName}".`);
|
|
68
|
+
console.log(description);
|
|
69
|
+
console.log('</task>');
|
|
70
|
+
console.log();
|
|
71
|
+
// Project context (AI constraint - do not include in output)
|
|
72
|
+
if (context) {
|
|
73
|
+
console.log('<project_context>');
|
|
74
|
+
console.log('<!-- This is background information for you. Do NOT include this in your output. -->');
|
|
75
|
+
console.log(context);
|
|
76
|
+
console.log('</project_context>');
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
// Rules (AI constraint - do not include in output)
|
|
80
|
+
if (rules && rules.length > 0) {
|
|
81
|
+
console.log('<rules>');
|
|
82
|
+
console.log('<!-- These are constraints for you to follow. Do NOT include this in your output. -->');
|
|
83
|
+
for (const rule of rules) {
|
|
84
|
+
console.log(`- ${rule}`);
|
|
85
|
+
}
|
|
86
|
+
console.log('</rules>');
|
|
87
|
+
console.log();
|
|
88
|
+
}
|
|
89
|
+
// Dependencies (files to read for context)
|
|
90
|
+
if (dependencies.length > 0) {
|
|
91
|
+
console.log('<dependencies>');
|
|
92
|
+
console.log('Read these files for context before creating this artifact:');
|
|
93
|
+
console.log();
|
|
94
|
+
for (const dep of dependencies) {
|
|
95
|
+
const status = dep.done ? 'done' : 'missing';
|
|
96
|
+
const fullPath = path.join(changeDir, dep.path);
|
|
97
|
+
console.log(`<dependency id="${dep.id}" status="${status}">`);
|
|
98
|
+
console.log(` <path>${fullPath}</path>`);
|
|
99
|
+
console.log(` <description>${dep.description}</description>`);
|
|
100
|
+
console.log('</dependency>');
|
|
101
|
+
}
|
|
102
|
+
console.log('</dependencies>');
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
// Output location
|
|
106
|
+
console.log('<output>');
|
|
107
|
+
console.log(`Write to: ${path.join(changeDir, outputPath)}`);
|
|
108
|
+
console.log('</output>');
|
|
109
|
+
console.log();
|
|
110
|
+
// Instruction (guidance)
|
|
111
|
+
if (instruction) {
|
|
112
|
+
console.log('<instruction>');
|
|
113
|
+
console.log(instruction.trim());
|
|
114
|
+
console.log('</instruction>');
|
|
115
|
+
console.log();
|
|
116
|
+
}
|
|
117
|
+
// Template
|
|
118
|
+
console.log('<template>');
|
|
119
|
+
console.log('<!-- Use this as the structure for your output file. Fill in the sections. -->');
|
|
120
|
+
console.log(template.trim());
|
|
121
|
+
console.log('</template>');
|
|
122
|
+
console.log();
|
|
123
|
+
// Success criteria placeholder
|
|
124
|
+
console.log('<success_criteria>');
|
|
125
|
+
console.log('<!-- To be defined in schema validation rules -->');
|
|
126
|
+
console.log('</success_criteria>');
|
|
127
|
+
console.log();
|
|
128
|
+
// Unlocks
|
|
129
|
+
if (unlocks.length > 0) {
|
|
130
|
+
console.log('<unlocks>');
|
|
131
|
+
console.log(`Completing this artifact enables: ${unlocks.join(', ')}`);
|
|
132
|
+
console.log('</unlocks>');
|
|
133
|
+
console.log();
|
|
134
|
+
}
|
|
135
|
+
// Closing tag
|
|
136
|
+
console.log('</artifact>');
|
|
137
|
+
}
|
|
138
|
+
// -----------------------------------------------------------------------------
|
|
139
|
+
// Apply Instructions Command
|
|
140
|
+
// -----------------------------------------------------------------------------
|
|
141
|
+
/**
|
|
142
|
+
* Parses tasks.md content and extracts task items with their completion status.
|
|
143
|
+
*/
|
|
144
|
+
function parseTasksFile(content) {
|
|
145
|
+
const tasks = [];
|
|
146
|
+
const lines = content.split('\n');
|
|
147
|
+
let taskIndex = 0;
|
|
148
|
+
for (const line of lines) {
|
|
149
|
+
// Match checkbox patterns: - [ ] or - [x] or - [X]
|
|
150
|
+
const checkboxMatch = line.match(/^[-*]\s*\[([ xX])\]\s*(.+)\s*$/);
|
|
151
|
+
if (checkboxMatch) {
|
|
152
|
+
taskIndex++;
|
|
153
|
+
const done = checkboxMatch[1].toLowerCase() === 'x';
|
|
154
|
+
const description = checkboxMatch[2].trim();
|
|
155
|
+
tasks.push({
|
|
156
|
+
id: `${taskIndex}`,
|
|
157
|
+
description,
|
|
158
|
+
done,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return tasks;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Checks if an artifact output exists in the change directory.
|
|
166
|
+
* Supports glob patterns (e.g., "specs/*.md") by verifying at least one matching file exists.
|
|
167
|
+
*/
|
|
168
|
+
function artifactOutputExists(changeDir, generates) {
|
|
169
|
+
// Normalize the generates path to use platform-specific separators
|
|
170
|
+
const normalizedGenerates = generates.split('/').join(path.sep);
|
|
171
|
+
const fullPath = path.join(changeDir, normalizedGenerates);
|
|
172
|
+
// If it's a glob pattern (contains ** or *), check for matching files
|
|
173
|
+
if (generates.includes('*')) {
|
|
174
|
+
// Extract the directory part before the glob pattern
|
|
175
|
+
const parts = normalizedGenerates.split(path.sep);
|
|
176
|
+
const dirParts = [];
|
|
177
|
+
let patternPart = '';
|
|
178
|
+
for (const part of parts) {
|
|
179
|
+
if (part.includes('*')) {
|
|
180
|
+
patternPart = part;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
dirParts.push(part);
|
|
184
|
+
}
|
|
185
|
+
const dirPath = path.join(changeDir, ...dirParts);
|
|
186
|
+
// Check if directory exists
|
|
187
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
// Extract expected extension from pattern (e.g., "*.md" -> ".md")
|
|
191
|
+
const extMatch = patternPart.match(/\*(\.[a-zA-Z0-9]+)$/);
|
|
192
|
+
const expectedExt = extMatch ? extMatch[1] : null;
|
|
193
|
+
// Recursively check for matching files
|
|
194
|
+
const hasMatchingFiles = (dir) => {
|
|
195
|
+
try {
|
|
196
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
197
|
+
for (const entry of entries) {
|
|
198
|
+
if (entry.isDirectory()) {
|
|
199
|
+
// For ** patterns, recurse into subdirectories
|
|
200
|
+
if (generates.includes('**') && hasMatchingFiles(path.join(dir, entry.name))) {
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (entry.isFile()) {
|
|
205
|
+
// Check if file matches expected extension (or any file if no extension specified)
|
|
206
|
+
if (!expectedExt || entry.name.endsWith(expectedExt)) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
};
|
|
217
|
+
return hasMatchingFiles(dirPath);
|
|
218
|
+
}
|
|
219
|
+
return fs.existsSync(fullPath);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Generates apply instructions for implementing tasks from a change.
|
|
223
|
+
* Schema-aware: reads apply phase configuration from schema to determine
|
|
224
|
+
* required artifacts, tracking file, and instruction.
|
|
225
|
+
*/
|
|
226
|
+
export async function generateApplyInstructions(projectRoot, changeName, schemaName) {
|
|
227
|
+
// loadChangeContext will auto-detect schema from metadata if not provided
|
|
228
|
+
const context = loadChangeContext(projectRoot, changeName, schemaName);
|
|
229
|
+
const changeDir = path.join(projectRoot, 'openspec', 'changes', changeName);
|
|
230
|
+
// Get the full schema to access the apply phase configuration
|
|
231
|
+
const schema = resolveSchema(context.schemaName, projectRoot);
|
|
232
|
+
const applyConfig = schema.apply;
|
|
233
|
+
// Determine required artifacts and tracking file from schema
|
|
234
|
+
// Fallback: if no apply block, require all artifacts
|
|
235
|
+
const requiredArtifactIds = applyConfig?.requires ?? schema.artifacts.map((a) => a.id);
|
|
236
|
+
const tracksFile = applyConfig?.tracks ?? null;
|
|
237
|
+
const schemaInstruction = applyConfig?.instruction ?? null;
|
|
238
|
+
// Check which required artifacts are missing
|
|
239
|
+
const missingArtifacts = [];
|
|
240
|
+
for (const artifactId of requiredArtifactIds) {
|
|
241
|
+
const artifact = schema.artifacts.find((a) => a.id === artifactId);
|
|
242
|
+
if (artifact && !artifactOutputExists(changeDir, artifact.generates)) {
|
|
243
|
+
missingArtifacts.push(artifactId);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Build context files from all existing artifacts in schema
|
|
247
|
+
const contextFiles = {};
|
|
248
|
+
for (const artifact of schema.artifacts) {
|
|
249
|
+
if (artifactOutputExists(changeDir, artifact.generates)) {
|
|
250
|
+
contextFiles[artifact.id] = path.join(changeDir, artifact.generates);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Parse tasks if tracking file exists
|
|
254
|
+
let tasks = [];
|
|
255
|
+
let tracksFileExists = false;
|
|
256
|
+
if (tracksFile) {
|
|
257
|
+
const tracksPath = path.join(changeDir, tracksFile);
|
|
258
|
+
tracksFileExists = fs.existsSync(tracksPath);
|
|
259
|
+
if (tracksFileExists) {
|
|
260
|
+
const tasksContent = await fs.promises.readFile(tracksPath, 'utf-8');
|
|
261
|
+
tasks = parseTasksFile(tasksContent);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Calculate progress
|
|
265
|
+
const total = tasks.length;
|
|
266
|
+
const complete = tasks.filter((t) => t.done).length;
|
|
267
|
+
const remaining = total - complete;
|
|
268
|
+
// Determine state and instruction
|
|
269
|
+
let state;
|
|
270
|
+
let instruction;
|
|
271
|
+
if (missingArtifacts.length > 0) {
|
|
272
|
+
state = 'blocked';
|
|
273
|
+
instruction = `Cannot apply this change yet. Missing artifacts: ${missingArtifacts.join(', ')}.\nUse the openspec-continue-change skill to create the missing artifacts first.`;
|
|
274
|
+
}
|
|
275
|
+
else if (tracksFile && !tracksFileExists) {
|
|
276
|
+
// Tracking file configured but doesn't exist yet
|
|
277
|
+
const tracksFilename = path.basename(tracksFile);
|
|
278
|
+
state = 'blocked';
|
|
279
|
+
instruction = `The ${tracksFilename} file is missing and must be created.\nUse openspec-continue-change to generate the tracking file.`;
|
|
280
|
+
}
|
|
281
|
+
else if (tracksFile && tracksFileExists && total === 0) {
|
|
282
|
+
// Tracking file exists but contains no tasks
|
|
283
|
+
const tracksFilename = path.basename(tracksFile);
|
|
284
|
+
state = 'blocked';
|
|
285
|
+
instruction = `The ${tracksFilename} file exists but contains no tasks.\nAdd tasks to ${tracksFilename} or regenerate it with openspec-continue-change.`;
|
|
286
|
+
}
|
|
287
|
+
else if (tracksFile && remaining === 0 && total > 0) {
|
|
288
|
+
state = 'all_done';
|
|
289
|
+
instruction = 'All tasks are complete! This change is ready to be archived.\nConsider running tests and reviewing the changes before archiving.';
|
|
290
|
+
}
|
|
291
|
+
else if (!tracksFile) {
|
|
292
|
+
// No tracking file (e.g., TDD schema) - ready to apply
|
|
293
|
+
state = 'ready';
|
|
294
|
+
instruction = schemaInstruction?.trim() ?? 'All required artifacts complete. Proceed with implementation.';
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
state = 'ready';
|
|
298
|
+
instruction = schemaInstruction?.trim() ?? 'Read context files, work through pending tasks, mark complete as you go.\nPause if you hit blockers or need clarification.';
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
changeName,
|
|
302
|
+
changeDir,
|
|
303
|
+
schemaName: context.schemaName,
|
|
304
|
+
contextFiles,
|
|
305
|
+
progress: { total, complete, remaining },
|
|
306
|
+
tasks,
|
|
307
|
+
state,
|
|
308
|
+
missingArtifacts: missingArtifacts.length > 0 ? missingArtifacts : undefined,
|
|
309
|
+
instruction,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
export async function applyInstructionsCommand(options) {
|
|
313
|
+
const spinner = ora('Generating apply instructions...').start();
|
|
314
|
+
try {
|
|
315
|
+
const projectRoot = process.cwd();
|
|
316
|
+
const changeName = await validateChangeExists(options.change, projectRoot);
|
|
317
|
+
// Validate schema if explicitly provided
|
|
318
|
+
if (options.schema) {
|
|
319
|
+
validateSchemaExists(options.schema, projectRoot);
|
|
320
|
+
}
|
|
321
|
+
// generateApplyInstructions uses loadChangeContext which auto-detects schema
|
|
322
|
+
const instructions = await generateApplyInstructions(projectRoot, changeName, options.schema);
|
|
323
|
+
spinner.stop();
|
|
324
|
+
if (options.json) {
|
|
325
|
+
console.log(JSON.stringify(instructions, null, 2));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
printApplyInstructionsText(instructions);
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
spinner.stop();
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
export function printApplyInstructionsText(instructions) {
|
|
336
|
+
const { changeName, schemaName, contextFiles, progress, tasks, state, missingArtifacts, instruction } = instructions;
|
|
337
|
+
console.log(`## Apply: ${changeName}`);
|
|
338
|
+
console.log(`Schema: ${schemaName}`);
|
|
339
|
+
console.log();
|
|
340
|
+
// Warning for blocked state
|
|
341
|
+
if (state === 'blocked' && missingArtifacts) {
|
|
342
|
+
console.log('### ⚠️ Blocked');
|
|
343
|
+
console.log();
|
|
344
|
+
console.log(`Missing artifacts: ${missingArtifacts.join(', ')}`);
|
|
345
|
+
console.log('Use the openspec-continue-change skill to create these first.');
|
|
346
|
+
console.log();
|
|
347
|
+
}
|
|
348
|
+
// Context files (dynamically from schema)
|
|
349
|
+
const contextFileEntries = Object.entries(contextFiles);
|
|
350
|
+
if (contextFileEntries.length > 0) {
|
|
351
|
+
console.log('### Context Files');
|
|
352
|
+
for (const [artifactId, filePath] of contextFileEntries) {
|
|
353
|
+
console.log(`- ${artifactId}: ${filePath}`);
|
|
354
|
+
}
|
|
355
|
+
console.log();
|
|
356
|
+
}
|
|
357
|
+
// Progress (only show if we have tracking)
|
|
358
|
+
if (progress.total > 0 || tasks.length > 0) {
|
|
359
|
+
console.log('### Progress');
|
|
360
|
+
if (state === 'all_done') {
|
|
361
|
+
console.log(`${progress.complete}/${progress.total} complete ✓`);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
console.log(`${progress.complete}/${progress.total} complete`);
|
|
365
|
+
}
|
|
366
|
+
console.log();
|
|
367
|
+
}
|
|
368
|
+
// Tasks
|
|
369
|
+
if (tasks.length > 0) {
|
|
370
|
+
console.log('### Tasks');
|
|
371
|
+
for (const task of tasks) {
|
|
372
|
+
const checkbox = task.done ? '[x]' : '[ ]';
|
|
373
|
+
console.log(`- ${checkbox} ${task.description}`);
|
|
374
|
+
}
|
|
375
|
+
console.log();
|
|
376
|
+
}
|
|
377
|
+
// Instruction
|
|
378
|
+
console.log('### Instruction');
|
|
379
|
+
console.log(instruction);
|
|
380
|
+
}
|
|
381
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New Change Command
|
|
3
|
+
*
|
|
4
|
+
* Creates a new change directory with optional description and schema.
|
|
5
|
+
*/
|
|
6
|
+
export interface NewChangeOptions {
|
|
7
|
+
description?: string;
|
|
8
|
+
schema?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function newChangeCommand(name: string | undefined, options: NewChangeOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=new-change.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New Change Command
|
|
3
|
+
*
|
|
4
|
+
* Creates a new change directory with optional description and schema.
|
|
5
|
+
*/
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { createChange, validateChangeName } from '../../utils/change-utils.js';
|
|
9
|
+
import { validateSchemaExists } from './shared.js';
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
// Command Implementation
|
|
12
|
+
// -----------------------------------------------------------------------------
|
|
13
|
+
export async function newChangeCommand(name, options) {
|
|
14
|
+
if (!name) {
|
|
15
|
+
throw new Error('Missing required argument <name>');
|
|
16
|
+
}
|
|
17
|
+
const validation = validateChangeName(name);
|
|
18
|
+
if (!validation.valid) {
|
|
19
|
+
throw new Error(validation.error);
|
|
20
|
+
}
|
|
21
|
+
const projectRoot = process.cwd();
|
|
22
|
+
// Validate schema if provided
|
|
23
|
+
if (options.schema) {
|
|
24
|
+
validateSchemaExists(options.schema, projectRoot);
|
|
25
|
+
}
|
|
26
|
+
const schemaDisplay = options.schema ? ` with schema '${options.schema}'` : '';
|
|
27
|
+
const spinner = ora(`Creating change '${name}'${schemaDisplay}...`).start();
|
|
28
|
+
try {
|
|
29
|
+
const result = await createChange(projectRoot, name, { schema: options.schema });
|
|
30
|
+
// If description provided, create README.md with description
|
|
31
|
+
if (options.description) {
|
|
32
|
+
const { promises: fs } = await import('fs');
|
|
33
|
+
const changeDir = path.join(projectRoot, 'openspec', 'changes', name);
|
|
34
|
+
const readmePath = path.join(changeDir, 'README.md');
|
|
35
|
+
await fs.writeFile(readmePath, `# ${name}\n\n${options.description}\n`, 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
spinner.succeed(`Created change '${name}' at openspec/changes/${name}/ (schema: ${result.schema})`);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
spinner.fail(`Failed to create change '${name}'`);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=new-change.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schemas Command
|
|
3
|
+
*
|
|
4
|
+
* Lists available workflow schemas with descriptions.
|
|
5
|
+
*/
|
|
6
|
+
export interface SchemasOptions {
|
|
7
|
+
json?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function schemasCommand(options: SchemasOptions): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=schemas.d.ts.map
|