@flyin-ai/alloy 0.1.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.
Files changed (94) hide show
  1. package/README.md +151 -0
  2. package/commands/alloy/apply.md +485 -0
  3. package/commands/alloy/archive.md +170 -0
  4. package/commands/alloy/discard.md +80 -0
  5. package/commands/alloy/finish.md +204 -0
  6. package/commands/alloy/fix.md +149 -0
  7. package/commands/alloy/plan.md +360 -0
  8. package/commands/alloy/start.md +314 -0
  9. package/commands/alloy/status.md +79 -0
  10. package/compat.yaml +10 -0
  11. package/dist/cli/commands/completion.d.ts +1 -0
  12. package/dist/cli/commands/completion.js +155 -0
  13. package/dist/cli/commands/completion.js.map +1 -0
  14. package/dist/cli/commands/doctor.d.ts +7 -0
  15. package/dist/cli/commands/doctor.js +93 -0
  16. package/dist/cli/commands/doctor.js.map +1 -0
  17. package/dist/cli/commands/init.d.ts +6 -0
  18. package/dist/cli/commands/init.js +168 -0
  19. package/dist/cli/commands/init.js.map +1 -0
  20. package/dist/cli/commands/internal/archive.d.ts +1 -0
  21. package/dist/cli/commands/internal/archive.js +91 -0
  22. package/dist/cli/commands/internal/archive.js.map +1 -0
  23. package/dist/cli/commands/internal/guard.d.ts +1 -0
  24. package/dist/cli/commands/internal/guard.js +135 -0
  25. package/dist/cli/commands/internal/guard.js.map +1 -0
  26. package/dist/cli/commands/internal/record.d.ts +1 -0
  27. package/dist/cli/commands/internal/record.js +144 -0
  28. package/dist/cli/commands/internal/record.js.map +1 -0
  29. package/dist/cli/commands/internal/state.d.ts +1 -0
  30. package/dist/cli/commands/internal/state.js +99 -0
  31. package/dist/cli/commands/internal/state.js.map +1 -0
  32. package/dist/cli/commands/status.d.ts +1 -0
  33. package/dist/cli/commands/status.js +112 -0
  34. package/dist/cli/commands/status.js.map +1 -0
  35. package/dist/cli/commands/update.d.ts +1 -0
  36. package/dist/cli/commands/update.js +162 -0
  37. package/dist/cli/commands/update.js.map +1 -0
  38. package/dist/cli/index.d.ts +2 -0
  39. package/dist/cli/index.js +291 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/utils/state.d.ts +6 -0
  42. package/dist/cli/utils/state.js +64 -0
  43. package/dist/cli/utils/state.js.map +1 -0
  44. package/dist/core/agents.d.ts +8 -0
  45. package/dist/core/agents.js +85 -0
  46. package/dist/core/agents.js.map +1 -0
  47. package/dist/core/claude-md.d.ts +4 -0
  48. package/dist/core/claude-md.js +47 -0
  49. package/dist/core/claude-md.js.map +1 -0
  50. package/dist/core/compat.d.ts +2 -0
  51. package/dist/core/compat.js +8 -0
  52. package/dist/core/compat.js.map +1 -0
  53. package/dist/core/detect.d.ts +2 -0
  54. package/dist/core/detect.js +22 -0
  55. package/dist/core/detect.js.map +1 -0
  56. package/dist/core/health.d.ts +22 -0
  57. package/dist/core/health.js +283 -0
  58. package/dist/core/health.js.map +1 -0
  59. package/dist/core/openspec.d.ts +2 -0
  60. package/dist/core/openspec.js +79 -0
  61. package/dist/core/openspec.js.map +1 -0
  62. package/dist/core/skills.d.ts +3 -0
  63. package/dist/core/skills.js +68 -0
  64. package/dist/core/skills.js.map +1 -0
  65. package/dist/core/superpowers.d.ts +1 -0
  66. package/dist/core/superpowers.js +31 -0
  67. package/dist/core/superpowers.js.map +1 -0
  68. package/dist/core/types.d.ts +76 -0
  69. package/dist/core/types.js +2 -0
  70. package/dist/core/types.js.map +1 -0
  71. package/dist/utils/fs.d.ts +1 -0
  72. package/dist/utils/fs.js +7 -0
  73. package/dist/utils/fs.js.map +1 -0
  74. package/dist/utils/prompt.d.ts +10 -0
  75. package/dist/utils/prompt.js +90 -0
  76. package/dist/utils/prompt.js.map +1 -0
  77. package/openspec/schemas/alloy/instructions/design.md +46 -0
  78. package/openspec/schemas/alloy/instructions/draft.md +39 -0
  79. package/openspec/schemas/alloy/instructions/plans.md +59 -0
  80. package/openspec/schemas/alloy/instructions/proposal.md +34 -0
  81. package/openspec/schemas/alloy/instructions/retrospective.md +157 -0
  82. package/openspec/schemas/alloy/instructions/specs.md +53 -0
  83. package/openspec/schemas/alloy/instructions/tasks.md +40 -0
  84. package/openspec/schemas/alloy/instructions/verify.md +90 -0
  85. package/openspec/schemas/alloy/schema.yaml +100 -0
  86. package/openspec/schemas/alloy/templates/design.md +15 -0
  87. package/openspec/schemas/alloy/templates/draft.md +17 -0
  88. package/openspec/schemas/alloy/templates/plans.md +28 -0
  89. package/openspec/schemas/alloy/templates/proposal.md +22 -0
  90. package/openspec/schemas/alloy/templates/retrospective.md +163 -0
  91. package/openspec/schemas/alloy/templates/specs.md +54 -0
  92. package/openspec/schemas/alloy/templates/tasks.md +8 -0
  93. package/openspec/schemas/alloy/templates/verify.md +55 -0
  94. package/package.json +43 -0
