sdd-flow-kit 1.0.22 → 1.0.27

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 CHANGED
@@ -11,6 +11,23 @@
11
11
  软件架构说明
12
12
 
13
13
 
14
+ #### Node 版本(14.16 / 18 / 20 均可)
15
+
16
+ | 组件 | 要求 |
17
+ |------|------|
18
+ | **sdd-flow-kit** CLI(`install` / `run` / `doctor` / `postinstall`) | **Node >= 14.16.0**(`engines` 已声明;兼容老 CI/内网机) |
19
+ | **openspec** CLI、`opsx-workflow` | 以各自包文档为准;建议 **18+** |
20
+ | 目标业务仓(如 adInsight `frontend`) | 按该仓 `package.json` engines,与 kit 独立 |
21
+
22
+ 安装后建议执行:
23
+
24
+ ```bash
25
+ node -v # 应 >= v14.16.0
26
+ npx sdd-flow-kit doctor --agent cursor
27
+ ```
28
+
29
+ 若 `doctor` 报 `node-version` 失败,请升级到 14.16+,或在该仓使用 `.nvmrc` 锁定版本。
30
+
14
31
  #### 安装教程
15
32
 
16
33
  1. 进入你要开发的项目目录
@@ -59,10 +76,11 @@
59
76
  ##### 需求澄清:用户无需背提示词
60
77
 
61
78
  `install` 会写入 `.cursor/rules/sdd-flow-kit-gates.mdc` 与触发 Skill。
62
- 澄清阶段你**直接粘贴确认点**(编号列表即可),AI 应自动进入文档模式,只改 `openspec/PRD/**`,不改 `src/`。
63
- 写业务代码仅在 `/opsx-propose` 完成且你同意 `/opsx-apply` 之后。
79
+ 澄清阶段你**直接粘贴确认点**(编号列表即可),AI 先进入文档模式更新 `openspec/PRD/**`。
80
+ **默认**:03 闭环并生成 01/02/04 后,**同一回合自动** `/opsx-propose`(01+02+UI)→ `/opsx-apply`,无需再说「继续」。
81
+ 说「只提案」或「先别写代码」可停在提案阶段;设 `autoChainOpsx: false` 可恢复人工分步。
64
82
 
65
- 阶段口语(可选,非必须):`继续` / `做提案` propose;`开始 apply` → 实现。
83
+ 阶段口语(可选,用于断点续跑):`继续` / `做提案` / `开始 apply`。
66
84
 
67
85
  ##### `/opsx-apply` 与 TDD + Playwright 检查机制
68
86
 
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getAdapter = getAdapter;
7
- const node_child_process_1 = require("node:child_process");
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const node_process_1 = __importDefault(require("node:process"));
7
+ const child_process_1 = require("child_process");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
10
  const fs_1 = require("../core/fs");
