@bobby_z/openspec 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +204 -0
- package/bin/openspec.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +482 -0
- package/dist/commands/change.d.ts +35 -0
- package/dist/commands/change.js +277 -0
- package/dist/commands/completion.d.ts +72 -0
- package/dist/commands/completion.js +257 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.js +198 -0
- package/dist/commands/feedback.d.ts +9 -0
- package/dist/commands/feedback.js +183 -0
- package/dist/commands/schema.d.ts +6 -0
- package/dist/commands/schema.js +869 -0
- package/dist/commands/show.d.ts +14 -0
- package/dist/commands/show.js +132 -0
- package/dist/commands/spec.d.ts +15 -0
- package/dist/commands/spec.js +225 -0
- package/dist/commands/validate.d.ts +24 -0
- package/dist/commands/validate.js +294 -0
- 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/archive.d.ts +11 -0
- package/dist/core/archive.js +328 -0
- package/dist/core/artifact-graph/graph.d.ts +56 -0
- package/dist/core/artifact-graph/graph.js +141 -0
- package/dist/core/artifact-graph/index.d.ts +7 -0
- package/dist/core/artifact-graph/index.js +13 -0
- package/dist/core/artifact-graph/instruction-loader.d.ts +143 -0
- package/dist/core/artifact-graph/instruction-loader.js +214 -0
- package/dist/core/artifact-graph/resolver.d.ts +81 -0
- package/dist/core/artifact-graph/resolver.js +257 -0
- package/dist/core/artifact-graph/schema.d.ts +13 -0
- package/dist/core/artifact-graph/schema.js +108 -0
- package/dist/core/artifact-graph/state.d.ts +12 -0
- package/dist/core/artifact-graph/state.js +54 -0
- package/dist/core/artifact-graph/types.d.ts +45 -0
- package/dist/core/artifact-graph/types.js +43 -0
- 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 +16 -0
- package/dist/core/command-generation/adapters/codex.js +39 -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/devagent.d.ts +15 -0
- package/dist/core/command-generation/adapters/devagent.js +28 -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 +28 -0
- package/dist/core/command-generation/adapters/index.js +28 -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 +29 -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 +90 -0
- package/dist/core/command-generation/types.d.ts +56 -0
- package/dist/core/command-generation/types.js +8 -0
- package/dist/core/completions/command-registry.d.ts +7 -0
- package/dist/core/completions/command-registry.js +454 -0
- package/dist/core/completions/completion-provider.d.ts +60 -0
- package/dist/core/completions/completion-provider.js +102 -0
- package/dist/core/completions/factory.d.ts +64 -0
- package/dist/core/completions/factory.js +75 -0
- package/dist/core/completions/generators/bash-generator.d.ts +32 -0
- package/dist/core/completions/generators/bash-generator.js +174 -0
- package/dist/core/completions/generators/fish-generator.d.ts +32 -0
- package/dist/core/completions/generators/fish-generator.js +157 -0
- package/dist/core/completions/generators/powershell-generator.d.ts +33 -0
- package/dist/core/completions/generators/powershell-generator.js +207 -0
- package/dist/core/completions/generators/zsh-generator.d.ts +44 -0
- package/dist/core/completions/generators/zsh-generator.js +250 -0
- package/dist/core/completions/installers/bash-installer.d.ts +87 -0
- package/dist/core/completions/installers/bash-installer.js +318 -0
- package/dist/core/completions/installers/fish-installer.d.ts +43 -0
- package/dist/core/completions/installers/fish-installer.js +143 -0
- package/dist/core/completions/installers/powershell-installer.d.ts +88 -0
- package/dist/core/completions/installers/powershell-installer.js +327 -0
- package/dist/core/completions/installers/zsh-installer.d.ts +125 -0
- package/dist/core/completions/installers/zsh-installer.js +449 -0
- package/dist/core/completions/templates/bash-templates.d.ts +6 -0
- package/dist/core/completions/templates/bash-templates.js +24 -0
- package/dist/core/completions/templates/fish-templates.d.ts +7 -0
- package/dist/core/completions/templates/fish-templates.js +39 -0
- package/dist/core/completions/templates/powershell-templates.d.ts +6 -0
- package/dist/core/completions/templates/powershell-templates.js +25 -0
- package/dist/core/completions/templates/zsh-templates.d.ts +6 -0
- package/dist/core/completions/templates/zsh-templates.js +36 -0
- package/dist/core/completions/types.d.ts +79 -0
- package/dist/core/completions/types.js +2 -0
- package/dist/core/config-prompts.d.ts +9 -0
- package/dist/core/config-prompts.js +34 -0
- package/dist/core/config-schema.d.ts +76 -0
- package/dist/core/config-schema.js +200 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +175 -0
- package/dist/core/converters/json-converter.d.ts +6 -0
- package/dist/core/converters/json-converter.js +51 -0
- package/dist/core/global-config.d.ts +39 -0
- package/dist/core/global-config.js +115 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +3 -0
- package/dist/core/init.d.ts +32 -0
- package/dist/core/init.js +447 -0
- package/dist/core/legacy-cleanup.d.ts +162 -0
- package/dist/core/legacy-cleanup.js +520 -0
- package/dist/core/list.d.ts +9 -0
- package/dist/core/list.js +171 -0
- package/dist/core/parsers/change-parser.d.ts +13 -0
- package/dist/core/parsers/change-parser.js +193 -0
- package/dist/core/parsers/markdown-parser.d.ts +22 -0
- package/dist/core/parsers/markdown-parser.js +187 -0
- package/dist/core/parsers/requirement-blocks.d.ts +37 -0
- package/dist/core/parsers/requirement-blocks.js +201 -0
- package/dist/core/project-config.d.ts +64 -0
- package/dist/core/project-config.js +223 -0
- package/dist/core/schemas/base.schema.d.ts +13 -0
- package/dist/core/schemas/base.schema.js +13 -0
- package/dist/core/schemas/change.schema.d.ts +73 -0
- package/dist/core/schemas/change.schema.js +31 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/spec.schema.d.ts +18 -0
- package/dist/core/schemas/spec.schema.js +15 -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 +42 -0
- package/dist/core/shared/skill-generation.js +80 -0
- package/dist/core/shared/tool-detection.d.ts +66 -0
- package/dist/core/shared/tool-detection.js +140 -0
- package/dist/core/specs-apply.d.ts +73 -0
- package/dist/core/specs-apply.js +384 -0
- package/dist/core/styles/palette.d.ts +7 -0
- package/dist/core/styles/palette.js +8 -0
- package/dist/core/templates/index.d.ts +8 -0
- package/dist/core/templates/index.js +9 -0
- package/dist/core/templates/skill-templates.d.ts +122 -0
- package/dist/core/templates/skill-templates.js +3437 -0
- package/dist/core/update.d.ts +42 -0
- package/dist/core/update.js +311 -0
- package/dist/core/validation/constants.d.ts +34 -0
- package/dist/core/validation/constants.js +40 -0
- package/dist/core/validation/types.d.ts +18 -0
- package/dist/core/validation/types.js +2 -0
- package/dist/core/validation/validator.d.ts +33 -0
- package/dist/core/validation/validator.js +409 -0
- package/dist/core/view.d.ts +8 -0
- package/dist/core/view.js +168 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/prompts/searchable-multi-select.d.ts +27 -0
- package/dist/prompts/searchable-multi-select.js +149 -0
- package/dist/telemetry/config.d.ts +32 -0
- package/dist/telemetry/config.js +68 -0
- package/dist/telemetry/index.d.ts +31 -0
- package/dist/telemetry/index.js +145 -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/change-metadata.d.ts +51 -0
- package/dist/utils/change-metadata.js +147 -0
- package/dist/utils/change-utils.d.ts +62 -0
- package/dist/utils/change-utils.js +121 -0
- package/dist/utils/command-references.d.ts +18 -0
- package/dist/utils/command-references.js +20 -0
- package/dist/utils/file-system.d.ts +36 -0
- package/dist/utils/file-system.js +281 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/interactive.d.ts +18 -0
- package/dist/utils/interactive.js +21 -0
- package/dist/utils/item-discovery.d.ts +4 -0
- package/dist/utils/item-discovery.js +72 -0
- package/dist/utils/match.d.ts +3 -0
- package/dist/utils/match.js +22 -0
- package/dist/utils/shell-detection.d.ts +20 -0
- package/dist/utils/shell-detection.js +41 -0
- package/dist/utils/task-progress.d.ts +8 -0
- package/dist/utils/task-progress.js +36 -0
- package/package.json +83 -0
- package/schemas/spec-driven/schema.yaml +151 -0
- package/schemas/spec-driven/templates/design.md +21 -0
- package/schemas/spec-driven/templates/proposal.md +25 -0
- package/schemas/spec-driven/templates/spec.md +10 -0
- package/schemas/spec-driven/templates/tasks.md +9 -0
- package/scripts/postinstall.js +147 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { promises as fs } from "fs";
|
|
6
|
+
import { AI_TOOLS } from "../core/config.js";
|
|
7
|
+
import { UpdateCommand } from "../core/update.js";
|
|
8
|
+
import { ListCommand } from "../core/list.js";
|
|
9
|
+
import { ArchiveCommand } from "../core/archive.js";
|
|
10
|
+
import { ViewCommand } from "../core/view.js";
|
|
11
|
+
import { registerSpecCommand } from "../commands/spec.js";
|
|
12
|
+
import { ChangeCommand } from "../commands/change.js";
|
|
13
|
+
import { ValidateCommand } from "../commands/validate.js";
|
|
14
|
+
import { ShowCommand } from "../commands/show.js";
|
|
15
|
+
import { CompletionCommand } from "../commands/completion.js";
|
|
16
|
+
import { FeedbackCommand } from "../commands/feedback.js";
|
|
17
|
+
import { registerConfigCommand } from "../commands/config.js";
|
|
18
|
+
import { registerSchemaCommand } from "../commands/schema.js";
|
|
19
|
+
import { statusCommand, instructionsCommand, applyInstructionsCommand, templatesCommand, schemasCommand, newChangeCommand, DEFAULT_SCHEMA, } from "../commands/workflow/index.js";
|
|
20
|
+
import { maybeShowTelemetryNotice, trackCommand, shutdown, } from "../telemetry/index.js";
|
|
21
|
+
const program = new Command();
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const { version } = require("../../package.json");
|
|
24
|
+
/**
|
|
25
|
+
* Get the full command path for nested commands.
|
|
26
|
+
* For example: 'change show' -> 'change:show'
|
|
27
|
+
*/
|
|
28
|
+
function getCommandPath(command) {
|
|
29
|
+
const names = [];
|
|
30
|
+
let current = command;
|
|
31
|
+
while (current) {
|
|
32
|
+
const name = current.name();
|
|
33
|
+
// Skip the root 'openspec' command
|
|
34
|
+
if (name && name !== "openspec") {
|
|
35
|
+
names.unshift(name);
|
|
36
|
+
}
|
|
37
|
+
current = current.parent;
|
|
38
|
+
}
|
|
39
|
+
return names.join(":") || "openspec";
|
|
40
|
+
}
|
|
41
|
+
program
|
|
42
|
+
.name("openspec")
|
|
43
|
+
.description("面向规范驱动的 AI 原生开发系统")
|
|
44
|
+
.version(version);
|
|
45
|
+
// Global options
|
|
46
|
+
program.option("--no-color", "关闭彩色输出");
|
|
47
|
+
// Apply global flags and telemetry before any command runs
|
|
48
|
+
// Note: preAction receives (thisCommand, actionCommand) where:
|
|
49
|
+
// - thisCommand: the command where hook was added (root program)
|
|
50
|
+
// - actionCommand: the command actually being executed (subcommand)
|
|
51
|
+
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
52
|
+
const opts = thisCommand.opts();
|
|
53
|
+
if (opts.color === false) {
|
|
54
|
+
process.env.NO_COLOR = "1";
|
|
55
|
+
}
|
|
56
|
+
// Show first-run telemetry notice (if not seen)
|
|
57
|
+
await maybeShowTelemetryNotice();
|
|
58
|
+
// Track command execution (use actionCommand to get the actual subcommand)
|
|
59
|
+
const commandPath = getCommandPath(actionCommand);
|
|
60
|
+
await trackCommand(commandPath, version);
|
|
61
|
+
});
|
|
62
|
+
// Shutdown telemetry after command completes
|
|
63
|
+
program.hook("postAction", async () => {
|
|
64
|
+
await shutdown();
|
|
65
|
+
});
|
|
66
|
+
const availableToolIds = AI_TOOLS.filter((tool) => tool.skillsDir).map((tool) => tool.value);
|
|
67
|
+
const toolsOptionDescription = `非交互配置 AI 工具。可选 "all"、"none" 或逗号分隔列表:${availableToolIds.join(", ")}`;
|
|
68
|
+
program
|
|
69
|
+
.command("init [path]")
|
|
70
|
+
.description("在项目中初始化 OpenSpec")
|
|
71
|
+
.option("--tools <tools>", toolsOptionDescription)
|
|
72
|
+
.option("--force", "自动清理旧版文件且不提示")
|
|
73
|
+
.action(async (targetPath = ".", options) => {
|
|
74
|
+
try {
|
|
75
|
+
// Validate that the path is a valid directory
|
|
76
|
+
const resolvedPath = path.resolve(targetPath);
|
|
77
|
+
try {
|
|
78
|
+
const stats = await fs.stat(resolvedPath);
|
|
79
|
+
if (!stats.isDirectory()) {
|
|
80
|
+
throw new Error(`路径 "${targetPath}" 不是目录`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error.code === "ENOENT") {
|
|
85
|
+
// Directory doesn't exist, but we can create it
|
|
86
|
+
console.log(`目录 "${targetPath}" 不存在,将自动创建。`);
|
|
87
|
+
}
|
|
88
|
+
else if (error.message &&
|
|
89
|
+
(error.message.includes("不是目录") ||
|
|
90
|
+
error.message.includes("not a directory"))) {
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
throw new Error(`无法访问路径 "${targetPath}": ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const { InitCommand } = await import("../core/init.js");
|
|
98
|
+
const initCommand = new InitCommand({
|
|
99
|
+
tools: options?.tools,
|
|
100
|
+
force: options?.force,
|
|
101
|
+
});
|
|
102
|
+
await initCommand.execute(targetPath);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.log(); // Empty line for spacing
|
|
106
|
+
ora().fail(`Error: ${error.message}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Hidden alias: 'experimental' -> 'init' for backwards compatibility
|
|
111
|
+
program
|
|
112
|
+
.command("experimental", { hidden: true })
|
|
113
|
+
.description("init 的别名(已弃用)")
|
|
114
|
+
.option("--tool <tool-id>", "目标 AI 工具(等同于 --tools)")
|
|
115
|
+
.option("--no-interactive", "关闭交互提示")
|
|
116
|
+
.action(async (options) => {
|
|
117
|
+
try {
|
|
118
|
+
console.log('提示:"openspec experimental" 已弃用,请改用 "openspec init"。');
|
|
119
|
+
const { InitCommand } = await import("../core/init.js");
|
|
120
|
+
const initCommand = new InitCommand({
|
|
121
|
+
tools: options?.tool,
|
|
122
|
+
interactive: options?.noInteractive === true ? false : undefined,
|
|
123
|
+
});
|
|
124
|
+
await initCommand.execute(".");
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.log();
|
|
128
|
+
ora().fail(`Error: ${error.message}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
program
|
|
133
|
+
.command("update [path]")
|
|
134
|
+
.description("更新 OpenSpec 指令文件")
|
|
135
|
+
.option("--force", "即使工具已是最新也强制更新")
|
|
136
|
+
.action(async (targetPath = ".", options) => {
|
|
137
|
+
try {
|
|
138
|
+
const resolvedPath = path.resolve(targetPath);
|
|
139
|
+
const updateCommand = new UpdateCommand({ force: options?.force });
|
|
140
|
+
await updateCommand.execute(resolvedPath);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.log(); // Empty line for spacing
|
|
144
|
+
ora().fail(`Error: ${error.message}`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
program
|
|
149
|
+
.command("list")
|
|
150
|
+
.description("列出项(默认为变更)。使用 --specs 列出规范。")
|
|
151
|
+
.option("--specs", "列出规范而非变更")
|
|
152
|
+
.option("--changes", "明确列出变更(默认)")
|
|
153
|
+
.option("--sort <order>", "排序:recent(默认)或 name", "recent")
|
|
154
|
+
.option("--json", "以 JSON 输出(供程序使用)")
|
|
155
|
+
.action(async (options) => {
|
|
156
|
+
try {
|
|
157
|
+
const listCommand = new ListCommand();
|
|
158
|
+
const mode = options?.specs ? "specs" : "changes";
|
|
159
|
+
const sort = options?.sort === "name" ? "name" : "recent";
|
|
160
|
+
await listCommand.execute(".", mode, { sort, json: options?.json });
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.log(); // Empty line for spacing
|
|
164
|
+
ora().fail(`Error: ${error.message}`);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
program
|
|
169
|
+
.command("view")
|
|
170
|
+
.description("显示规范与变更的交互式总览")
|
|
171
|
+
.action(async () => {
|
|
172
|
+
try {
|
|
173
|
+
const viewCommand = new ViewCommand();
|
|
174
|
+
await viewCommand.execute(".");
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.log(); // Empty line for spacing
|
|
178
|
+
ora().fail(`Error: ${error.message}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
// Change command with subcommands
|
|
183
|
+
const changeCmd = program
|
|
184
|
+
.command("change")
|
|
185
|
+
.description("管理 OpenSpec 变更提案");
|
|
186
|
+
// Deprecation notice for noun-based commands
|
|
187
|
+
changeCmd.hook("preAction", () => {
|
|
188
|
+
console.error('警告:"openspec change ..." 命令已弃用,请使用动词优先命令(如 "openspec list"、"openspec validate --changes")。');
|
|
189
|
+
});
|
|
190
|
+
changeCmd
|
|
191
|
+
.command("show [change-name]")
|
|
192
|
+
.description("以 JSON 或 Markdown 显示变更提案")
|
|
193
|
+
.option("--json", "输出 JSON")
|
|
194
|
+
.option("--deltas-only", "仅显示增量(仅 JSON)")
|
|
195
|
+
.option("--requirements-only", "同 --deltas-only(已弃用)")
|
|
196
|
+
.option("--no-interactive", "关闭交互提示")
|
|
197
|
+
.action(async (changeName, options) => {
|
|
198
|
+
try {
|
|
199
|
+
const changeCommand = new ChangeCommand();
|
|
200
|
+
await changeCommand.show(changeName, options);
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
console.error(`Error: ${error.message}`);
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
changeCmd
|
|
208
|
+
.command("list")
|
|
209
|
+
.description('列出所有进行中变更(已弃用:请用 "openspec list")')
|
|
210
|
+
.option("--json", "输出 JSON")
|
|
211
|
+
.option("--long", "显示 id 与标题及数量")
|
|
212
|
+
.action(async (options) => {
|
|
213
|
+
try {
|
|
214
|
+
console.error('警告:"openspec change list" 已弃用,请使用 "openspec list"。');
|
|
215
|
+
const changeCommand = new ChangeCommand();
|
|
216
|
+
await changeCommand.list(options);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.error(`Error: ${error.message}`);
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
changeCmd
|
|
224
|
+
.command("validate [change-name]")
|
|
225
|
+
.description("校验变更提案")
|
|
226
|
+
.option("--strict", "启用严格校验模式")
|
|
227
|
+
.option("--json", "以 JSON 输出校验报告")
|
|
228
|
+
.option("--no-interactive", "关闭交互提示")
|
|
229
|
+
.action(async (changeName, options) => {
|
|
230
|
+
try {
|
|
231
|
+
const changeCommand = new ChangeCommand();
|
|
232
|
+
await changeCommand.validate(changeName, options);
|
|
233
|
+
if (typeof process.exitCode === "number" && process.exitCode !== 0) {
|
|
234
|
+
process.exit(process.exitCode);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
console.error(`Error: ${error.message}`);
|
|
239
|
+
process.exitCode = 1;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
program
|
|
243
|
+
.command("archive [change-name]")
|
|
244
|
+
.description("归档已完成的变更并更新主规范")
|
|
245
|
+
.option("-y, --yes", "跳过确认提示")
|
|
246
|
+
.option("--skip-specs", "跳过规范更新(适用于基础设施、工具或仅文档类变更)")
|
|
247
|
+
.option("--no-validate", "跳过校验(不推荐,需确认)")
|
|
248
|
+
.action(async (changeName, options) => {
|
|
249
|
+
try {
|
|
250
|
+
const archiveCommand = new ArchiveCommand();
|
|
251
|
+
await archiveCommand.execute(changeName, options);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
console.log(); // Empty line for spacing
|
|
255
|
+
ora().fail(`Error: ${error.message}`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
registerSpecCommand(program);
|
|
260
|
+
registerConfigCommand(program);
|
|
261
|
+
registerSchemaCommand(program);
|
|
262
|
+
// Top-level validate command
|
|
263
|
+
program
|
|
264
|
+
.command("validate [item-name]")
|
|
265
|
+
.description("校验变更与规范")
|
|
266
|
+
.option("--all", "校验所有变更与规范")
|
|
267
|
+
.option("--changes", "校验所有变更")
|
|
268
|
+
.option("--specs", "校验所有规范")
|
|
269
|
+
.option("--type <type>", "名称歧义时指定类型:change|spec")
|
|
270
|
+
.option("--strict", "启用严格校验模式")
|
|
271
|
+
.option("--json", "以 JSON 输出校验结果")
|
|
272
|
+
.option("--concurrency <n>", "最大并发校验数(默认取 OPENSPEC_CONCURRENCY 或 6)")
|
|
273
|
+
.option("--no-interactive", "关闭交互提示")
|
|
274
|
+
.action(async (itemName, options) => {
|
|
275
|
+
try {
|
|
276
|
+
const validateCommand = new ValidateCommand();
|
|
277
|
+
await validateCommand.execute(itemName, options);
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
console.log();
|
|
281
|
+
ora().fail(`Error: ${error.message}`);
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
// Top-level show command
|
|
286
|
+
program
|
|
287
|
+
.command("show [item-name]")
|
|
288
|
+
.description("显示变更或规范")
|
|
289
|
+
.option("--json", "输出 JSON")
|
|
290
|
+
.option("--type <type>", "名称歧义时指定类型:change|spec")
|
|
291
|
+
.option("--no-interactive", "关闭交互提示")
|
|
292
|
+
// change-only flags
|
|
293
|
+
.option("--deltas-only", "仅显示增量(仅 JSON,变更)")
|
|
294
|
+
.option("--requirements-only", "同 --deltas-only(已弃用,变更)")
|
|
295
|
+
// spec-only flags
|
|
296
|
+
.option("--requirements", "仅 JSON:仅显示需求(不含场景)")
|
|
297
|
+
.option("--no-scenarios", "仅 JSON:不含场景内容")
|
|
298
|
+
.option("-r, --requirement <id>", "仅 JSON:按 ID 显示指定需求(从 1 起)")
|
|
299
|
+
// allow unknown options to pass-through to underlying command implementation
|
|
300
|
+
.allowUnknownOption(true)
|
|
301
|
+
.action(async (itemName, options) => {
|
|
302
|
+
try {
|
|
303
|
+
const showCommand = new ShowCommand();
|
|
304
|
+
await showCommand.execute(itemName, options ?? {});
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
console.log();
|
|
308
|
+
ora().fail(`Error: ${error.message}`);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// Feedback command
|
|
313
|
+
program
|
|
314
|
+
.command("feedback <message>")
|
|
315
|
+
.description("提交 OpenSpec 相关反馈")
|
|
316
|
+
.option("--body <text>", "反馈的详细说明")
|
|
317
|
+
.action(async (message, options) => {
|
|
318
|
+
try {
|
|
319
|
+
const feedbackCommand = new FeedbackCommand();
|
|
320
|
+
await feedbackCommand.execute(message, options);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
console.log();
|
|
324
|
+
ora().fail(`Error: ${error.message}`);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
// Completion command with subcommands
|
|
329
|
+
const completionCmd = program
|
|
330
|
+
.command("completion")
|
|
331
|
+
.description("管理 OpenSpec CLI 的 Shell 补全");
|
|
332
|
+
completionCmd
|
|
333
|
+
.command("generate [shell]")
|
|
334
|
+
.description("生成某 Shell 的补全脚本(输出到 stdout)")
|
|
335
|
+
.action(async (shell) => {
|
|
336
|
+
try {
|
|
337
|
+
const completionCommand = new CompletionCommand();
|
|
338
|
+
await completionCommand.generate({ shell });
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
console.log();
|
|
342
|
+
ora().fail(`Error: ${error.message}`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
completionCmd
|
|
347
|
+
.command("install [shell]")
|
|
348
|
+
.description("为某 Shell 安装补全脚本")
|
|
349
|
+
.option("--verbose", "显示详细安装输出")
|
|
350
|
+
.action(async (shell, options) => {
|
|
351
|
+
try {
|
|
352
|
+
const completionCommand = new CompletionCommand();
|
|
353
|
+
await completionCommand.install({ shell, verbose: options?.verbose });
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
console.log();
|
|
357
|
+
ora().fail(`Error: ${error.message}`);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
completionCmd
|
|
362
|
+
.command("uninstall [shell]")
|
|
363
|
+
.description("卸载某 Shell 的补全脚本")
|
|
364
|
+
.option("-y, --yes", "跳过确认提示")
|
|
365
|
+
.action(async (shell, options) => {
|
|
366
|
+
try {
|
|
367
|
+
const completionCommand = new CompletionCommand();
|
|
368
|
+
await completionCommand.uninstall({ shell, yes: options?.yes });
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
console.log();
|
|
372
|
+
ora().fail(`Error: ${error.message}`);
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
// Hidden command for machine-readable completion data
|
|
377
|
+
program
|
|
378
|
+
.command("__complete <type>", { hidden: true })
|
|
379
|
+
.description("以机器可读格式输出补全数据(内部使用)")
|
|
380
|
+
.action(async (type) => {
|
|
381
|
+
try {
|
|
382
|
+
const completionCommand = new CompletionCommand();
|
|
383
|
+
await completionCommand.complete({ type });
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
// Silently fail for graceful shell completion experience
|
|
387
|
+
process.exitCode = 1;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
// ═══════════════════════════════════════════════════════════
|
|
391
|
+
// Workflow Commands (formerly experimental)
|
|
392
|
+
// ═══════════════════════════════════════════════════════════
|
|
393
|
+
// Status command
|
|
394
|
+
program
|
|
395
|
+
.command("status")
|
|
396
|
+
.description("显示某变更的制品完成状态")
|
|
397
|
+
.option("--change <id>", "要查看状态的变更名")
|
|
398
|
+
.option("--schema <name>", "工作流模式覆盖(默认从 config.yaml 检测)")
|
|
399
|
+
.option("--json", "输出 JSON")
|
|
400
|
+
.action(async (options) => {
|
|
401
|
+
try {
|
|
402
|
+
await statusCommand(options);
|
|
403
|
+
}
|
|
404
|
+
catch (error) {
|
|
405
|
+
console.log();
|
|
406
|
+
ora().fail(`Error: ${error.message}`);
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
// Instructions command
|
|
411
|
+
program
|
|
412
|
+
.command("instructions [artifact]")
|
|
413
|
+
.description("输出创建制品或实施任务的增强指引")
|
|
414
|
+
.option("--change <id>", "变更名")
|
|
415
|
+
.option("--schema <name>", "工作流模式覆盖(默认从 config.yaml 检测)")
|
|
416
|
+
.option("--json", "输出 JSON")
|
|
417
|
+
.action(async (artifactId, options) => {
|
|
418
|
+
try {
|
|
419
|
+
// Special case: "apply" is not an artifact, but a command to get apply instructions
|
|
420
|
+
if (artifactId === "apply") {
|
|
421
|
+
await applyInstructionsCommand(options);
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
await instructionsCommand(artifactId, options);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
console.log();
|
|
429
|
+
ora().fail(`Error: ${error.message}`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
// Templates command
|
|
434
|
+
program
|
|
435
|
+
.command("templates")
|
|
436
|
+
.description("显示某工作流模式中所有制品的解析后模板路径")
|
|
437
|
+
.option("--schema <name>", `使用的工作流模式(默认:${DEFAULT_SCHEMA})`)
|
|
438
|
+
.option("--json", "以 JSON 输出制品 ID 到模板路径的映射")
|
|
439
|
+
.action(async (options) => {
|
|
440
|
+
try {
|
|
441
|
+
await templatesCommand(options);
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
console.log();
|
|
445
|
+
ora().fail(`Error: ${error.message}`);
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
// Schemas command
|
|
450
|
+
program
|
|
451
|
+
.command("schemas")
|
|
452
|
+
.description("列出可用工作流模式及说明")
|
|
453
|
+
.option("--json", "输出 JSON(供 Agent 使用)")
|
|
454
|
+
.action(async (options) => {
|
|
455
|
+
try {
|
|
456
|
+
await schemasCommand(options);
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
console.log();
|
|
460
|
+
ora().fail(`Error: ${error.message}`);
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
// New command group with change subcommand
|
|
465
|
+
const newCmd = program.command("new").description("创建新项");
|
|
466
|
+
newCmd
|
|
467
|
+
.command("change <name>")
|
|
468
|
+
.description("创建新的变更目录")
|
|
469
|
+
.option("--description <text>", "写入 README.md 的说明")
|
|
470
|
+
.option("--schema <name>", `使用的工作流模式(默认:${DEFAULT_SCHEMA})`)
|
|
471
|
+
.action(async (name, options) => {
|
|
472
|
+
try {
|
|
473
|
+
await newChangeCommand(name, options);
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
console.log();
|
|
477
|
+
ora().fail(`Error: ${error.message}`);
|
|
478
|
+
process.exit(1);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
program.parse();
|
|
482
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare class ChangeCommand {
|
|
2
|
+
private converter;
|
|
3
|
+
constructor();
|
|
4
|
+
/**
|
|
5
|
+
* Show a change proposal.
|
|
6
|
+
* - Text mode: raw markdown passthrough (no filters)
|
|
7
|
+
* - JSON mode: minimal object with deltas; --deltas-only returns same object with filtered deltas
|
|
8
|
+
* Note: --requirements-only is deprecated alias for --deltas-only
|
|
9
|
+
*/
|
|
10
|
+
show(changeName?: string, options?: {
|
|
11
|
+
json?: boolean;
|
|
12
|
+
requirementsOnly?: boolean;
|
|
13
|
+
deltasOnly?: boolean;
|
|
14
|
+
noInteractive?: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* List active changes.
|
|
18
|
+
* - Text default: IDs only; --long prints minimal details (title, counts)
|
|
19
|
+
* - JSON: array of { id, title, deltaCount, taskStatus }, sorted by id
|
|
20
|
+
*/
|
|
21
|
+
list(options?: {
|
|
22
|
+
json?: boolean;
|
|
23
|
+
long?: boolean;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
validate(changeName?: string, options?: {
|
|
26
|
+
strict?: boolean;
|
|
27
|
+
json?: boolean;
|
|
28
|
+
noInteractive?: boolean;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
private getActiveChanges;
|
|
31
|
+
private extractTitle;
|
|
32
|
+
private countTasks;
|
|
33
|
+
private printNextSteps;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=change.d.ts.map
|