@@ -0,0 +1,47 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ export const CLAUDE_MD_MARKER_START = "<!-- ALLOY-WORKFLOW:START -->";
4
+ export const CLAUDE_MD_MARKER_END = "<!-- ALLOY-WORKFLOW:END -->";
5
+ export async function injectClaudeMd(opts) {
6
+ if (!opts.injectClaudeMd)
7
+ return false;
8
+ const claudeMdPath = join(opts.projectPath, "CLAUDE.md");
9
+ const fragment = [
10
+ "",
11
+ CLAUDE_MD_MARKER_START,
12
+ "## Alloy 工作流",
13
+ "",
14
+ "本项目使用 [Alloy](https://github.com/Rushing0711/alloy) 管理开发工作流。",
15
+ "",
16
+ "常用命令:",
17
+ "- `/alloy-start [topic]` - 智能入口",
18
+ "- `/alloy-plan [name]` - 制品规划",
19
+ "- `/alloy-apply [name]` - 执行实现",
20
+ "- `/alloy-archive [name]` - 归档与收尾",
21
+ "- `/alloy-finish [name]` - 独立收尾",
22
+ "- `/alloy-fix` - Bug 修复",
23
+ "- `/alloy-status [name]` - 查看状态",
24
+ "",
25
+ CLAUDE_MD_MARKER_END,
26
+ "",
27
+ ].join("\n");
28
+ let existing = "";
29
+ try {
30
+ existing = await readFile(claudeMdPath, "utf-8");
31
+ }
32
+ catch {
33
+ // CLAUDE.md 不存在
34
+ }
35
+ if (existing.includes(CLAUDE_MD_MARKER_START)) {
36
+ const startIdx = existing.indexOf(CLAUDE_MD_MARKER_START);
37
+ const endIdx = existing.indexOf(CLAUDE_MD_MARKER_END);
38
+ if (endIdx > startIdx) {
39
+ existing =
40
+ existing.slice(0, startIdx) +
41
+ existing.slice(endIdx + CLAUDE_MD_MARKER_END.length);
42
+ }
43
+ }
44
+ await writeFile(claudeMdPath, existing + fragment, "utf-8");
45
+ return true;
46
+ }
47
+ //# sourceMappingURL=claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-md.js","sourceRoot":"","sources":["../../src/core/claude-md.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,CAAC,MAAM,sBAAsB,GAAG,+BAA+B,CAAC;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,6BAA6B,CAAC;AAElE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAmB;IACtD,IAAI,CAAC,IAAI,CAAC,cAAc;QAAE,OAAO,KAAK,CAAC;IAEvC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG;QACf,EAAE;QACF,sBAAsB;QACtB,cAAc;QACd,EAAE;QACF,8DAA8D;QAC9D,EAAE;QACF,OAAO;QACP,iCAAiC;QACjC,+BAA+B;QAC/B,gCAAgC;QAChC,mCAAmC;QACnC,iCAAiC;QACjC,yBAAyB;QACzB,iCAAiC;QACjC,EAAE;QACF,oBAAoB;QACpB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACtD,IAAI,MAAM,GAAG,QAAQ,EAAE,CAAC;YACtB,QAAQ;gBACN,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;oBAC3B,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC,YAAY,EAAE,QAAQ,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { CompatConfig } from "./types.js";
2
+ export declare function loadCompat(packageDir: string): Promise<CompatConfig>;
@@ -0,0 +1,8 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ export async function loadCompat(packageDir) {
5
+ const content = await readFile(join(packageDir, "compat.yaml"), "utf-8");
6
+ return parseYaml(content);
7
+ }
8
+ //# sourceMappingURL=compat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.js","sourceRoot":"","sources":["../../src/core/compat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAG1C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,EAAE,OAAO,CAAC,CAAC;IACzE,OAAO,SAAS,CAAC,OAAO,CAAiB,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { EnvInfo } from "./types.js";
2
+ export declare function detectEnv(): EnvInfo;
@@ -0,0 +1,22 @@
1
+ import { execSync } from "node:child_process";
2
+ export function detectEnv() {
3
+ const nodeVersion = process.version.slice(1);
4
+ let gitInstalled = false;
5
+ try {
6
+ execSync("git --version", { stdio: "pipe" });
7
+ gitInstalled = true;
8
+ }
9
+ catch {
10
+ // git 未安装
11
+ }
12
+ let claudeCodeInstalled = false;
13
+ try {
14
+ execSync("claude --version", { stdio: "pipe" });
15
+ claudeCodeInstalled = true;
16
+ }
17
+ catch {
18
+ // Claude Code CLI 未安装
19
+ }
20
+ return { nodeVersion, gitInstalled, claudeCodeInstalled };
21
+ }
22
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/core/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,UAAU,SAAS;IACvB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7C,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,QAAQ,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7C,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAChC,IAAI,CAAC;QACH,QAAQ,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,mBAAmB,GAAG,IAAI,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { DepCheckResult, HealthCheckResult } from "./types.js";
2
+ /**
3
+ * 检测 OpenSpec CLI 是否安装且版本兼容。
4
+ * 供 doctor 诊断和 init 安装前检测复用。
5
+ */
6
+ export declare function checkOpenSpec(requiredRange: string): DepCheckResult;
7
+ /**
8
+ * 检测 Superpowers 是否安装且版本兼容。
9
+ * 优先检查 Claude Code 插件(~/.claude/plugins/installed_plugins.json),
10
+ * fallback 到 npx skills list。
11
+ * 供 doctor 诊断和 init 安装前检测复用。
12
+ */
13
+ export declare function checkSuperpowers(requiredRange: string): Promise<DepCheckResult>;
14
+ /**
15
+ * 运行 7 项健康检查,统一编排并返回结果数组。
16
+ * 每一项检查独立运行,一项失败不影响其他项。
17
+ *
18
+ * @param packageDir 包安装目录(读取 compat.yaml 和 package.json)
19
+ * @param projectPath 用户项目根路径(检查 change 和 skills 目录)
20
+ * @param scope 技能安装范围:"global" 检查 ~/.claude/skills/,"project"(默认)检查 projectPath/.claude/skills/
21
+ */
22
+ export declare function runHealthCheck(packageDir: string, projectPath: string, scope?: "global" | "project"): Promise<HealthCheckResult[]>;
@@ -0,0 +1,283 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { execSync } from "node:child_process";
5
+ import semver from "semver";
6
+ import { loadCompat } from "./compat.js";
7
+ import { detectEnv } from "./detect.js";
8
+ const EXPECTED_COMMAND_IDS = [
9
+ "start", "plan", "apply", "archive",
10
+ "finish", "fix", "discard", "status",
11
+ ];
12
+ /**
13
+ * 检测 OpenSpec CLI 是否安装且版本兼容。
14
+ * 供 doctor 诊断和 init 安装前检测复用。
15
+ */
16
+ export function checkOpenSpec(requiredRange) {
17
+ try {
18
+ const version = execSync("openspec --version", { stdio: "pipe" })
19
+ .toString()
20
+ .trim();
21
+ return {
22
+ installed: true,
23
+ version,
24
+ compatible: semver.satisfies(version, requiredRange),
25
+ };
26
+ }
27
+ catch {
28
+ return { installed: false, compatible: false };
29
+ }
30
+ }
31
+ /**
32
+ * 检测 Superpowers 是否安装且版本兼容。
33
+ * 优先检查 Claude Code 插件(~/.claude/plugins/installed_plugins.json),
34
+ * fallback 到 npx skills list。
35
+ * 供 doctor 诊断和 init 安装前检测复用。
36
+ */
37
+ export async function checkSuperpowers(requiredRange) {
38
+ // 1. 检查 Claude Code 插件
39
+ try {
40
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
41
+ const pluginsJsonPath = join(home, ".claude", "plugins", "installed_plugins.json");
42
+ const pluginsRaw = await readFile(pluginsJsonPath, "utf-8");
43
+ const plugins = JSON.parse(pluginsRaw);
44
+ const sp = plugins?.plugins?.["superpowers@claude-plugins-official"];
45
+ if (sp && sp.length > 0) {
46
+ return {
47
+ installed: true,
48
+ version: sp[0].version,
49
+ compatible: semver.satisfies(sp[0].version, requiredRange),
50
+ };
51
+ }
52
+ }
53
+ catch {
54
+ // 插件文件不存在或无 superpowers 条目,继续 fallback
55
+ }
56
+ // 2. fallback: npx skills list
57
+ try {
58
+ const output = execSync("npx skills list", { stdio: "pipe" }).toString();
59
+ if (output.includes("brainstorming") && output.includes("using-git-worktrees")) {
60
+ return { installed: true, compatible: true };
61
+ }
62
+ }
63
+ catch {
64
+ // 未安装
65
+ }
66
+ return { installed: false, compatible: false };
67
+ }
68
+ /**
69
+ * 运行 7 项健康检查,统一编排并返回结果数组。
70
+ * 每一项检查独立运行,一项失败不影响其他项。
71
+ *
72
+ * @param packageDir 包安装目录(读取 compat.yaml 和 package.json)
73
+ * @param projectPath 用户项目根路径(检查 change 和 skills 目录)
74
+ * @param scope 技能安装范围:"global" 检查 ~/.claude/skills/,"project"(默认)检查 projectPath/.claude/skills/
75
+ */
76
+ export async function runHealthCheck(packageDir, projectPath, scope) {
77
+ const results = [];
78
+ const config = await loadCompat(packageDir);
79
+ const env = detectEnv();
80
+ // 1. Node.js 版本
81
+ results.push({
82
+ name: "Node.js",
83
+ current: env.nodeVersion,
84
+ required: config.compatible.node,
85
+ status: semver.satisfies(env.nodeVersion, config.compatible.node) ? "pass" : "fail",
86
+ });
87
+ // 2. OpenSpec
88
+ const osCheck = checkOpenSpec(config.compatible.openspec);
89
+ if (osCheck.installed) {
90
+ results.push({
91
+ name: "OpenSpec",
92
+ current: osCheck.version,
93
+ required: config.compatible.openspec,
94
+ status: osCheck.compatible ? "pass" : "warn",
95
+ });
96
+ }
97
+ else {
98
+ results.push({
99
+ name: "OpenSpec",
100
+ current: "未安装",
101
+ required: config.compatible.openspec,
102
+ status: "fail",
103
+ });
104
+ }
105
+ // 3. Superpowers
106
+ const spCheck = await checkSuperpowers(config.compatible.superpowers);
107
+ if (spCheck.installed) {
108
+ const versionInfo = spCheck.version ? ` v${spCheck.version}` : "";
109
+ results.push({
110
+ name: "Superpowers",
111
+ current: `已安装${versionInfo}`,
112
+ required: config.compatible.superpowers,
113
+ status: spCheck.compatible ? "pass" : "warn",
114
+ });
115
+ }
116
+ else {
117
+ results.push({
118
+ name: "Superpowers",
119
+ current: "未安装",
120
+ required: config.compatible.superpowers,
121
+ status: "fail",
122
+ });
123
+ }
124
+ // 4. Alloy 自身版本
125
+ try {
126
+ const pkg = JSON.parse(await readFile(join(packageDir, "package.json"), "utf-8"));
127
+ const version = pkg.version;
128
+ results.push({
129
+ name: "Alloy",
130
+ current: version,
131
+ required: config.compatible.alloy,
132
+ status: semver.satisfies(version, config.compatible.alloy)
133
+ ? "pass"
134
+ : "warn",
135
+ });
136
+ }
137
+ catch {
138
+ results.push({
139
+ name: "Alloy",
140
+ current: "未知",
141
+ required: config.compatible.alloy,
142
+ status: "fail",
143
+ });
144
+ }
145
+ // 5. Schema 版本
146
+ try {
147
+ const changesDir = join(projectPath, "openspec", "changes");
148
+ const schemaStatus = await checkSchemaVersions(changesDir, config.compatible.schema);
149
+ results.push(schemaStatus);
150
+ }
151
+ catch {
152
+ results.push({
153
+ name: "Schema",
154
+ current: "无法检测",
155
+ required: String(config.compatible.schema),
156
+ status: "warn",
157
+ message: "openspec/changes/ 目录不存在或无法读取",
158
+ });
159
+ }
160
+ // 6. Command 文件完整性
161
+ try {
162
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
163
+ const commandsDir = scope === "global"
164
+ ? join(home, ".claude", "commands")
165
+ : join(projectPath, ".claude", "commands");
166
+ let commandsStatus = checkCommandsIntegrity(commandsDir);
167
+ // 如果 .claude/commands/ 不完整,尝试检查 commands/(源码目录)
168
+ if (commandsStatus.status === "fail") {
169
+ const sourceDir = join(projectPath, "commands");
170
+ const sourceStatus = checkCommandsIntegrity(sourceDir);
171
+ if (sourceStatus.status === "pass") {
172
+ commandsStatus = {
173
+ ...sourceStatus,
174
+ current: `${sourceStatus.current}(来源: commands/)`,
175
+ };
176
+ }
177
+ }
178
+ results.push(commandsStatus);
179
+ }
180
+ catch {
181
+ results.push({
182
+ name: "Commands",
183
+ current: "无法检测",
184
+ required: `8 个文件`,
185
+ status: "warn",
186
+ });
187
+ }
188
+ // 7. 环境检测
189
+ const envOk = env.gitInstalled;
190
+ const envDetails = [];
191
+ if (env.gitInstalled)
192
+ envDetails.push("git ✓");
193
+ else
194
+ envDetails.push("git ✗");
195
+ results.push({
196
+ name: "Environment",
197
+ current: envDetails.join(" "),
198
+ required: "git",
199
+ status: envOk ? "pass" : "warn",
200
+ });
201
+ return results;
202
+ }
203
+ /**
204
+ * 检查 openspec/changes/ 下各 change 的 schema_version 是否与兼容版本一致。
205
+ * 内部 helper,不导出。
206
+ */
207
+ async function checkSchemaVersions(changesDir, requiredVersion) {
208
+ try {
209
+ const { readdir } = await import("node:fs/promises");
210
+ const entries = await readdir(changesDir, { withFileTypes: true });
211
+ const mismatches = [];
212
+ const yaml = await import("yaml");
213
+ for (const entry of entries) {
214
+ if (!entry.isDirectory())
215
+ continue;
216
+ try {
217
+ const content = await readFile(join(changesDir, entry.name, ".alloy.yaml"), "utf-8");
218
+ const state = yaml.parse(content);
219
+ if (state.schema_version !== undefined &&
220
+ state.schema_version !== requiredVersion) {
221
+ mismatches.push(`${entry.name}=${state.schema_version}`);
222
+ }
223
+ }
224
+ catch {
225
+ // 跳过无 .alloy.yaml 的目录
226
+ }
227
+ }
228
+ if (mismatches.length === 0) {
229
+ return {
230
+ name: "Schema",
231
+ current: `version ${requiredVersion}`,
232
+ required: String(requiredVersion),
233
+ status: "pass",
234
+ };
235
+ }
236
+ return {
237
+ name: "Schema",
238
+ current: mismatches.join(", "),
239
+ required: String(requiredVersion),
240
+ status: "warn",
241
+ message: `以下 change 的 schema_version 不匹配: ${mismatches.join(", ")}`,
242
+ };
243
+ }
244
+ catch {
245
+ return {
246
+ name: "Schema",
247
+ current: "无 changes",
248
+ required: String(requiredVersion),
249
+ status: "pass",
250
+ message: "没有活跃 change,跳过 schema_version 检查",
251
+ };
252
+ }
253
+ }
254
+ /**
255
+ * 检查 .claude/commands/alloy/ 下 8 个 alloy command 文件是否完整。
256
+ * 内部 helper,不导出。
257
+ */
258
+ function checkCommandsIntegrity(commandsDir) {
259
+ const alloyDir = join(commandsDir, "alloy");
260
+ const missing = [];
261
+ for (const id of EXPECTED_COMMAND_IDS) {
262
+ if (!existsSync(join(alloyDir, `${id}.md`))) {
263
+ missing.push(id);
264
+ }
265
+ }
266
+ const found = EXPECTED_COMMAND_IDS.length - missing.length;
267
+ if (missing.length === 0) {
268
+ return {
269
+ name: "Commands",
270
+ current: `${found}/${EXPECTED_COMMAND_IDS.length} 完整`,
271
+ required: `${EXPECTED_COMMAND_IDS.length} 个文件`,
272
+ status: "pass",
273
+ };
274
+ }
275
+ return {
276
+ name: "Commands",
277
+ current: `${found}/${EXPECTED_COMMAND_IDS.length}(缺失: ${missing.join(", ")})`,
278
+ required: `${EXPECTED_COMMAND_IDS.length} 个文件`,
279
+ status: "fail",
280
+ message: `缺失: ${missing.join(", ")}`,
281
+ };
282
+ }
283
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function installOpenSpecCli(): Promise<"installed" | "skipped" | "failed">;
2
+ export declare function initOpenSpecProject(projectPath: string, scope: "global" | "project"): Promise<"initialized" | "skipped" | "failed">;
@@ -0,0 +1,79 @@
1
+ import { mkdirSync, mkdtempSync, writeFileSync, rmSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { execSync } from "node:child_process";
6
+ import { checkOpenSpec } from "./health.js";
7
+ import { loadCompat } from "./compat.js";
8
+ import { getPackageRoot } from "../utils/fs.js";
9
+ function createCustomProfile() {
10
+ const configHome = mkdtempSync(join(tmpdir(), "alloy-openspec-profile-"));
11
+ const openspecConfigDir = join(configHome, "openspec");
12
+ mkdirSync(openspecConfigDir, { recursive: true });
13
+ const config = {
14
+ featureFlags: {},
15
+ profile: "custom",
16
+ delivery: "commands",
17
+ workflows: [
18
+ "propose", "explore", "new", "continue", "apply", "ff",
19
+ "sync", "archive", "bulk-archive", "verify", "onboard",
20
+ ],
21
+ };
22
+ writeFileSync(join(openspecConfigDir, "config.json"), JSON.stringify(config, null, 2) + "\n", "utf-8");
23
+ return {
24
+ env: { ...process.env, XDG_CONFIG_HOME: configHome },
25
+ cleanup: () => rmSync(configHome, { recursive: true, force: true }),
26
+ };
27
+ }
28
+ export async function installOpenSpecCli() {
29
+ const packageDir = getPackageRoot();
30
+ const config = await loadCompat(packageDir);
31
+ const dep = checkOpenSpec(config.compatible.openspec);
32
+ if (dep.installed && dep.compatible) {
33
+ console.log(` ✓ OpenSpec CLI ${dep.version} 已安装,跳过`);
34
+ return "skipped";
35
+ }
36
+ if (dep.installed && !dep.compatible) {
37
+ console.log(` ⚠ OpenSpec ${dep.version} 不满足要求 ${config.compatible.openspec},重新安装...`);
38
+ }
39
+ try {
40
+ execSync("npm install -g @fission-ai/openspec@1", {
41
+ stdio: "pipe",
42
+ cwd: process.cwd(),
43
+ });
44
+ return "installed";
45
+ }
46
+ catch {
47
+ return "failed";
48
+ }
49
+ }
50
+ export async function initOpenSpecProject(projectPath, scope) {
51
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
52
+ const targetPath = scope === "global" ? home : projectPath;
53
+ const label = scope === "global" ? "全局" : "项目";
54
+ if (scope === "project") {
55
+ const configPath = join(projectPath, "openspec", "config.yaml");
56
+ try {
57
+ await readFile(configPath, "utf-8");
58
+ console.log(` ✓ ${label}已初始化 OpenSpec,跳过`);
59
+ return "skipped";
60
+ }
61
+ catch {
62
+ // 文件不存在,需要初始化
63
+ }
64
+ }
65
+ const profile = createCustomProfile();
66
+ try {
67
+ execSync(`openspec init ${JSON.stringify(targetPath)} --tools claude --profile custom`, { stdio: "pipe", timeout: 120_000, env: profile.env });
68
+ console.log(` ✓ openspec init 完成(${label})`);
69
+ return "initialized";
70
+ }
71
+ catch (error) {
72
+ console.error(` ✗ openspec init 失败: ${error.message}`);
73
+ return "failed";
74
+ }
75
+ finally {
76
+ profile.cleanup();
77
+ }
78
+ }
79
+ //# sourceMappingURL=openspec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openspec.js","sourceRoot":"","sources":["../../src/core/openspec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,SAAS,mBAAmB;IAC1B,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAC1E,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACvD,SAAS,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAElD,MAAM,MAAM,GAAG;QACb,YAAY,EAAE,EAAE;QAChB,OAAO,EAAE,QAAQ;QACjB,QAAQ,EAAE,UAAU;QACpB,SAAS,EAAE;YACT,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI;YACtD,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,SAAS;SACvD;KACF,CAAC;IACF,aAAa,CACX,IAAI,CAAC,iBAAiB,EAAE,aAAa,CAAC,EACtC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,OAAO,CACR,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,UAAU,EAAE;QACpD,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;KACpE,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC;QACzD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CACT,mBAAmB,GAAG,CAAC,OAAO,UAAU,MAAM,CAAC,UAAU,CAAC,QAAQ,UAAU,CAC7E,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,CAAC,uCAAuC,EAAE;YAChD,KAAK,EAAE,MAAM;YACb,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC,CAAC;QACH,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,KAA2B;IAE3B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC;IAChE,MAAM,UAAU,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;IAC3D,MAAM,KAAK,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,kBAAkB,CAAC,CAAC;YAC/C,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,IAAI,CAAC;QACH,QAAQ,CACN,iBAAiB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,kCAAkC,EAC7E,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CACtD,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,GAAG,CAAC,CAAC;QACjD,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA6B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACtE,OAAO,QAAQ,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DeployOptions } from "./types.js";
2
+ export declare function deployCommands(opts: DeployOptions): Promise<string[]>;
3
+ export declare function deploySchema(opts: DeployOptions): Promise<string>;
@@ -0,0 +1,68 @@
1
+ import { mkdir, cp, readFile, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { getPackageRoot } from "../utils/fs.js";
4
+ import { getCommandTargetDir } from "./agents.js";
5
+ export async function deployCommands(opts) {
6
+ const deployed = [];
7
+ const packageRoot = getPackageRoot();
8
+ // 始终从冒号源目录读取(commands/alloy/),横线版从冒号源自动生成
9
+ const colonSourceDir = join(packageRoot, "commands", "alloy");
10
+ const { readdir } = await import("node:fs/promises");
11
+ const entries = await readdir(colonSourceDir, { withFileTypes: true });
12
+ for (const agent of opts.targetAgents) {
13
+ // Codex: project 模式跳过
14
+ if (agent.globalOnly && opts.scope === "project") {
15
+ console.log(` ⚠ Codex commands 仅全局安装有效,跳过`);
16
+ continue;
17
+ }
18
+ const targetDir = getCommandTargetDir(agent, opts.scope, opts.projectPath);
19
+ await mkdir(targetDir, { recursive: true });
20
+ for (const entry of entries) {
21
+ if (!entry.isFile())
22
+ continue;
23
+ const src = join(colonSourceDir, entry.name);
24
+ if (agent.supportsColonCommands) {
25
+ // 冒号版:直接拷贝到 alloy/ 子目录
26
+ const dest = join(targetDir, entry.name);
27
+ await cp(src, dest);
28
+ deployed.push(dest);
29
+ }
30
+ else {
31
+ // 横线版:从冒号源自动生成 — 文件名和 frontmatter 中 : 替换为 -
32
+ const dashFilename = `alloy-${entry.name}`; // start.md → alloy-start.md
33
+ const dest = join(targetDir, dashFilename);
34
+ const content = await readFile(src, "utf-8");
35
+ const convertedContent = content.replace(/name: "Alloy: (.+)"/, 'name: "Alloy-$1"');
36
+ await writeFile(dest, convertedContent, "utf-8");
37
+ deployed.push(dest);
38
+ }
39
+ }
40
+ }
41
+ return deployed;
42
+ }
43
+ export async function deploySchema(opts) {
44
+ const packageRoot = getPackageRoot();
45
+ const schemaSource = join(packageRoot, "openspec", "schemas", "alloy");
46
+ const schemaTarget = join(opts.projectPath, "openspec", "schemas", "alloy");
47
+ const openspecDir = join(opts.projectPath, "openspec");
48
+ await mkdir(join(openspecDir, "specs"), { recursive: true });
49
+ await mkdir(join(openspecDir, "changes"), { recursive: true });
50
+ await mkdir(schemaTarget, { recursive: true });
51
+ if (resolve(schemaSource) !== resolve(schemaTarget)) {
52
+ await cp(schemaSource, schemaTarget, { recursive: true });
53
+ }
54
+ const configPath = join(openspecDir, "config.yaml");
55
+ try {
56
+ let existing = await readFile(configPath, "utf-8");
57
+ if (!existing.includes("schema: alloy")) {
58
+ existing = existing.trimEnd() + "\nschema: alloy\n";
59
+ await writeFile(configPath, existing, "utf-8");
60
+ }
61
+ }
62
+ catch {
63
+ const configContent = "schema: alloy\n";
64
+ await writeFile(configPath, configContent, "utf-8");
65
+ }
66
+ return schemaTarget;
67
+ }
68
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function installSuperpowers(scope: "global" | "project"): Promise<"installed" | "skipped" | "failed">;
@@ -0,0 +1,31 @@
1
+ import { execSync } from "node:child_process";
2
+ import { checkSuperpowers } from "./health.js";
3
+ import { loadCompat } from "./compat.js";
4
+ import { getPackageRoot } from "../utils/fs.js";
5
+ export async function installSuperpowers(scope) {
6
+ const packageDir = getPackageRoot();
7
+ const config = await loadCompat(packageDir);
8
+ const dep = await checkSuperpowers(config.compatible.superpowers);
9
+ if (dep.installed && dep.compatible) {
10
+ const versionInfo = dep.version ? ` v${dep.version}` : "";
11
+ console.log(` ✓ Superpowers${versionInfo} 已安装,跳过`);
12
+ return "skipped";
13
+ }
14
+ if (dep.installed && !dep.compatible) {
15
+ const versionInfo = dep.version ? ` v${dep.version}` : "";
16
+ console.log(` ⚠ Superpowers${versionInfo} 不满足要求 ${config.compatible.superpowers},重新安装...`);
17
+ }
18
+ const scopeFlag = scope === "global" ? "-g" : "";
19
+ const flags = ["-y", scopeFlag, "--agent claude-code"].filter(Boolean).join(" ");
20
+ try {
21
+ execSync(`npx skills add obra/superpowers ${flags}`, {
22
+ stdio: "pipe",
23
+ cwd: process.cwd(),
24
+ });
25
+ return "installed";
26
+ }
27
+ catch {
28
+ return "failed";
29
+ }
30
+ }
31
+ //# sourceMappingURL=superpowers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"superpowers.js","sourceRoot":"","sources":["../../src/core/superpowers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAA2B;IAE3B,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAElE,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,qBAAqB,WAAW,SAAS,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,GAAG,CACT,qBAAqB,WAAW,UAAU,MAAM,CAAC,UAAU,CAAC,WAAW,UAAU,CAClF,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEjF,IAAI,CAAC;QACH,QAAQ,CAAC,mCAAmC,KAAK,EAAE,EAAE;YACnD,KAAK,EAAE,MAAM;YACb,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC,CAAC;QACH,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}