sdd-flow-kit 1.0.25 → 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. 进入你要开发的项目目录
@@ -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 = [
@@ -49,16 +50,16 @@ async function runClaudeFlow(args) {
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
+ }
@@ -4,16 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.loadTemplateText = loadTemplateText;
7
- const node_path_1 = __importDefault(require("node:path"));
7
+ const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = require("./fs");
9
9
  function resolveCandidatePaths(relPathFromPackageRoot) {
10
10
  // 在 TS 开发态:<pkg>/src/templates/xxx
11
11
  // 在编译态:<pkg>/dist/cli.js -> __dirname=<pkg>/dist,所以 src/templates 要向上找两级
12
12
  const here = __dirname; // src/core/* 或 dist/*
13
- const pkgRoot = node_path_1.default.resolve(here, "../.."); // 兼容 src/ 与 dist/
13
+ const pkgRoot = path_1.default.resolve(here, "../.."); // 兼容 src/ 与 dist/
14
14
  return [
15
- node_path_1.default.join(pkgRoot, "src", "templates", relPathFromPackageRoot),
16
- node_path_1.default.join(pkgRoot, "dist", "templates", relPathFromPackageRoot),
15
+ path_1.default.join(pkgRoot, "src", "templates", relPathFromPackageRoot),
16
+ path_1.default.join(pkgRoot, "dist", "templates", relPathFromPackageRoot),
17
17
  ];
18
18
  }
19
19
  async function loadTemplateText(relPathFromPackageRoot) {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatYYYYMMDD = formatYYYYMMDD;
4
+ exports.replaceAllStr = replaceAllStr;
4
5
  exports.ensurePosixRelativePath = ensurePosixRelativePath;
5
6
  /**
6
7
  * 生成 YYYYMMDD 字符串,用于 openspec/PRD 目录命名。
@@ -11,7 +12,13 @@ function formatYYYYMMDD(d) {
11
12
  const dd = String(d.getDate()).padStart(2, "0");
12
13
  return `${yyyy}${mm}${dd}`;
13
14
  }
15
+ /** Node 14 无 String.prototype.replaceAll(需 Node 15+) */
16
+ function replaceAllStr(text, search, replacement) {
17
+ if (!search)
18
+ return text;
19
+ return text.split(search).join(replacement);
20
+ }
14
21
  function ensurePosixRelativePath(p) {
15
22
  // 用于模板占位符中展示,避免反斜杠导致工具误解析。
16
- return p.replaceAll("\\", "/");
23
+ return replaceAllStr(p, "\\", "/");
17
24
  }
@@ -36,20 +36,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- const node_path_1 = __importDefault(require("node:path"));
40
- const node_process_1 = __importDefault(require("node:process"));
39
+ const path_1 = __importDefault(require("path"));
40
+ const process_1 = __importDefault(require("process"));
41
41
  const inferProject_1 = require("./core/inferProject");
42
42
  const opsxDelivery_1 = require("./core/opsxDelivery");
43
43
  const setupProject_1 = require("./steps/setupProject");
44
44
  async function inferAgent(projectRoot) {
45
- const fromEnv = (node_process_1.default.env.SDD_FLOW_KIT_AGENT ?? "").trim();
45
+ var _a;
46
+ const fromEnv = ((_a = process_1.default.env.SDD_FLOW_KIT_AGENT) !== null && _a !== void 0 ? _a : "").trim();
46
47
  const allowed = ["cursor", "claude-code", "codex", "openclaw"];
47
48
  if (allowed.includes(fromEnv))
48
49
  return fromEnv;
49
- const fs = await Promise.resolve().then(() => __importStar(require("node:fs/promises")));
50
+ const fs = await Promise.resolve().then(() => __importStar(require("fs/promises")));
50
51
  const exists = async (rel) => {
51
52
  try {
52
- await fs.access(node_path_1.default.join(projectRoot, rel));
53
+ await fs.access(path_1.default.join(projectRoot, rel));
53
54
  return true;
54
55
  }
55
56
  catch {
@@ -67,12 +68,12 @@ async function inferAgent(projectRoot) {
67
68
  return "cursor";
68
69
  }
69
70
  async function main() {
70
- if (node_process_1.default.env.SDD_FLOW_KIT_SKIP_POSTINSTALL === "1") {
71
+ if (process_1.default.env.SDD_FLOW_KIT_SKIP_POSTINSTALL === "1") {
71
72
  return;
72
73
  }
73
- const initCwd = node_process_1.default.env.INIT_CWD ? node_path_1.default.resolve(node_process_1.default.env.INIT_CWD) : null;
74
- const pkgDir = node_path_1.default.resolve(__dirname, "..");
75
- const projectRoot = initCwd ?? node_process_1.default.cwd();
74
+ const initCwd = process_1.default.env.INIT_CWD ? path_1.default.resolve(process_1.default.env.INIT_CWD) : null;
75
+ const pkgDir = path_1.default.resolve(__dirname, "..");
76
+ const projectRoot = initCwd !== null && initCwd !== void 0 ? initCwd : process_1.default.cwd();
76
77
  if (projectRoot === pkgDir)
77
78
  return;
78
79
  const projectKind = await (0, inferProject_1.inferProjectKind)(projectRoot);
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runDoctor = runDoctor;
7
- const node_child_process_1 = require("node:child_process");
8
- const promises_1 = __importDefault(require("node:fs/promises"));
9
- const node_path_1 = __importDefault(require("node:path"));
7
+ const child_process_1 = require("child_process");
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const process_1 = __importDefault(require("process"));
11
+ const nodeCompat_1 = require("../core/nodeCompat");
10
12
  const opsxDelivery_1 = require("../core/opsxDelivery");
11
13
  function hasCommand(cmd) {
12
- const out = (0, node_child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" });
14
+ const out = (0, child_process_1.spawnSync)("which", [cmd], { stdio: "ignore" });
13
15
  return out.status === 0;
14
16
  }
15
17
  async function hasPath(filePath) {
@@ -34,6 +36,11 @@ function agentBin(agent) {
34
36
  }
35
37
  async function runDoctor(options) {
36
38
  const checks = [];
39
+ checks.push({
40
+ name: "node-version",
41
+ ok: (0, nodeCompat_1.isNodeVersionSupported)(),
42
+ detail: `Node ${process_1.default.version}(要求 ${(0, nodeCompat_1.nodeVersionRequirementLabel)()},推荐 18/20 LTS)`,
43
+ });
37
44
  checks.push({
38
45
  name: "git",
39
46
  ok: hasCommand("git"),
@@ -54,7 +61,7 @@ async function runDoctor(options) {
54
61
  }
55
62
  checks.push({
56
63
  name: "openspec-dir",
57
- ok: await hasPath(node_path_1.default.join(options.projectRoot, "openspec")),
64
+ ok: await hasPath(path_1.default.join(options.projectRoot, "openspec")),
58
65
  detail: "openspec 目录存在性",
59
66
  });
60
67
  const toolDirMap = {
@@ -68,7 +75,7 @@ async function runDoctor(options) {
68
75
  if (expectedDir) {
69
76
  checks.push({
70
77
  name: `${options.agent}-dir`,
71
- ok: await hasPath(node_path_1.default.join(options.projectRoot, expectedDir)),
78
+ ok: await hasPath(path_1.default.join(options.projectRoot, expectedDir)),
72
79
  detail: `${expectedDir} 目录存在性`,
73
80
  });
74
81
  }
@@ -17,6 +17,7 @@ function parseInvokeText(text) {
17
17
  return { product, version };
18
18
  }
19
19
  function toRunOptions(args) {
20
+ var _a, _b;
20
21
  return {
21
22
  product: args.parsed.product,
22
23
  version: args.parsed.version,
@@ -24,6 +25,6 @@ function toRunOptions(args) {
24
25
  branch: args.branch,
25
26
  yes: args.yes,
26
27
  dryRun: args.dryRun,
27
- agent: args.agent ?? args.parsed.agent ?? "claude-code",
28
+ agent: (_b = (_a = args.agent) !== null && _a !== void 0 ? _a : args.parsed.agent) !== null && _b !== void 0 ? _b : "claude-code",
28
29
  };
29
30
  }
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runFlow = runFlow;
7
- const node_path_1 = __importDefault(require("node:path"));
7
+ const path_1 = __importDefault(require("path"));
8
8
  const adapters_1 = require("../adapters");
9
9
  const fs_1 = require("../core/fs");
10
10
  const startFlow_1 = require("./startFlow");
@@ -41,7 +41,7 @@ async function runFlow(options) {
41
41
  const scaffold = options.dryRun
42
42
  ? {
43
43
  runId: "dry-run-no-files-generated",
44
- outputRoot: node_path_1.default.join(options.projectRoot, "openspec", "PRD"),
44
+ outputRoot: path_1.default.join(options.projectRoot, "openspec", "PRD"),
45
45
  }
46
46
  : await (0, startFlow_1.startFlowScaffold)(options);
47
47
  const adapter = (0, adapters_1.getAdapter)(setup.agent);
@@ -63,7 +63,7 @@ async function runFlow(options) {
63
63
  version: options.version,
64
64
  });
65
65
  if (!options.dryRun) {
66
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(scaffold.outputRoot, "AUTO-RUN-CHECKLIST.md"), checklist);
66
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(scaffold.outputRoot, "AUTO-RUN-CHECKLIST.md"), checklist);
67
67
  }
68
68
  return {
69
69
  ...scaffold,
@@ -4,19 +4,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.setupProject = setupProject;
7
- const node_child_process_1 = require("node:child_process");
8
- const node_path_1 = __importDefault(require("node:path"));
9
- const promises_1 = require("node:readline/promises");
10
- 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"));
11
10
  const fs_1 = require("../core/fs");
11
+ const readlinePrompt_1 = require("../core/readlinePrompt");
12
+ const utils_1 = require("../core/utils");
12
13
  const opsxDelivery_1 = require("../core/opsxDelivery");
13
14
  const templates_1 = require("../core/templates");
14
15
  const EDITOR_CHOICES = ["claude-code", "cursor", "codex", "openclaw"];
15
16
  const PROJECT_CHOICES = ["OMS", "ADI", "欢盟", "AD Tools"];
16
17
  function runGit(args, cwd) {
17
- const out = (0, node_child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8" });
18
+ var _a, _b;
19
+ const out = (0, child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8" });
18
20
  if (out.status !== 0) {
19
- const err = out.stderr?.trim() || out.stdout?.trim() || `git ${args.join(" ")} failed`;
21
+ const err = ((_a = out.stderr) === null || _a === void 0 ? void 0 : _a.trim()) || ((_b = out.stdout) === null || _b === void 0 ? void 0 : _b.trim()) || `git ${args.join(" ")} failed`;
20
22
  throw new Error(err);
21
23
  }
22
24
  return out.stdout.trim();
@@ -45,9 +47,9 @@ function listLocalBranches(projectRoot) {
45
47
  }
46
48
  }
47
49
  async function askAgent(defaultAgent) {
48
- if (!node_process_1.default.stdin.isTTY)
50
+ if (!process_1.default.stdin.isTTY)
49
51
  return defaultAgent;
50
- const rl = (0, promises_1.createInterface)({ input: node_process_1.default.stdin, output: node_process_1.default.stdout });
52
+ const rl = (0, readlinePrompt_1.createPromptInterface)();
51
53
  const prompt = [
52
54
  "请选择开发环境:",
53
55
  "1) claude-code (default)",
@@ -56,7 +58,7 @@ async function askAgent(defaultAgent) {
56
58
  "4) openclaw",
57
59
  "输入编号(回车默认 1):",
58
60
  ].join("\n");
59
- const answer = (await rl.question(`${prompt}\n`)).trim();
61
+ const answer = (await (0, readlinePrompt_1.promptLine)(rl, `${prompt}\n`)).trim();
60
62
  rl.close();
61
63
  if (!answer)
62
64
  return defaultAgent;
@@ -66,17 +68,17 @@ async function askAgent(defaultAgent) {
66
68
  return EDITOR_CHOICES[idx - 1];
67
69
  }
68
70
  async function askBranch(defaultBranch) {
69
- if (!node_process_1.default.stdin.isTTY)
71
+ if (!process_1.default.stdin.isTTY)
70
72
  return defaultBranch;
71
- const rl = (0, promises_1.createInterface)({ input: node_process_1.default.stdin, output: node_process_1.default.stdout });
72
- const answer = (await rl.question(`请输入开发分支(默认 ${defaultBranch}):\n`)).trim();
73
+ const rl = (0, readlinePrompt_1.createPromptInterface)();
74
+ const answer = (await (0, readlinePrompt_1.promptLine)(rl, `请输入开发分支(默认 ${defaultBranch}):\n`)).trim();
73
75
  rl.close();
74
76
  return answer || defaultBranch;
75
77
  }
76
78
  async function askProjectKind(defaultKind) {
77
- if (!node_process_1.default.stdin.isTTY)
79
+ if (!process_1.default.stdin.isTTY)
78
80
  return defaultKind;
79
- const rl = (0, promises_1.createInterface)({ input: node_process_1.default.stdin, output: node_process_1.default.stdout });
81
+ const rl = (0, readlinePrompt_1.createPromptInterface)();
80
82
  const prompt = [
81
83
  "请选择当前项目类型(用于生成 PRD 下载 skill):",
82
84
  "1) OMS (default)",
@@ -85,7 +87,7 @@ async function askProjectKind(defaultKind) {
85
87
  "4) AD Tools",
86
88
  "输入编号(回车默认 1):",
87
89
  ].join("\n");
88
- const answer = (await rl.question(`${prompt}\n`)).trim();
90
+ const answer = (await (0, readlinePrompt_1.promptLine)(rl, `${prompt}\n`)).trim();
89
91
  rl.close();
90
92
  if (!answer)
91
93
  return defaultKind;
@@ -114,7 +116,7 @@ function skillInstallPath(projectRoot, agent) {
114
116
  const rel = relMap[agent];
115
117
  if (!rel)
116
118
  return null;
117
- return node_path_1.default.join(projectRoot, rel);
119
+ return path_1.default.join(projectRoot, rel);
118
120
  }
119
121
  function allSkillInstallPaths(projectRoot) {
120
122
  const agents = ["cursor", "claude-code", "codex", "openclaw"];
@@ -135,19 +137,19 @@ async function installAgentSkill(projectRoot) {
135
137
  : target.includes("/.codex/")
136
138
  ? "codex"
137
139
  : "openclaw";
138
- const content = template.replaceAll("{{AGENT_NAME}}", agentName);
140
+ const content = (0, utils_1.replaceAllStr)(template, "{{AGENT_NAME}}", agentName);
139
141
  await (0, fs_1.writeTextFileEnsuredDir)(target, content);
140
142
  }
141
143
  }
142
144
  async function installSddCursorRule(projectRoot) {
143
- const rulePath = node_path_1.default.join(projectRoot, ".cursor", "rules", "sdd-flow-kit-gates.mdc");
145
+ const rulePath = path_1.default.join(projectRoot, ".cursor", "rules", "sdd-flow-kit-gates.mdc");
144
146
  const template = await (0, templates_1.loadTemplateText)("rules/sdd-no-implement-until-apply.mdc.template");
145
147
  await (0, fs_1.writeTextFileEnsuredDir)(rulePath, template);
146
148
  }
147
149
  function renderVars(template, vars) {
148
150
  let out = template;
149
151
  for (const [k, v] of Object.entries(vars)) {
150
- out = out.replaceAll(`{{${k}}}`, v);
152
+ out = (0, utils_1.replaceAllStr)(out, `{{${k}}}`, v);
151
153
  }
152
154
  return out;
153
155
  }
@@ -166,7 +168,7 @@ function docSkillDirName(kind) {
166
168
  }
167
169
  async function installDocsSkill(projectRoot, kind) {
168
170
  const { dir, prefix } = docSkillDirName(kind);
169
- const docsDir = node_path_1.default.join(projectRoot, "docs", dir);
171
+ const docsDir = path_1.default.join(projectRoot, "docs", dir);
170
172
  const pyTemplate = await (0, templates_1.loadTemplateText)("skills/confluence-doc.py.template");
171
173
  const mdTemplate = await (0, templates_1.loadTemplateText)("skills/doc-skill.SKILL.md.template");
172
174
  const md = renderVars(mdTemplate, {
@@ -176,9 +178,9 @@ async function installDocsSkill(projectRoot, kind) {
176
178
  PRODUCT_PREFIX_LOWER: prefix.toLowerCase(),
177
179
  SKILL_DIR: dir,
178
180
  });
179
- const py = pyTemplate.replaceAll("{{DOC_PRODUCT_PREFIX}}", prefix);
180
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(docsDir, "SKILL.md"), md);
181
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(docsDir, "confluence-doc.py"), py);
181
+ const py = (0, utils_1.replaceAllStr)(pyTemplate, "{{DOC_PRODUCT_PREFIX}}", prefix);
182
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(docsDir, "SKILL.md"), md);
183
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(docsDir, "confluence-doc.py"), py);
182
184
  return { dirPath: docsDir };
183
185
  }
184
186
  function getOpsxPathsByAgent(agent) {
@@ -196,7 +198,7 @@ function getOpsxPathsByAgent(agent) {
196
198
  }
197
199
  }
198
200
  async function installOpsxConfig(projectRoot, agent) {
199
- const target = node_path_1.default.join(projectRoot, ".opsx", "config.json");
201
+ const target = path_1.default.join(projectRoot, ".opsx", "config.json");
200
202
  const resolvedAgent = await (0, opsxDelivery_1.resolveOpsxAgent)(projectRoot, agent);
201
203
  const paths = getOpsxPathsByAgent(resolvedAgent);
202
204
  const config = {
@@ -216,11 +218,12 @@ async function installOpsxConfig(projectRoot, agent) {
216
218
  await (0, fs_1.writeTextFileEnsuredDir)(target, JSON.stringify(config, null, 2));
217
219
  }
218
220
  async function setupProject(options) {
219
- const defaultAgent = options.agent ?? "claude-code";
221
+ var _a, _b, _c;
222
+ const defaultAgent = (_a = options.agent) !== null && _a !== void 0 ? _a : "claude-code";
220
223
  const selectedAgent = options.yes ? defaultAgent : await askAgent(defaultAgent);
221
- const defaultKind = options.projectKind ?? "OMS";
224
+ const defaultKind = (_b = options.projectKind) !== null && _b !== void 0 ? _b : "OMS";
222
225
  const selectedKind = options.yes ? defaultKind : await askProjectKind(defaultKind);
223
- const defaultBranch = options.branch ?? pickDefaultBranch(options.projectRoot);
226
+ const defaultBranch = (_c = options.branch) !== null && _c !== void 0 ? _c : pickDefaultBranch(options.projectRoot);
224
227
  const selectedBranch = options.yes ? defaultBranch : await askBranch(defaultBranch);
225
228
  const plannedActions = [];
226
229
  const branches = listLocalBranches(options.projectRoot);
@@ -268,9 +271,9 @@ async function setupProject(options) {
268
271
  plannedActions.push(`would install skill: ${skillPath}`);
269
272
  }
270
273
  const { dir } = docSkillDirName(selectedKind);
271
- plannedActions.push(`would install docs skill: ${node_path_1.default.join(options.projectRoot, "docs", dir)}`);
272
- plannedActions.push(`would install opsx config: ${node_path_1.default.join(options.projectRoot, ".opsx", "config.json")}`);
273
- plannedActions.push(`would install cursor rule: ${node_path_1.default.join(options.projectRoot, ".cursor", "rules", "sdd-flow-kit-gates.mdc")}`);
274
+ plannedActions.push(`would install docs skill: ${path_1.default.join(options.projectRoot, "docs", dir)}`);
275
+ plannedActions.push(`would install opsx config: ${path_1.default.join(options.projectRoot, ".opsx", "config.json")}`);
276
+ plannedActions.push(`would install cursor rule: ${path_1.default.join(options.projectRoot, ".cursor", "rules", "sdd-flow-kit-gates.mdc")}`);
274
277
  }
275
278
  else {
276
279
  await installAgentSkill(options.projectRoot);
@@ -304,7 +307,7 @@ async function setupProject(options) {
304
307
  ...plannedActions.map((x) => `- ${x}`),
305
308
  "",
306
309
  ].join("\n");
307
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(options.projectRoot, ".sdd-flow-kit", "setup-summary.md"), summary);
310
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(options.projectRoot, ".sdd-flow-kit", "setup-summary.md"), summary);
308
311
  return {
309
312
  agent: selectedAgent,
310
313
  projectKind: selectedKind,
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.startFlowScaffold = startFlowScaffold;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const promises_1 = __importDefault(require("node:fs/promises"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
9
  const utils_1 = require("../core/utils");
10
10
  const fs_1 = require("../core/fs");
11
11
  const templates_1 = require("../core/templates");
@@ -13,15 +13,15 @@ const inferProject_1 = require("../core/inferProject");
13
13
  function renderTemplate(template, vars) {
14
14
  let out = template;
15
15
  for (const [k, v] of Object.entries(vars)) {
16
- out = out.replaceAll(`{{${k}}}`, v);
16
+ out = (0, utils_1.replaceAllStr)(out, `{{${k}}}`, v);
17
17
  }
18
18
  return out;
19
19
  }
20
20
  async function startFlowScaffold(options) {
21
21
  const now = new Date();
22
22
  const runId = `${(0, utils_1.formatYYYYMMDD)(now)}-${options.product}-${options.version}`;
23
- const outputRoot = node_path_1.default.join(options.projectRoot, "openspec", "PRD", runId);
24
- const sourceDir = node_path_1.default.join(outputRoot, "source");
23
+ const outputRoot = path_1.default.join(options.projectRoot, "openspec", "PRD", runId);
24
+ const sourceDir = path_1.default.join(outputRoot, "source");
25
25
  await promises_1.default.mkdir(sourceDir, { recursive: true });
26
26
  // 1) Step1: doc-skill 指引(按产品解析脚本路径,支持 monorepo frontend)
27
27
  const kind = (0, inferProject_1.productToKind)(options.product);
@@ -33,23 +33,23 @@ async function startFlowScaffold(options) {
33
33
  DOC_SKILL_REL: docSkill.relFromRoot.replace(/\\/g, "/"),
34
34
  VERSION_EXAMPLE: options.version,
35
35
  });
36
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "01-获取需求文档指引.md"), step1);
36
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "01-获取需求文档指引.md"), step1);
37
37
  // source 占位:让第 2 步提示词在任何工具里都能直接读
38
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(sourceDir, "PRD.md"), [
38
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(sourceDir, "PRD.md"), [
39
39
  "# source/PRD.md",
40
40
  "",
41
41
  "请把《PRD》markdown 内容粘贴到这里(由 `adi-doc-skill` 下载并回填)。",
42
42
  "",
43
43
  "- 建议:保持原有标题层级与编号。",
44
44
  ].join("\n"));
45
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(sourceDir, "接口文档.md"), [
45
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(sourceDir, "接口文档.md"), [
46
46
  "# source/接口文档.md",
47
47
  "",
48
48
  "(可选)如果你已经有接口文档,请粘贴到这里;没有也不影响后续 SDD 循环。",
49
49
  "",
50
50
  "- 注意:接口文档中的字段/示例越完整,分析报告越贴近落地。",
51
51
  ].join("\n"));
52
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(sourceDir, "openspec-knowledge-base-summary.md"), [
52
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(sourceDir, "openspec-knowledge-base-summary.md"), [
53
53
  "# source/openspec-knowledge-base-summary.md",
54
54
  "",
55
55
  "(可选)现有知识库摘要/快速索引,建议由你在执行第 2 步前手动整理。",
@@ -60,23 +60,23 @@ async function startFlowScaffold(options) {
60
60
  const sddLoopPrompt = await (0, templates_1.loadTemplateText)("prompts/02-sdd-loop-prompt.md");
61
61
  const step2PromptTemplate = await (0, templates_1.loadTemplateText)("artifacts/02-需求分析提示词.template.md");
62
62
  const step2Prompt = renderTemplate(step2PromptTemplate, { SDD_LOOP_PROMPT: sddLoopPrompt });
63
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "02-需求分析提示词.md"), step2Prompt);
63
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "02-需求分析提示词.md"), step2Prompt);
64
64
  // 3) Step2 输出文件占位(由 AI 工具生成并覆盖)
65
65
  const file01Template = await (0, templates_1.loadTemplateText)("artifacts/01-需求分析报告.template.md");
66
66
  const file02Template = await (0, templates_1.loadTemplateText)("artifacts/02-改动点清单.template.md");
67
67
  const file03Template = await (0, templates_1.loadTemplateText)("artifacts/03-待确认问题清单.template.md");
68
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "01-需求分析报告.md"), file01Template);
69
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "02-改动点清单.md"), file02Template);
70
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "03-待确认问题清单.md"), file03Template);
68
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "01-需求分析报告.md"), file01Template);
69
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "02-改动点清单.md"), file02Template);
70
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "03-待确认问题清单.md"), file03Template);
71
71
  // 4) Step4 技术文档入口(草稿)
72
72
  const techDocTemplate = await (0, templates_1.loadTemplateText)("artifacts/04-技术文档.template.md");
73
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "04-技术文档草稿.md"), techDocTemplate);
73
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "04-技术文档草稿.md"), techDocTemplate);
74
74
  // 5) Step5 openspec 提案入口(草稿)