11
11
  function hasCommand(cmd) {
12
- const result = (0, node_child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" });
12
+ const result = (0, child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" });
13
13
  return result.status === 0;
14
14
  }
15
15
  function createManualAdapter(name, displayName, bins) {
@@ -25,15 +25,16 @@ function createManualAdapter(name, displayName, bins) {
25
25
  };
26
26
  }
27
27
  async function runClaudeFlow(args) {
28
+ var _a;
28
29
  // 默认关闭“二次调用 claude”自动执行,避免在 AI 会话内递归触发导致静默挂起。
29
30
  // 仅在显式开启时执行:SDD_FLOW_KIT_ENABLE_CLAUDE_AUTORUN=1
30
- if (node_process_1.default.env.SDD_FLOW_KIT_ENABLE_CLAUDE_AUTORUN !== "1") {
31
+ if (process_1.default.env.SDD_FLOW_KIT_ENABLE_CLAUDE_AUTORUN !== "1") {
31
32
  return false;
32
33
  }
33
34
  const hasClaude = hasCommand("claude");
34
35
  if (!hasClaude)
35
36
  return false;
36
- const sddPrompt = await (0, fs_1.readFileIfExists)(node_path_1.default.join(args.outputRoot, "02-需求分析提示词.md"));
37
+ const sddPrompt = await (0, fs_1.readFileIfExists)(path_1.default.join(args.outputRoot, "02-需求分析提示词.md"));
37
38
  if (!sddPrompt)
38
39
  return false;
39
40
  const prompt = [
@@ -42,23 +43,23 @@ async function runClaudeFlow(args) {
42
43
  "1) 01-获取需求文档指引:回填 source/PRD.md(及接口文档,如有)。",
43
44
  "2) 02-需求分析:若矛盾点未闭合,仅更新 03-待确认问题清单.md 并停止;用户确认后再生成 01/02/闭环03。",
44
45
  "3) 用户确认后补全 04-技术文档草稿.md。",
45
- "4) /opsx-propose:基于 0102 UI 参考生成 openspec change,并记录到 05-openspec-提案草稿.md",
46
- "5) /opsx-apply:提案 apply-ready 后执行 delivery-pipeline。",
46
+ "4) 03 闭环后默认同一回合:/opsx-propose01+02+UI)→ /opsx-apply delivery-pipeline exit 0(见 06-opsx-自动串联指引.md)。",
47
+ "5) 仅当用户说「只提案」或 autoChainOpsx=false 时,在 propose 后暂停等待 apply。",
47
48
  "完成后输出一句:SDD flow completed",
48
49
  "",
49
50
  "以下是第2步提示词:",
50
51
  sddPrompt,
51
52
  ].join("\n");
52
- const commandResult = (0, node_child_process_1.spawnSync)("claude", ["-p", prompt], {
53
+ const commandResult = (0, child_process_1.spawnSync)("claude", ["-p", prompt], {
53
54
  cwd: args.outputRoot,
54
55
  encoding: "utf8",
55
- env: node_process_1.default.env,
56
+ env: process_1.default.env,
56
57
  });
57
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(args.outputRoot, "AUTO-RUN-LOG.md"), [
58
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(args.outputRoot, "AUTO-RUN-LOG.md"), [
58
59
  "# AUTO-RUN-LOG",
59
60
  "",
60
61
  `agent: claude-code`,
61
- `status: ${commandResult.status ?? "unknown"}`,
62
+ `status: ${(_a = commandResult.status) !== null && _a !== void 0 ? _a : "unknown"}`,
62
63
  "",
63
64
  "## stdout",
64
65
  commandResult.stdout || "",
package/dist/cli.js CHANGED
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const node_process_1 = __importDefault(require("node:process"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const process_1 = __importDefault(require("process"));
9
9
  const startFlow_1 = require("./steps/startFlow");
10
10
  const runFlow_1 = require("./steps/runFlow");
11
11
  const utils_1 = require("./core/utils");
@@ -14,10 +14,10 @@ const doctor_1 = require("./steps/doctor");
14
14
  const invokeFlow_1 = require("./steps/invokeFlow");
15
15
  const ALLOWED_AGENTS = ["cursor", "claude-code", "codex", "openclaw", "custom"];
16
16
  function getArgValue(flag) {
17
- const idx = node_process_1.default.argv.indexOf(flag);
17
+ const idx = process_1.default.argv.indexOf(flag);
18
18
  if (idx === -1)
19
19
  return null;
20
- const v = node_process_1.default.argv[idx + 1];
20
+ const v = process_1.default.argv[idx + 1];
21
21
  if (!v)
22
22
  return null;
23
23
  return v;
@@ -61,7 +61,8 @@ function printHelp() {
61
61
  ].join("\n"));
62
62
  }
63
63
  async function main() {
64
- const cmd = node_process_1.default.argv[2];
64
+ var _a, _b, _c, _d;
65
+ const cmd = process_1.default.argv[2];
65
66
  if (!cmd || cmd === "--help" || cmd === "-h") {
66
67
  printHelp();
67
68
  return;
@@ -74,23 +75,23 @@ async function main() {
74
75
  cmd !== "ensure-opsx" &&
75
76
  cmd !== "invoke") {
76
77
  printHelp();
77
- node_process_1.default.exitCode = 1;
78
+ process_1.default.exitCode = 1;
78
79
  return;
79
80
  }
80
81
  const product = getArgValue("--product");
81
82
  const version = getArgValue("--version");
82
- const projectRoot = getArgValue("--projectRoot") ?? node_process_1.default.cwd();
83
- const branch = getArgValue("--branch") ?? undefined;
84
- const yes = node_process_1.default.argv.includes("-y");
85
- const dryRun = node_process_1.default.argv.includes("--dry-run");
86
- const planJson = node_process_1.default.argv.includes("--plan-json");
87
- const agentValue = getArgValue("--agent") ?? "claude-code";
88
- const projectKind = (getArgValue("--project") ?? "OMS");
83
+ const projectRoot = (_a = getArgValue("--projectRoot")) !== null && _a !== void 0 ? _a : process_1.default.cwd();
84
+ const branch = (_b = getArgValue("--branch")) !== null && _b !== void 0 ? _b : undefined;
85
+ const yes = process_1.default.argv.includes("-y");
86
+ const dryRun = process_1.default.argv.includes("--dry-run");
87
+ const planJson = process_1.default.argv.includes("--plan-json");
88
+ const agentValue = (_c = getArgValue("--agent")) !== null && _c !== void 0 ? _c : "claude-code";
89
+ const projectKind = ((_d = getArgValue("--project")) !== null && _d !== void 0 ? _d : "OMS");
89
90
  if (!ALLOWED_AGENTS.includes(agentValue)) {
90
91
  // eslint-disable-next-line no-console
91
92
  console.error(`不支持的 --agent: ${agentValue}`);
92
93
  printHelp();
93
- node_process_1.default.exitCode = 1;
94
+ process_1.default.exitCode = 1;
94
95
  return;
95
96
  }
96
97
  const agent = agentValue;
@@ -98,13 +99,13 @@ async function main() {
98
99
  if (!allowedProjects.includes(projectKind)) {
99
100
  // eslint-disable-next-line no-console
100
101
  console.error(`不支持的 --project: ${projectKind}(可选:${allowedProjects.join(" / ")})`);
101
- node_process_1.default.exitCode = 1;
102
+ process_1.default.exitCode = 1;
102
103
  return;
103
104
  }
104
105
  if (cmd === "doctor" || cmd === "ensure-opsx") {
105
- const fix = cmd === "ensure-opsx" || node_process_1.default.argv.includes("--fix");
106
+ const fix = cmd === "ensure-opsx" || process_1.default.argv.includes("--fix");
106
107
  const doctor = await (0, doctor_1.runDoctor)({
107
- projectRoot: node_path_1.default.resolve(projectRoot),
108
+ projectRoot: path_1.default.resolve(projectRoot),
108
109
  agent,
109
110
  fix,
110
111
  dryRun,
@@ -117,11 +118,11 @@ async function main() {
117
118
  }
118
119
  if (planJson) {
119
120
  // eslint-disable-next-line no-console
120
- console.log(JSON.stringify({ command: "doctor", projectRoot: node_path_1.default.resolve(projectRoot), result: doctor }, null, 2));
121
+ console.log(JSON.stringify({ command: "doctor", projectRoot: path_1.default.resolve(projectRoot), result: doctor }, null, 2));
121
122
  }
122
123
  if (cmd === "ensure-opsx" && !dryRun) {
123
124
  await (0, setupProject_1.setupProject)({
124
- projectRoot: node_path_1.default.resolve(projectRoot),
125
+ projectRoot: path_1.default.resolve(projectRoot),
125
126
  agent,
126
127
  yes: true,
127
128
  light: true,
@@ -129,12 +130,12 @@ async function main() {
129
130
  });
130
131
  }
131
132
  if (!doctor.ok)
132
- node_process_1.default.exitCode = 1;
133
+ process_1.default.exitCode = 1;
133
134
  return;
134
135
  }
135
136
  if (cmd === "setup" || cmd === "install") {
136
137
  const result = await (0, setupProject_1.setupProject)({
137
- projectRoot: node_path_1.default.resolve(projectRoot),
138
+ projectRoot: path_1.default.resolve(projectRoot),
138
139
  agent,
139
140
  branch,
140
141
  yes,
@@ -151,7 +152,7 @@ async function main() {
151
152
  // eslint-disable-next-line no-console
152
153
  console.log(JSON.stringify({
153
154
  command: cmd,
154
- projectRoot: node_path_1.default.resolve(projectRoot),
155
+ projectRoot: path_1.default.resolve(projectRoot),
155
156
  dryRun,
156
157
  result,
157
158
  }, null, 2));
@@ -160,18 +161,18 @@ async function main() {
160
161
  }
161
162
  if (!product || !version) {
162
163
  if (cmd === "invoke") {
163
- const raw = node_process_1.default.argv
164
+ const raw = process_1.default.argv
164
165
  .slice(3)
165
166
  .filter((token) => !token.startsWith("--") && token !== "-y")
166
167
  .join(" ")
167
168
  .trim();
168
169
  const fromFlag = getArgValue("--text");
169
- const text = (fromFlag ?? raw).trim();
170
+ const text = (fromFlag !== null && fromFlag !== void 0 ? fromFlag : raw).trim();
170
171
  const parsed = (0, invokeFlow_1.parseInvokeText)(text);
171
172
  if (!parsed) {
172
173
  throw new Error("invoke 解析失败,请使用:开发 ADI 2.3.2 需求");
173
174
  }
174
- const resolvedRoot = node_path_1.default.resolve(projectRoot);
175
+ const resolvedRoot = path_1.default.resolve(projectRoot);
175
176
  const options = (0, invokeFlow_1.toRunOptions)({
176
177
  parsed,
177
178
  projectRoot: resolvedRoot,
@@ -190,10 +191,10 @@ async function main() {
190
191
  return;
191
192
  }
192
193
  printHelp();
193
- node_process_1.default.exitCode = 1;
194
+ process_1.default.exitCode = 1;
194
195
  return;
195
196
  }
196
- const resolvedRoot = node_path_1.default.resolve(projectRoot);
197
+ const resolvedRoot = path_1.default.resolve(projectRoot);
197
198
  const runId = `${(0, utils_1.formatYYYYMMDD)(new Date())}-${product}-${version}`;
198
199
  if (cmd === "start") {
199
200
  await (0, startFlow_1.startFlowScaffold)({
@@ -243,5 +244,5 @@ async function main() {
243
244
  main().catch((e) => {
244
245
  // eslint-disable-next-line no-console
245
246
  console.error(e);
246
- node_process_1.default.exitCode = 1;
247
+ process_1.default.exitCode = 1;
247
248
  });
package/dist/core/fs.js CHANGED
@@ -5,8 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.readFileIfExists = readFileIfExists;
7
7
  exports.writeTextFileEnsuredDir = writeTextFileEnsuredDir;
8
- const promises_1 = __importDefault(require("node:fs/promises"));
9
- const node_path_1 = __importDefault(require("node:path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const path_1 = __importDefault(require("path"));
10
10
  async function readFileIfExists(filePath) {
11
11
  try {
12
12
  return await promises_1.default.readFile(filePath, "utf8");
@@ -22,6 +22,6 @@ async function readFileIfExists(filePath) {
22
22
  }
23
23
  }
24
24
  async function writeTextFileEnsuredDir(filePath, content) {
25
- await promises_1.default.mkdir(node_path_1.default.dirname(filePath), { recursive: true });
25
+ await promises_1.default.mkdir(path_1.default.dirname(filePath), { recursive: true });
26
26
  await promises_1.default.writeFile(filePath, content, "utf8");
27
27
  }
@@ -7,8 +7,8 @@ exports.PRODUCT_PREFIX_BY_KIND = exports.DOC_SKILL_BY_KIND = exports.ALLOWED_PRO
7
7
  exports.productToKind = productToKind;
8
8
  exports.resolveDocSkillDir = resolveDocSkillDir;
9
9
  exports.inferProjectKind = inferProjectKind;
10
- const promises_1 = __importDefault(require("node:fs/promises"));
11
- const node_path_1 = __importDefault(require("node:path"));
10
+ const promises_1 = __importDefault(require("fs/promises"));
11
+ const path_1 = __importDefault(require("path"));
12
12
  exports.ALLOWED_PROJECTS = ["OMS", "ADI", "欢盟", "AD Tools"];
13
13
  exports.DOC_SKILL_BY_KIND = {
14
14
  ADI: "adi-doc-skill",
@@ -37,24 +37,24 @@ function productToKind(product) {
37
37
  /** 从 projectRoot 向上查找 docs/*-doc-skill(适配 frontend 子目录 + 根目录 docs) */
38
38
  async function resolveDocSkillDir(projectRoot, kind) {
39
39
  const dirName = exports.DOC_SKILL_BY_KIND[kind];
40
- let cur = node_path_1.default.resolve(projectRoot);
40
+ let cur = path_1.default.resolve(projectRoot);
41
41
  for (let i = 0; i < 8; i += 1) {
42
- const candidate = node_path_1.default.join(cur, "docs", dirName);
43
- if (await pathExists(node_path_1.default.join(candidate, "confluence-doc.py"))) {
44
- const rel = node_path_1.default.relative(projectRoot, candidate);
42
+ const candidate = path_1.default.join(cur, "docs", dirName);
43
+ if (await pathExists(path_1.default.join(candidate, "confluence-doc.py"))) {
44
+ const rel = path_1.default.relative(projectRoot, candidate);
45
45
  return {
46
46
  absPath: candidate,
47
- relFromRoot: rel.startsWith("..") ? rel : node_path_1.default.join("docs", dirName),
47
+ relFromRoot: rel.startsWith("..") ? rel : path_1.default.join("docs", dirName),
48
48
  };
49
49
  }
50
- const parent = node_path_1.default.dirname(cur);
50
+ const parent = path_1.default.dirname(cur);
51
51
  if (parent === cur)
52
52
  break;
53
53
  cur = parent;
54
54
  }
55
55
  return {
56
- absPath: node_path_1.default.join(projectRoot, "docs", dirName),
57
- relFromRoot: node_path_1.default.join("docs", dirName),
56
+ absPath: path_1.default.join(projectRoot, "docs", dirName),
57
+ relFromRoot: path_1.default.join("docs", dirName),
58
58
  };
59
59
  }
60
60
  async function pathExists(filePath) {
@@ -87,12 +87,12 @@ async function inferFromExistingDocSkill(projectRoot) {
87
87
  let dir = projectRoot;
88
88
  for (let i = 0; i < 8; i += 1) {
89
89
  for (const kind of exports.ALLOWED_PROJECTS) {
90
- const rel = node_path_1.default.join(dir, "docs", exports.DOC_SKILL_BY_KIND[kind]);
91
- if (await pathExists(node_path_1.default.join(rel, "SKILL.md"))) {
90
+ const rel = path_1.default.join(dir, "docs", exports.DOC_SKILL_BY_KIND[kind]);
91
+ if (await pathExists(path_1.default.join(rel, "SKILL.md"))) {
92
92
  return kind;
93
93
  }
94
94
  }
95
- const parent = node_path_1.default.dirname(dir);
95
+ const parent = path_1.default.dirname(dir);
96
96
  if (parent === dir)
97
97
  break;
98
98
  dir = parent;
@@ -101,10 +101,10 @@ async function inferFromExistingDocSkill(projectRoot) {
101
101
  }
102
102
  /** 从目录路径(含父级)推断产品类型 */
103
103
  function inferFromPathSegments(projectRoot) {
104
- const resolved = node_path_1.default.resolve(projectRoot);
105
- const parts = resolved.split(node_path_1.default.sep);
104
+ const resolved = path_1.default.resolve(projectRoot);
105
+ const parts = resolved.split(path_1.default.sep);
106
106
  for (let i = parts.length; i > 0; i -= 1) {
107
- const segment = parts.slice(0, i).join(node_path_1.default.sep);
107
+ const segment = parts.slice(0, i).join(path_1.default.sep);
108
108
  const hit = matchKindInText(segment);
109
109
  if (hit)
110
110
  return hit;
@@ -112,10 +112,11 @@ function inferFromPathSegments(projectRoot) {
112
112
  return null;
113
113
  }
114
114
  async function inferFromPackageJson(dir) {
115
+ var _a, _b;
115
116
  try {
116
- const pkgText = await promises_1.default.readFile(node_path_1.default.join(dir, "package.json"), "utf8");
117
+ const pkgText = await promises_1.default.readFile(path_1.default.join(dir, "package.json"), "utf8");
117
118
  const pkg = JSON.parse(pkgText);
118
- const blob = `${pkg.name ?? ""} ${pkg.description ?? ""}`;
119
+ const blob = `${(_a = pkg.name) !== null && _a !== void 0 ? _a : ""} ${(_b = pkg.description) !== null && _b !== void 0 ? _b : ""}`;
119
120
  return matchKindInText(blob);
120
121
  }
121
122
  catch {
@@ -127,7 +128,8 @@ async function inferFromPackageJson(dir) {
127
128
  * monorepo 子目录(如 adInsight-web/frontend)会向上扫描路径,避免误判为 OMS。
128
129
  */
129
130
  async function inferProjectKind(projectRoot) {
130
- const fromEnv = (process.env.SDD_FLOW_KIT_PROJECT ?? "").trim();
131
+ var _a;
132
+ const fromEnv = ((_a = process.env.SDD_FLOW_KIT_PROJECT) !== null && _a !== void 0 ? _a : "").trim();
131
133
  if (exports.ALLOWED_PROJECTS.includes(fromEnv)) {
132
134
  return fromEnv;
133
135
  }
@@ -140,7 +142,7 @@ async function inferProjectKind(projectRoot) {
140
142
  const fromPkg = await inferFromPackageJson(dir);
141
143
  if (fromPkg)
142
144
  return fromPkg;
143
- const parent = node_path_1.default.dirname(dir);
145
+ const parent = path_1.default.dirname(dir);
144
146
  if (parent === dir)
145
147
  break;
146
148
  dir = parent;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MIN_NODE_PATCH = exports.MIN_NODE_MINOR = exports.MIN_NODE_MAJOR = void 0;
7
+ exports.parseNodeSemver = parseNodeSemver;
8
+ exports.isNodeVersionSupported = isNodeVersionSupported;
9
+ exports.nodeVersionRequirementLabel = nodeVersionRequirementLabel;
10
+ const process_1 = __importDefault(require("process"));
11
+ /** 与 package.json engines.node 对齐 */
12
+ exports.MIN_NODE_MAJOR = 14;
13
+ exports.MIN_NODE_MINOR = 16;
14
+ exports.MIN_NODE_PATCH = 0;
15
+ function parseNodeSemver() {
16
+ const m = process_1.default.version.match(/^v(\d+)\.(\d+)\.(\d+)/);
17
+ if (!m)
18
+ return { major: 0, minor: 0, patch: 0 };
19
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
20
+ }
21
+ function isNodeVersionSupported() {
22
+ const v = parseNodeSemver();
23
+ if (v.major > exports.MIN_NODE_MAJOR)
24
+ return true;
25
+ if (v.major < exports.MIN_NODE_MAJOR)
26
+ return false;
27
+ if (v.minor > exports.MIN_NODE_MINOR)
28
+ return true;
29
+ if (v.minor < exports.MIN_NODE_MINOR)
30
+ return false;
31
+ return v.patch >= exports.MIN_NODE_PATCH;
32
+ }
33
+ function nodeVersionRequirementLabel() {
34
+ return `>= ${exports.MIN_NODE_MAJOR}.${exports.MIN_NODE_MINOR}.${exports.MIN_NODE_PATCH}`;
35
+ }
@@ -11,9 +11,9 @@ exports.buildOpsxWorkflowSetupCommand = buildOpsxWorkflowSetupCommand;
11
11
  exports.isOpsxApplyReady = isOpsxApplyReady;
12
12
  exports.ensureOpsxWorkflow = ensureOpsxWorkflow;
13
13
  exports.collectDeliverySetupChecks = collectDeliverySetupChecks;
14
- const node_child_process_1 = require("node:child_process");
15
- const promises_1 = __importDefault(require("node:fs/promises"));
16
- const node_path_1 = __importDefault(require("node:path"));
14
+ const child_process_1 = require("child_process");
15
+ const promises_1 = __importDefault(require("fs/promises"));
16
+ const path_1 = __importDefault(require("path"));
17
17
  const fs_1 = require("./fs");
18
18
  const DELIVERY_SCRIPT_REL = ".cursor/skills/opsx-dev-delivery-pipeline/scripts/opsx-delivery-pipeline.sh";
19
19
  function deliveryPipelineNpmScripts() {
@@ -32,24 +32,24 @@ async function pathExists(filePath) {
32
32
  }
33
33
  /** 优先使用已安装 OPSX skills 的 editor 目录 */
34
34
  async function resolveOpsxAgent(projectRoot, preferred) {
35
- const deliverySkill = node_path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
35
+ const deliverySkill = path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
36
36
  if (await pathExists(deliverySkill))
37
37
  return "cursor";
38
- const claudeDelivery = node_path_1.default.join(projectRoot, ".claude", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
38
+ const claudeDelivery = path_1.default.join(projectRoot, ".claude", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
39
39
  if (await pathExists(claudeDelivery))
40
40
  return "claude-code";
41
- if (await pathExists(node_path_1.default.join(projectRoot, ".cursor")))
41
+ if (await pathExists(path_1.default.join(projectRoot, ".cursor")))
42
42
  return "cursor";
43
- if (await pathExists(node_path_1.default.join(projectRoot, ".claude")))
43
+ if (await pathExists(path_1.default.join(projectRoot, ".claude")))
44
44
  return "claude-code";
45
45
  return preferred;
46
46
  }
47
47
  /** 将 package.json 中过期的 poquan-delivery-pipeline 脚本修正为 opsx-dev-delivery-pipeline */
48
48
  async function repairOpsxDeliveryScripts(projectRoot) {
49
- const pkgPath = node_path_1.default.join(projectRoot, "package.json");
49
+ const pkgPath = path_1.default.join(projectRoot, "package.json");
50
50
  if (!(await pathExists(pkgPath)))
51
51
  return false;
52
- const scriptOnDisk = node_path_1.default.join(projectRoot, DELIVERY_SCRIPT_REL);
52
+ const scriptOnDisk = path_1.default.join(projectRoot, DELIVERY_SCRIPT_REL);
53
53
  if (!(await pathExists(scriptOnDisk)))
54
54
  return false;
55
55
  const { full, short } = deliveryPipelineNpmScripts();
@@ -73,7 +73,7 @@ async function repairOpsxDeliveryScripts(projectRoot) {
73
73
  return true;
74
74
  }
75
75
  function hasCommand(cmd) {
76
- return (0, node_child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" }).status === 0;
76
+ return (0, child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" }).status === 0;
77
77
  }
78
78
  function buildOpsxWorkflowSetupCommand(projectRoot, agent) {
79
79
  const baseArgs = ["@lixin5257xxx/opsx-workflow", "setup"];
@@ -120,7 +120,7 @@ async function ensureOpsxWorkflow(options) {
120
120
  plannedActions,
121
121
  };
122
122
  }
123
- const ret = (0, node_child_process_1.spawnSync)(cmd, args, {
123
+ const ret = (0, child_process_1.spawnSync)(cmd, args, {
124
124
  cwd: options.projectRoot,
125
125
  stdio: "inherit",
126
126
  env: process.env,
@@ -142,10 +142,11 @@ async function ensureOpsxWorkflow(options) {
142
142
  };
143
143
  }
144
144
  async function collectDeliverySetupChecks(projectRoot) {
145
+ var _a, _b, _c, _d, _e, _f;
145
146
  const checks = [];
146
147
  checks.push({
147
148
  name: "openspec-dir",
148
- ok: await pathExists(node_path_1.default.join(projectRoot, "openspec")),
149
+ ok: await pathExists(path_1.default.join(projectRoot, "openspec")),
149
150
  detail: "openspec/ 目录",
150
151
  });
151
152
  checks.push({
@@ -153,34 +154,34 @@ async function collectDeliverySetupChecks(projectRoot) {
153
154
  ok: hasCommand("openspec"),
154
155
  detail: "openspec CLI(npx openspec 或全局安装)",
155
156
  });
156
- const skillPath = node_path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
157
+ const skillPath = path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md");
157
158
  checks.push({
158
159
  name: "opsx-dev-delivery-pipeline-skill",
159
160
  ok: await pathExists(skillPath),
160
161
  detail: skillPath,
161
162
  });
162
- const tddPath = node_path_1.default.join(projectRoot, ".cursor", "skills", "tdd-script", "SKILL.md");
163
+ const tddPath = path_1.default.join(projectRoot, ".cursor", "skills", "tdd-script", "SKILL.md");
163
164
  checks.push({
164
165
  name: "tdd-script-skill",
165
166
  ok: await pathExists(tddPath),
166
167
  detail: tddPath,
167
168
  });
168
- const applyPath = node_path_1.default.join(projectRoot, ".cursor", "skills", "openspec-apply-change", "SKILL.md");
169
+ const applyPath = path_1.default.join(projectRoot, ".cursor", "skills", "openspec-apply-change", "SKILL.md");
169
170
  checks.push({
170
171
  name: "openspec-apply-change-skill",
171
172
  ok: await pathExists(applyPath),
172
173
  detail: applyPath,
173
174
  });
174
- const pipelineScript = node_path_1.default.join(projectRoot, DELIVERY_SCRIPT_REL);
175
+ const pipelineScript = path_1.default.join(projectRoot, DELIVERY_SCRIPT_REL);
175
176
  checks.push({
176
177
  name: "delivery-pipeline-script",
177
178
  ok: await pathExists(pipelineScript),
178
179
  detail: pipelineScript,
179
180
  });
180
181
  try {
181
- const pkgText = await promises_1.default.readFile(node_path_1.default.join(projectRoot, "package.json"), "utf8");
182
+ const pkgText = await promises_1.default.readFile(path_1.default.join(projectRoot, "package.json"), "utf8");
182
183
  const pkg = JSON.parse(pkgText);
183
- const cmd = pkg.scripts?.["opsx:delivery-pipeline"] ?? "";
184
+ const cmd = (_b = (_a = pkg.scripts) === null || _a === void 0 ? void 0 : _a["opsx:delivery-pipeline"]) !== null && _b !== void 0 ? _b : "";
184
185
  const ok = cmd.includes("opsx-dev-delivery-pipeline") &&
185
186
  cmd.includes("opsx-delivery-pipeline.sh") &&
186
187
  !cmd.includes("poquan");
@@ -198,11 +199,11 @@ async function collectDeliverySetupChecks(projectRoot) {
198
199
  });
199
200
  }
200
201
  try {
201
- const cfgText = await promises_1.default.readFile(node_path_1.default.join(projectRoot, ".opsx", "config.json"), "utf8");
202
+ const cfgText = await promises_1.default.readFile(path_1.default.join(projectRoot, ".opsx", "config.json"), "utf8");
202
203
  const cfg = JSON.parse(cfgText);
203
- const skillsDir = cfg.skillsDir ?? "";
204
- const hasCursorDelivery = await pathExists(node_path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md"));
205
- const nameOk = cfg.deliveryPipeline?.skillName === "opsx-dev-delivery-pipeline";
204
+ const skillsDir = (_c = cfg.skillsDir) !== null && _c !== void 0 ? _c : "";
205
+ const hasCursorDelivery = await pathExists(path_1.default.join(projectRoot, ".cursor", "skills", "opsx-dev-delivery-pipeline", "SKILL.md"));
206
+ const nameOk = ((_d = cfg.deliveryPipeline) === null || _d === void 0 ? void 0 : _d.skillName) === "opsx-dev-delivery-pipeline";
206
207
  const dirOk = (hasCursorDelivery && skillsDir.includes(".cursor")) ||
207
208
  (!hasCursorDelivery && (skillsDir.includes(".cursor") || skillsDir.includes(".claude")));
208
209
  checks.push({
@@ -210,7 +211,7 @@ async function collectDeliverySetupChecks(projectRoot) {
210
211
  ok: nameOk && dirOk,
211
212
  detail: hasCursorDelivery && !skillsDir.includes(".cursor")
212
213
  ? `skills 在 .cursor 但 config 指向 ${skillsDir},请 npx sdd-flow-kit install -y`
213
- : `skillsDir=${skillsDir}, skillName=${cfg.deliveryPipeline?.skillName ?? ""}`,
214
+ : `skillsDir=${skillsDir}, skillName=${(_f = (_e = cfg.deliveryPipeline) === null || _e === void 0 ? void 0 : _e.skillName) !== null && _f !== void 0 ? _f : ""}`,
214
215
  });
215
216
  }
216
217
  catch {
@@ -221,7 +222,7 @@ async function collectDeliverySetupChecks(projectRoot) {
221
222
  });
222
223
  }
223
224
  try {
224
- const pkgText = await promises_1.default.readFile(node_path_1.default.join(projectRoot, "package.json"), "utf8");
225
+ const pkgText = await promises_1.default.readFile(path_1.default.join(projectRoot, "package.json"), "utf8");
225
226
  const pkg = JSON.parse(pkgText);
226
227
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
227
228
  const hasPw = Boolean(deps["@playwright/test"] || deps.playwright);
@@ -238,7 +239,7 @@ async function collectDeliverySetupChecks(projectRoot) {
238
239
  detail: "无法读取 package.json 检查 Playwright",
239
240
  });
240
241
  }
241
- const agentsMd = node_path_1.default.join(projectRoot, "AGENTS.md");
242
+ const agentsMd = path_1.default.join(projectRoot, "AGENTS.md");
242
243
  checks.push({
243
244
  name: "agents-md",
244
245
  ok: await pathExists(agentsMd),
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createPromptInterface = createPromptInterface;
40
+ exports.promptLine = promptLine;
41
+ const readline = __importStar(require("readline"));
42
+ const process_1 = __importDefault(require("process"));
43
+ /** Node 14 兼容:不使用 node:readline/promises(需 Node 17+) */
44
+ function createPromptInterface() {
45
+ return readline.createInterface({ input: process_1.default.stdin, output: process_1.default.stdout });
46
+ }
47
+ function promptLine(rl, query) {
48
+ return new Promise((resolve) => {
49
+ rl.question(query, (answer) => resolve(answer));
50
+ });
51
+ }