75
75
  const openspecEntryTemplate = await (0, templates_1.loadTemplateText)("artifacts/05-openspec-提案草稿.template.md");
76
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "05-openspec-提案草稿.md"), openspecEntryTemplate);
76
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "05-openspec-提案草稿.md"), openspecEntryTemplate);
77
77
  const opsxAutoChainTemplate = await (0, templates_1.loadTemplateText)("artifacts/06-opsx-auto-chain.template.md");
78
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "06-opsx-自动串联指引.md"), opsxAutoChainTemplate);
79
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, ".session-state.json"), JSON.stringify({
78
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "06-opsx-自动串联指引.md"), opsxAutoChainTemplate);
79
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, ".session-state.json"), JSON.stringify({
80
80
  product: options.product,
81
81
  version: options.version,
82
82
  runId,
@@ -88,7 +88,7 @@ async function startFlowScaffold(options) {
88
88
  createdAtISO: new Date().toISOString(),
89
89
  }, null, 2));
90
90
  // runDir 自述
91
- await (0, fs_1.writeTextFileEnsuredDir)(node_path_1.default.join(outputRoot, "RUNME.md"), [
91
+ await (0, fs_1.writeTextFileEnsuredDir)(path_1.default.join(outputRoot, "RUNME.md"), [
92
92
  "# RUNME(SDD 流程执行说明)",
93
93
  "",
94
94
  `本次 runId: \`${runId}\``,
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "sdd-flow-kit",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "private": false,
5
5
  "description": "Cross-agent SDD automated development workflow kit (ADI/ADI-like).",
6
6
  "license": "MIT",
7
+ "engines": {
8
+ "node": ">=14.16.0"
9
+ },
7
10
  "type": "commonjs",
8
11
  "main": "dist/index.js",
9
12
  "files": [