lee-spec-kit 0.6.24 → 0.6.26

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/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import path22 from 'path';
2
+ import path23 from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { program } from 'commander';
5
- import fs16 from 'fs-extra';
5
+ import fs17 from 'fs-extra';
6
6
  import prompts from 'prompts';
7
7
  import chalk6 from 'chalk';
8
8
  import { spawn, spawnSync, execFileSync, execSync } from 'child_process';
@@ -10,7 +10,7 @@ import os from 'os';
10
10
  import { createHash, randomUUID } from 'crypto';
11
11
 
12
12
  var getFilename = () => fileURLToPath(import.meta.url);
13
- var getDirname = () => path22.dirname(getFilename());
13
+ var getDirname = () => path23.dirname(getFilename());
14
14
  var __dirname$1 = /* @__PURE__ */ getDirname();
15
15
  async function walkFiles(rootDir, options = {}) {
16
16
  const out = [];
@@ -21,9 +21,9 @@ async function walkFiles(rootDir, options = {}) {
21
21
  (options.ignoreDirs || []).map((value) => value.trim().toLowerCase()).filter(Boolean)
22
22
  );
23
23
  async function visit(current) {
24
- const entries = await fs16.readdir(current, { withFileTypes: true });
24
+ const entries = await fs17.readdir(current, { withFileTypes: true });
25
25
  for (const entry of entries) {
26
- const absolute = path22.join(current, entry.name);
26
+ const absolute = path23.join(current, entry.name);
27
27
  if (entry.isDirectory()) {
28
28
  if (ignored.has(entry.name.trim().toLowerCase())) continue;
29
29
  await visit(absolute);
@@ -31,26 +31,26 @@ async function walkFiles(rootDir, options = {}) {
31
31
  }
32
32
  if (!entry.isFile()) continue;
33
33
  if (normalizedExtensions.size > 0) {
34
- const ext = path22.extname(entry.name).toLowerCase();
34
+ const ext = path23.extname(entry.name).toLowerCase();
35
35
  if (!normalizedExtensions.has(ext)) continue;
36
36
  }
37
37
  out.push(absolute);
38
38
  }
39
39
  }
40
- if (await fs16.pathExists(rootDir)) {
40
+ if (await fs17.pathExists(rootDir)) {
41
41
  await visit(rootDir);
42
42
  }
43
43
  return out;
44
44
  }
45
45
  async function listSubdirectories(rootDir) {
46
- if (!await fs16.pathExists(rootDir)) return [];
47
- const entries = await fs16.readdir(rootDir, { withFileTypes: true });
48
- return entries.filter((entry) => entry.isDirectory()).map((entry) => path22.join(rootDir, entry.name));
46
+ if (!await fs17.pathExists(rootDir)) return [];
47
+ const entries = await fs17.readdir(rootDir, { withFileTypes: true });
48
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => path23.join(rootDir, entry.name));
49
49
  }
50
50
 
51
51
  // src/utils/template.ts
52
52
  async function copyTemplates(src, dest) {
53
- await fs16.copy(src, dest, {
53
+ await fs17.copy(src, dest, {
54
54
  overwrite: true,
55
55
  errorOnExist: false
56
56
  });
@@ -66,22 +66,22 @@ function applyReplacements(content, replacements) {
66
66
  async function replaceInFiles(dir, replacements) {
67
67
  const files = await walkFiles(dir, { extensions: [".md"] });
68
68
  for (const file of files) {
69
- let content = await fs16.readFile(file, "utf-8");
69
+ let content = await fs17.readFile(file, "utf-8");
70
70
  content = applyReplacements(content, replacements);
71
- await fs16.writeFile(file, content, "utf-8");
71
+ await fs17.writeFile(file, content, "utf-8");
72
72
  }
73
73
  const shFiles = await walkFiles(dir, { extensions: [".sh"] });
74
74
  for (const file of shFiles) {
75
- let content = await fs16.readFile(file, "utf-8");
75
+ let content = await fs17.readFile(file, "utf-8");
76
76
  content = applyReplacements(content, replacements);
77
- await fs16.writeFile(file, content, "utf-8");
77
+ await fs17.writeFile(file, content, "utf-8");
78
78
  }
79
79
  }
80
80
  var __filename2 = fileURLToPath(import.meta.url);
81
- var __dirname2 = path22.dirname(__filename2);
81
+ var __dirname2 = path23.dirname(__filename2);
82
82
  function getTemplatesDir() {
83
- const rootDir = path22.resolve(__dirname2, "..");
84
- return path22.join(rootDir, "templates");
83
+ const rootDir = path23.resolve(__dirname2, "..");
84
+ return path23.join(rootDir, "templates");
85
85
  }
86
86
 
87
87
  // src/utils/locales/ko.ts
@@ -163,11 +163,16 @@ var ko = {
163
163
  "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
164
164
  "context.suggestionCommandHint": "\uB77C\uBCA8 \uCC38\uACE0 \uBA85\uB839: {command}",
165
165
  "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example}, `A \uC9C4\uD589\uD574`)",
166
+ "context.autoRunUnavailable": "\uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8\uC5D0\uC11C\uB294 \uC790\uB3D9 \uC2E4\uD589\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
167
+ "context.autoRunSummary": "config \uAE30\uC900\uC73C\uB85C \uC2B9\uC778 \uD544\uC694 \uCE74\uD14C\uACE0\uB9AC \uC804\uAE4C\uC9C0 \uC5F0\uC18D \uC2E4\uD589\uD558\uC138\uC694: {categories}",
168
+ "context.autoRunCommandHint": "\uC790\uB3D9 \uC2E4\uD589 \uBA85\uB839(config \uAC8C\uC774\uD2B8): {command}",
169
+ "context.subAgentOrchestrationHint": "\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8 \uC624\uCF00\uC2A4\uD2B8\uB808\uC774\uC158: \uC9E7\uC740 \uB2E8\uACC4\uB294 \uBA54\uC778\uC774 \uC9C1\uC811 \uC218\uD589\uD558\uACE0, \uC7A5\uC2DC\uAC04 \uB8E8\uD504(task_execute/code_review/review_fix_commit/pre_pr_review \uB610\uB294 auto)\uB294 \uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8\uC5D0 \uC704\uC784\uD558\uC138\uC694.",
166
170
  "context.commandDetail.branchCreateWithWorktree": "({scope}) worktree {worktree}\uB97C \uC0AC\uC6A9\uD574 \uBE0C\uB79C\uCE58 {branch}\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
167
171
  "context.commandDetail.branchCreateWithBranch": "({scope}) \uBE0C\uB79C\uCE58 {branch}\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
168
172
  "context.commandDetail.branchCreateGeneric": "({scope}) feature \uBE0C\uB79C\uCE58\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
169
173
  "context.commandDetail.codeReviewMergeAfterOk": "({scope}) \uBA85\uC2DC\uC801 \uC2B9\uC778 \uD6C4 PR\uC744 \uBA38\uC9C0\uD558\uC138\uC694",
170
174
  "context.commandDetail.codeReviewPushFix": "({scope}) \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 push\uD558\uC138\uC694",
175
+ "context.commandDetail.prePrReviewRun": "({scope}) Pre-PR \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD558\uACE0 decisions.md\uC640 tasks.md\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
171
176
  "context.actionSummary.runDocsCommand": "\uBB38\uC11C \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
172
177
  "context.actionSummary.runProjectCommand": "\uD504\uB85C\uC81D\uD2B8 \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
173
178
  "context.actionDetail.featureFolder": "Feature \uD3F4\uB354\uC640 \uAE30\uBCF8 \uBB38\uC11C \uACE8\uACA9\uC744 \uC900\uBE44\uD558\uC138\uC694",
@@ -176,16 +181,38 @@ var ko = {
176
181
  "context.actionDetail.planWrite": "plan.md\uB97C \uC791\uC131/\uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C \uB9DE\uCD94\uC138\uC694",
177
182
  "context.actionDetail.planApprove": "plan.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
178
183
  "context.actionDetail.tasksWrite": "tasks.md\uB97C \uC791\uC131/\uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C \uC815\uB82C\uD558\uC138\uC694",
184
+ "context.actionDetail.tasksWriteCreate": "tasks.md\uB97C \uC0DD\uC131\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694",
185
+ "context.actionDetail.tasksWriteNeedAtLeastOne": "tasks.md\uC5D0 \uCD5C\uC18C 1\uAC1C \uC774\uC0C1\uC758 \uD0DC\uC2A4\uD06C\uB97C \uCD94\uAC00\uD558\uC138\uC694",
186
+ "context.actionDetail.tasksWriteImprove": "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C \uC815\uB82C\uD558\uC138\uC694",
179
187
  "context.actionDetail.tasksApprove": "tasks.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
180
188
  "context.actionDetail.issueCreate": "\uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 \uC774\uC288 \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
189
+ "context.actionDetail.issueCreateAndWrite": "\uC774\uC288 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC2B9\uC778(OK) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD574 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
190
+ "context.actionDetail.issueCreatePrepareFromDoc": "issue.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
191
+ "context.actionDetail.issueCreateFromDoc": "Ready \uC0C1\uD0DC issue.md\uB85C \uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
181
192
  "context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
182
193
  "context.actionDetail.reviewFixCommit": "\uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uB9CC\uB4DC\uC138\uC694",
183
194
  "context.actionDetail.prePrReview": "PR \uC804 \uB9AC\uBDF0\uB97C \uC218\uD589\uD558\uACE0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694",
184
195
  "context.actionDetail.prCreate": "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 PR \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
196
+ "context.actionDetail.prCreateRequiredSequence": "PR 2\uB2E8\uACC4(\uCD08\uC548/\uC2B9\uC778 \uD6C4 \uC0DD\uC131/\uB3D9\uAE30\uD654)\uB97C \uC21C\uC11C\uB300\uB85C \uC644\uB8CC\uD558\uC138\uC694",
197
+ "context.actionDetail.prCreatePrepareFromDoc": "pr.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
198
+ "context.actionDetail.prCreateExecuteFromDoc": "Ready \uC0C1\uD0DC pr.md\uB85C PR\uC744 \uC0DD\uC131\uD558\uACE0 \uB9C1\uD06C/\uC0C1\uD0DC\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
185
199
  "context.actionDetail.prStatusUpdate": "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C \uCD5C\uC2E0\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
200
+ "context.actionDetail.prStatusUpdateSetReview": "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694",
201
+ "context.actionDetail.prStatusUpdateSyncApproved": "\uC6D0\uACA9 \uBA38\uC9C0 \uC0C1\uD0DC\uB97C \uBC18\uC601\uD574 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
186
202
  "context.actionDetail.codeReview": "\uCF54\uB4DC \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D\uC744 \uBC18\uC601\uD558\uACE0 PR \uB9AC\uBDF0 \uC815\uBCF4\uB97C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
203
+ "context.actionDetail.codeReviewNeedEvidenceField": "tasks.md\uC5D0 PR \uB9AC\uBDF0 Evidence \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694",
204
+ "context.actionDetail.codeReviewNeedEvidence": "PR \uB9AC\uBDF0 Evidence \uC694\uC57D\uC744 \uAE30\uB85D\uD558\uC138\uC694",
205
+ "context.actionDetail.codeReviewNeedDecisionField": "tasks.md\uC5D0 PR \uB9AC\uBDF0 Decision \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694",
206
+ "context.actionDetail.codeReviewNeedDecision": "PR \uB9AC\uBDF0 Decision\uC744 \uAE30\uB85D\uD558\uC138\uC694",
207
+ "context.actionDetail.codeReviewResolve": "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uBC18\uC601\uD558\uACE0 PR \uB9AC\uBDF0 \uBB38\uC11C\uB97C \uCD5C\uC2E0\uD654\uD558\uC138\uC694",
208
+ "context.actionDetail.codeReviewNeedProjectRoot": "\uB9AC\uBDF0 \uC791\uC5C5\uC744 \uACC4\uC18D\uD558\uB824\uBA74 projectRoot\uB97C \uC124\uC815\uD558\uC138\uC694",
209
+ "context.actionDetail.codeReviewRemoteBlocked": "\uC6D0\uACA9 PR \uCC28\uB2E8 \uC0AC\uC720\uB97C \uD574\uC18C\uD55C \uB4A4 \uBA38\uC9C0\uB97C \uC9C4\uD589\uD558\uC138\uC694",
210
+ "context.actionDetail.codeReviewMergeAfterOk": "\uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 PR\uC744 \uBA38\uC9C0\uD558\uC138\uC694",
211
+ "context.actionDetail.codeReviewRequestReview": "\uB9AC\uBDF0 \uC694\uCCAD\uC744 \uC9C4\uD589\uD558\uACE0 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC720\uC9C0\uD558\uC138\uC694",
187
212
  "context.actionDetail.worktreeCleanup": "\uC644\uB8CC\uB41C feature worktree\uB97C \uC815\uB9AC\uD558\uC138\uC694",
188
213
  "context.actionDetail.prMetadataMigrate": "tasks.md\uC758 PR \uD56D\uBAA9 \uD615\uC2DD\uC744 \uCD5C\uC2E0 \uD15C\uD50C\uB9BF\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
214
+ "context.actionDetail.prMetadataMigratePrFields": "tasks.md\uC5D0 PR/PR \uC0C1\uD0DC \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694",
215
+ "context.actionDetail.prMetadataMigratePrePrReviewField": "tasks.md\uC5D0 PR \uC804 \uB9AC\uBDF0 \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694",
189
216
  "context.actionDetail.userRequestReplan": "\uC0C8 \uC0AC\uC6A9\uC790 \uC694\uAD6C\uB97C \uBA3C\uC800 \uBC18\uC601\uD55C \uB4A4 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
190
217
  "context.actionDetail.featureDone": "\uC774 Feature\uC758 \uC644\uB8CC \uC870\uAC74\uC774 \uBAA8\uB450 \uCDA9\uC871\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
191
218
  "context.actionDetail.fallback": "\uD604\uC7AC \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uB4A4 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
@@ -197,7 +224,7 @@ var ko = {
197
224
  "context.suggestion.showOpen": "\uC9C4\uD589 \uC911 Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
198
225
  "context.finalLabelCommandHint": "\uB77C\uBCA8\uC744 \uBC1B\uC73C\uBA74 \uC2B9\uC778 \uC120\uD0DD \uC2E4\uD589: {command}",
199
226
  "context.finalTicketCommandHint": "\uBA85\uB839 \uC2E4\uD589\uC740 \uC2B9\uC778 \uACB0\uACFC\uC758 \uD2F0\uCF13\uC73C\uB85C \uC2E4\uD589: {command}",
200
- "context.readBuiltinDocFirst": "\uC774\uBC88 \uC138\uC158\uC5D0 \uC544\uC9C1 \uC77D\uC9C0 \uC54A\uC558\uAC70\uB098 \uBCC0\uACBD \uAC00\uB2A5\uC131\uC774 \uC788\uC744 \uB54C\uB9CC \uD544\uC694\uD55C \uB0B4\uC7A5 \uBB38\uC11C\uB97C \uD655\uC778\uD558\uC138\uC694.",
227
+ "context.readBuiltinDocFirst": "\uC774\uBC88 \uC138\uC158\uC5D0 \uC544\uC9C1 \uC77D\uC9C0 \uC54A\uC558\uAC70\uB098 \uBCC0\uACBD \uAC00\uB2A5\uC131\uC774 \uC788\uC744 \uB54C\uB9CC \uD544\uC694\uD55C \uB0B4\uC7A5 \uBB38\uC11C\uB97C \uD655\uC778\uD558\uC138\uC694: {command}",
201
228
  "context.tipDocsCommitRules": "\uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uADDC\uCE59\uC740 git-workflow \uAC00\uC774\uB4DC\uB97C \uAE30\uC900\uC73C\uB85C \uD655\uC778\uD558\uC138\uC694.",
202
229
  "context.list.docsCommitNeeded": "\uBB38\uC11C \uCEE4\uBC0B \uD544\uC694",
203
230
  "context.list.projectCommitNeeded": "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B \uD544\uC694",
@@ -206,7 +233,6 @@ var ko = {
206
233
  "context.list.recordPrLink": "PR \uB9C1\uD06C \uAE30\uB85D",
207
234
  "context.list.addPrePrReviewField": "Pre-PR Review \uD544\uB4DC \uCD94\uAC00",
208
235
  "context.list.completePrePrReview": "Pre-PR \uB9AC\uBDF0 \uC644\uB8CC \uCC98\uB9AC",
209
- "context.list.addPrePrFindings": "Pre-PR Findings \uAE30\uB85D",
210
236
  "context.list.addPrePrEvidence": "Pre-PR Evidence \uADFC\uAC70 \uCD94\uAC00",
211
237
  "context.list.addPrePrDecision": "Pre-PR Decision \uAE30\uB85D",
212
238
  "context.list.resolvePrePrDecision": "Pre-PR Decision\uC744 approve\uB85C \uC815\uB9AC",
@@ -492,8 +518,8 @@ var ko = {
492
518
  worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
493
519
  tasksAllDoneButNoChecklist: '\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uC138\uC694. tasks.md\uC758 "\uC644\uB8CC \uC870\uAC74" \uC139\uC158\uC5D0 \uAC80\uC99D \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0, \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uC138\uC694. \uCD5C\uC885 \uC2B9\uC778(OK)\uB3C4 \uBC18\uC601\uD558\uC138\uC694.',
494
520
  tasksAllDoneButChecklist: "\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uC758 \uB0A8\uC740 \uD56D\uBAA9\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uD604\uC7AC \uC9C4\uD589: ({checked}/{total}) \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uACE0 \uCD5C\uC885 \uC2B9\uC778(OK)\uC744 \uBC18\uC601\uD558\uC138\uC694.",
495
- finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC218\uD589\uD558\uC138\uC694: "{title}" ({done}/{total}) \uC644\uB8CC \uC2DC \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC740 \uB4A4 DONE \uCC98\uB9AC',
496
- startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4: "{title}" ({done}/{total}) \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD) \uD6C4 DOING \uCC98\uB9AC',
521
+ finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC218\uD589\uD558\uC138\uC694: "{title}" ({done}/{total}) \uC644\uB8CC \uC2DC \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 DONE \uCC98\uB9AC',
522
+ startNextTodoTask: '\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4: "{title}" ({done}/{total}) \uC791\uC5C5\uC744 \uC2DC\uC791\uD558\uBA74 DOING \uCC98\uB9AC',
497
523
  checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total})",
498
524
  taskCommitGateStrictBlock: "\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB85C \uB118\uC5B4\uAC00\uAE30 \uC804\uC5D0 `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B` \uADDC\uCE59\uC744 \uCDA9\uC871\uD574\uC57C \uD569\uB2C8\uB2E4. \uC810\uAC80 \uACB0\uACFC: {reason}. \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694.",
499
525
  taskCommitGateWarnProceed: "\u26A0\uFE0F \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704 \uC810\uAC80 \uACBD\uACE0: {reason}. \uD604\uC7AC\uB294 \uC9C4\uD589 \uAC00\uB2A5\uD558\uC9C0\uB9CC `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B`\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
@@ -544,7 +570,6 @@ var ko = {
544
570
  legacyTasksDocStatusField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. `\uBB38\uC11C \uC0C1\uD0DC` \uD544\uB4DC(Draft/Review/Approved)\uB97C \uCD94\uAC00\uD574 \uD0DC\uC2A4\uD06C \uC2B9\uC778 \uB2E8\uACC4\uB97C \uD65C\uC131\uD654\uD558\uC138\uC694.",
545
571
  legacyTasksPrFields: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR` \uBC0F `PR \uC0C1\uD0DC` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
546
572
  legacyTasksPrePrReviewField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`)",
547
- legacyTasksPrePrFindingsField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Findings` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0 Findings**: major=0, minor=0`)",
548
573
  legacyTasksPrePrEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
549
574
  legacyTasksPrePrDecisionField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Decision` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0 Decision**: \uACB0\uC815: ...`)",
550
575
  legacyTasksPrReviewEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
@@ -563,10 +588,9 @@ var ko = {
563
588
  workflowPrRemoteChecksPending: "\uC6D0\uACA9 PR \uCCB4\uD06C \uB300\uAE30\uAC00 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCCB4\uD06C \uC644\uB8CC \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
564
589
  workflowPrePrReviewMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. (tasks.md\uC5D0 `- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`\uC744 \uCD94\uAC00\uD558\uC138\uC694.)",
565
590
  workflowPrePrReviewNotDone: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0`\uAC00 Done\uC774 \uC544\uB2D9\uB2C8\uB2E4. (\uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0 \uD6C4 Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
566
- workflowPrePrFindingsMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Findings`\uAC00 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`major=<n>, minor=<n>` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D)",
567
591
  workflowPrePrEvidenceMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (path_required \uC815\uCC45\uC774\uBA74 \uC2E4\uC81C \uC874\uC7AC\uD558\uB294 \uACBD\uB85C\uB97C \uAE30\uB85D\uD558\uC138\uC694.)",
568
592
  workflowPrePrDecisionMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`decision: approve|changes_requested|blocked ...` \uD615\uC2DD)",
569
- workflowPrePrDecisionNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{outcome}`\uC785\uB2C8\uB2E4. Findings\uB97C \uD574\uACB0\uD558\uACE0 pre-pr-review\uB97C \uC7AC\uC2E4\uD589\uD574 `approve`\uB85C \uB9DE\uCD94\uC138\uC694."
593
+ workflowPrePrDecisionNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{outcome}`\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB9AC\uC2A4\uD06C\uB97C \uD574\uC18C\uD55C \uB4A4 pre-pr-review\uB97C \uC7AC\uC2E4\uD589\uD574 `approve`\uB85C \uB9DE\uCD94\uC138\uC694."
570
594
  }
571
595
  };
572
596
  var ko_default = ko;
@@ -650,11 +674,16 @@ var en = {
650
674
  "context.suggestionHeader": "Suggested Next Options",
651
675
  "context.suggestionCommandHint": "Reference command: {command}",
652
676
  "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply with a format that includes a label token. (e.g. {example}, `A proceed`)",
677
+ "context.autoRunUnavailable": "Auto-run is not available in the current context.",
678
+ "context.autoRunSummary": "Run continuously by config until approval-required categories appear: {categories}",
679
+ "context.autoRunCommandHint": "Auto-run command (config-based gate): {command}",
680
+ "context.subAgentOrchestrationHint": "Main-agent orchestration: keep short steps in the main agent, and delegate only long-running loops (task_execute/code_review/review_fix_commit/pre_pr_review or auto mode) to a sub-agent.",
653
681
  "context.commandDetail.branchCreateWithWorktree": "({scope}) create or reuse worktree {worktree} for branch {branch}",
654
682
  "context.commandDetail.branchCreateWithBranch": "({scope}) create or reuse worktree for branch {branch}",
655
683
  "context.commandDetail.branchCreateGeneric": "({scope}) create or reuse feature branch worktree",
656
684
  "context.commandDetail.codeReviewMergeAfterOk": "({scope}) merge PR after explicit OK",
657
685
  "context.commandDetail.codeReviewPushFix": "({scope}) push review-fix commits",
686
+ "context.commandDetail.prePrReviewRun": "({scope}) run pre-PR review and sync decisions.md + tasks.md",
658
687
  "context.actionSummary.runDocsCommand": "Run docs command",
659
688
  "context.actionSummary.runProjectCommand": "Run project command",
660
689
  "context.actionDetail.featureFolder": "Prepare feature folder and baseline docs",
@@ -663,16 +692,38 @@ var en = {
663
692
  "context.actionDetail.planWrite": "Write or refine plan.md and set status",
664
693
  "context.actionDetail.planApprove": "Approve plan.md",
665
694
  "context.actionDetail.tasksWrite": "Write or refine tasks.md and align document status",
695
+ "context.actionDetail.tasksWriteCreate": "Create tasks.md and set Doc Status to Review",
696
+ "context.actionDetail.tasksWriteNeedAtLeastOne": "Add at least one task to tasks.md",
697
+ "context.actionDetail.tasksWriteImprove": "Refine tasks.md and align Doc Status",
666
698
  "context.actionDetail.tasksApprove": "Approve tasks.md",
667
699
  "context.actionDetail.issueCreate": "Create the issue and sync issue fields in tasks.md",
700
+ "context.actionDetail.issueCreateAndWrite": "Draft issue content, get explicit OK, then create and sync Issue",
701
+ "context.actionDetail.issueCreatePrepareFromDoc": "Refine issue.md draft and set Status to Ready",
702
+ "context.actionDetail.issueCreateFromDoc": "Create GitHub Issue from ready issue.md and sync Issue",
668
703
  "context.actionDetail.taskExecute": "Proceed with the current task",
669
704
  "context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
670
705
  "context.actionDetail.prePrReview": "Run pre-PR review and record results",
671
706
  "context.actionDetail.prCreate": "Create PR and sync PR fields in tasks.md",
707
+ "context.actionDetail.prCreateRequiredSequence": "Complete PR 2-step flow: prepare draft + OK, then create and sync",
708
+ "context.actionDetail.prCreatePrepareFromDoc": "Refine pr.md draft and set Status to Ready",
709
+ "context.actionDetail.prCreateExecuteFromDoc": "Create PR from ready pr.md and sync PR link/status",
672
710
  "context.actionDetail.prStatusUpdate": "Sync PR status in tasks.md with remote status",
711
+ "context.actionDetail.prStatusUpdateSetReview": "Set PR Status to Review",
712
+ "context.actionDetail.prStatusUpdateSyncApproved": "PR merged remotely; sync PR Status to Approved",
673
713
  "context.actionDetail.codeReview": "Address review feedback and update PR review fields",
714
+ "context.actionDetail.codeReviewNeedEvidenceField": "Add PR Review Evidence field in tasks.md",
715
+ "context.actionDetail.codeReviewNeedEvidence": "Record PR Review Evidence summary",
716
+ "context.actionDetail.codeReviewNeedDecisionField": "Add PR Review Decision field in tasks.md",
717
+ "context.actionDetail.codeReviewNeedDecision": "Record PR Review Decision",
718
+ "context.actionDetail.codeReviewResolve": "Address review feedback and keep PR review docs updated",
719
+ "context.actionDetail.codeReviewNeedProjectRoot": "Set projectRoot to continue review actions",
720
+ "context.actionDetail.codeReviewRemoteBlocked": "Resolve remote PR blockers before merge",
721
+ "context.actionDetail.codeReviewMergeAfterOk": "Merge PR after explicit OK",
722
+ "context.actionDetail.codeReviewRequestReview": "Request review and keep PR Status as Review",
674
723
  "context.actionDetail.worktreeCleanup": "Clean up the completed feature worktree",
675
724
  "context.actionDetail.prMetadataMigrate": "Update tasks.md PR fields to the latest template format",
725
+ "context.actionDetail.prMetadataMigratePrFields": "Update tasks.md with PR/PR Status fields",
726
+ "context.actionDetail.prMetadataMigratePrePrReviewField": "Add Pre-PR Review field in tasks.md",
676
727
  "context.actionDetail.userRequestReplan": "Handle the new user request first and re-run context",
677
728
  "context.actionDetail.featureDone": "All completion checks are satisfied for this feature",
678
729
  "context.actionDetail.fallback": "Verify current status and re-run context",
@@ -684,7 +735,7 @@ var en = {
684
735
  "context.suggestion.showOpen": "Show open features",
685
736
  "context.finalLabelCommandHint": "When a label is provided, run approval selection: {command}",
686
737
  "context.finalTicketCommandHint": "Execute commands using the ticket from approval result: {command}",
687
- "context.readBuiltinDocFirst": "Read required built-in docs only if not read in this session yet or likely changed.",
738
+ "context.readBuiltinDocFirst": "Read required built-in docs only if not read in this session yet or likely changed: {command}",
688
739
  "context.tipDocsCommitRules": "Check commit message rules against the git-workflow guide.",
689
740
  "context.list.docsCommitNeeded": "Commit docs changes",
690
741
  "context.list.projectCommitNeeded": "Commit project code changes",
@@ -693,7 +744,6 @@ var en = {
693
744
  "context.list.recordPrLink": "Record PR link",
694
745
  "context.list.addPrePrReviewField": "Add Pre-PR Review field",
695
746
  "context.list.completePrePrReview": "Complete Pre-PR review",
696
- "context.list.addPrePrFindings": "Record Pre-PR Findings",
697
747
  "context.list.addPrePrEvidence": "Add Pre-PR Evidence",
698
748
  "context.list.addPrePrDecision": "Add Pre-PR Decision",
699
749
  "context.list.resolvePrePrDecision": "Resolve Pre-PR decision to approve",
@@ -979,8 +1029,8 @@ var en = {
979
1029
  worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
980
1030
  tasksAllDoneButNoChecklist: 'Create the completion checklist. Add verification items to the tasks.md "Completion Criteria" section, then mark satisfied items as [x] after user confirmation. Record final approval (OK) as well.',
981
1031
  tasksAllDoneButChecklist: "Proceed with remaining completion checklist items. Current progress: ({checked}/{total}) Mark items as [x] only after user confirmation and real verification. Record final approval (OK) as well.",
982
- finishDoingTask: 'Continue working on the current DOING/REVIEW task: "{title}" ({done}/{total}) After it is complete, share outcome/verification and get approval before marking DONE',
983
- startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) Get approval (`A` or `A OK`) before marking DOING',
1032
+ finishDoingTask: 'Continue working on the current DOING/REVIEW task: "{title}" ({done}/{total}) After it is complete, share outcome/verification and mark it DONE',
1033
+ startNextTodoTask: 'Start the next TODO task: "{title}" ({done}/{total}) Mark it DOING when you begin work',
984
1034
  checkTaskStatuses: "Check task statuses. ({done}/{total})",
985
1035
  taskCommitGateStrictBlock: "Before moving to the next TODO task, you must satisfy the `1 task = 1 commit` rule. Check result: {reason}. Re-align task commit boundaries, then continue.",
986
1036
  taskCommitGateWarnProceed: "\u26A0\uFE0F Task commit boundary warning: {reason}. You may continue, but `1 task = 1 commit` is recommended.",
@@ -1031,7 +1081,6 @@ var en = {
1031
1081
  legacyTasksDocStatusField: "Legacy tasks.md format detected. Add a `Doc Status` field (Draft/Review/Approved) to enable tasks approval.",
1032
1082
  legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
1033
1083
  legacyTasksPrePrReviewField: "Legacy tasks.md format detected. Add `Pre-PR Review` before PR steps. (`- **Pre-PR Review**: Pending | Done`)",
1034
- legacyTasksPrePrFindingsField: "Legacy tasks.md format detected. Add `Pre-PR Findings` before PR steps. (`- **Pre-PR Findings**: major=0, minor=0`)",
1035
1084
  legacyTasksPrePrEvidenceField: "Legacy tasks.md format detected. Add `Pre-PR Evidence` before PR steps.",
1036
1085
  legacyTasksPrePrDecisionField: "Legacy tasks.md format detected. Add `Pre-PR Decision` before PR steps. (`- **Pre-PR Decision**: decision: ...`)",
1037
1086
  legacyTasksPrReviewEvidenceField: "Legacy tasks.md format detected. Add `PR Review Evidence` before review iteration.",
@@ -1050,10 +1099,9 @@ var en = {
1050
1099
  workflowPrRemoteChecksPending: "Remote PR has {count} pending check(s). Wait for checks to complete, then re-check.",
1051
1100
  workflowPrePrReviewMissing: "Implementation is done but `Pre-PR Review` is missing. (Add `- **Pre-PR Review**: Pending | Done` in tasks.md.)",
1052
1101
  workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)",
1053
- workflowPrePrFindingsMissing: "Implementation is done but `Pre-PR Findings` is missing/invalid. (Use `major=<n>, minor=<n>`.)",
1054
1102
  workflowPrePrEvidenceMissing: "Implementation is done but `Pre-PR Evidence` is empty/invalid. (Record a real existing path when path_required policy is enabled.)",
1055
1103
  workflowPrePrDecisionMissing: "Implementation is done but `Pre-PR Decision` is empty/invalid. (Use `decision: approve|changes_requested|blocked ...`.)",
1056
- workflowPrePrDecisionNotApproved: "Implementation is done but `Pre-PR Decision` is `{outcome}`. Resolve findings and re-run pre-PR review until decision becomes `approve`."
1104
+ workflowPrePrDecisionNotApproved: "Implementation is done but `Pre-PR Decision` is `{outcome}`. Resolve review risks and re-run pre-PR review until decision becomes `approve`."
1057
1105
  }
1058
1106
  };
1059
1107
  var en_default = en;
@@ -1479,10 +1527,10 @@ var DEFAULT_STALE_MS = 2 * 6e4;
1479
1527
  var RUNTIME_GIT_DIRNAME = "lee-spec-kit.runtime";
1480
1528
  var RUNTIME_TEMP_DIRNAME = "lee-spec-kit-runtime";
1481
1529
  function toScopeKey(value) {
1482
- return createHash("sha1").update(path22.resolve(value)).digest("hex").slice(0, 16);
1530
+ return createHash("sha1").update(path23.resolve(value)).digest("hex").slice(0, 16);
1483
1531
  }
1484
1532
  function getTempRuntimeDir(scopePath) {
1485
- return path22.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1533
+ return path23.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1486
1534
  }
1487
1535
  function resolveGitRuntimeDir(cwd) {
1488
1536
  try {
@@ -1496,42 +1544,42 @@ function resolveGitRuntimeDir(cwd) {
1496
1544
  }
1497
1545
  ).trim();
1498
1546
  if (!out) return null;
1499
- return path22.isAbsolute(out) ? out : path22.resolve(cwd, out);
1547
+ return path23.isAbsolute(out) ? out : path23.resolve(cwd, out);
1500
1548
  } catch {
1501
1549
  return null;
1502
1550
  }
1503
1551
  }
1504
1552
  function getRuntimeStateDir(cwd) {
1505
- const resolved = path22.resolve(cwd);
1553
+ const resolved = path23.resolve(cwd);
1506
1554
  return resolveGitRuntimeDir(resolved) ?? getTempRuntimeDir(resolved);
1507
1555
  }
1508
1556
  function getDocsLockPath(docsDir) {
1509
- return path22.join(
1557
+ return path23.join(
1510
1558
  getRuntimeStateDir(docsDir),
1511
1559
  "locks",
1512
1560
  `docs-${toScopeKey(docsDir)}.lock`
1513
1561
  );
1514
1562
  }
1515
1563
  function getInitLockPath(targetDir) {
1516
- return path22.join(
1517
- getRuntimeStateDir(path22.dirname(path22.resolve(targetDir))),
1564
+ return path23.join(
1565
+ getRuntimeStateDir(path23.dirname(path23.resolve(targetDir))),
1518
1566
  "locks",
1519
1567
  `init-${toScopeKey(targetDir)}.lock`
1520
1568
  );
1521
1569
  }
1522
1570
  function getApprovalTicketStorePath(docsDir) {
1523
- return path22.join(
1571
+ return path23.join(
1524
1572
  getRuntimeStateDir(docsDir),
1525
1573
  "tickets",
1526
1574
  `approval-${toScopeKey(docsDir)}.json`
1527
1575
  );
1528
1576
  }
1529
1577
  function getProjectExecutionLockPath(cwd) {
1530
- return path22.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1578
+ return path23.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1531
1579
  }
1532
1580
  async function isStaleLock(lockPath, staleMs) {
1533
1581
  try {
1534
- const stat = await fs16.stat(lockPath);
1582
+ const stat = await fs17.stat(lockPath);
1535
1583
  if (Date.now() - stat.mtimeMs <= staleMs) {
1536
1584
  return false;
1537
1585
  }
@@ -1546,7 +1594,7 @@ async function isStaleLock(lockPath, staleMs) {
1546
1594
  }
1547
1595
  async function readLockPayload(lockPath) {
1548
1596
  try {
1549
- const raw = await fs16.readFile(lockPath, "utf8");
1597
+ const raw = await fs17.readFile(lockPath, "utf8");
1550
1598
  const parsed = JSON.parse(raw);
1551
1599
  if (!parsed || typeof parsed !== "object") return null;
1552
1600
  return parsed;
@@ -1568,17 +1616,17 @@ function isProcessAlive(pid) {
1568
1616
  }
1569
1617
  }
1570
1618
  async function tryAcquire(lockPath, owner) {
1571
- await fs16.ensureDir(path22.dirname(lockPath));
1619
+ await fs17.ensureDir(path23.dirname(lockPath));
1572
1620
  try {
1573
- const fd = await fs16.open(lockPath, "wx");
1621
+ const fd = await fs17.open(lockPath, "wx");
1574
1622
  const payload = JSON.stringify(
1575
1623
  { pid: process.pid, owner: owner ?? "unknown", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
1576
1624
  null,
1577
1625
  2
1578
1626
  );
1579
- await fs16.writeFile(fd, `${payload}
1627
+ await fs17.writeFile(fd, `${payload}
1580
1628
  `, { encoding: "utf8" });
1581
- await fs16.close(fd);
1629
+ await fs17.close(fd);
1582
1630
  return true;
1583
1631
  } catch (error) {
1584
1632
  if (error.code === "EEXIST") {
@@ -1592,9 +1640,9 @@ async function waitForLockRelease(lockPath, options = {}) {
1592
1640
  const pollMs = options.pollMs ?? DEFAULT_POLL_MS;
1593
1641
  const staleMs = options.staleMs ?? DEFAULT_STALE_MS;
1594
1642
  const startedAt = Date.now();
1595
- while (await fs16.pathExists(lockPath)) {
1643
+ while (await fs17.pathExists(lockPath)) {
1596
1644
  if (await isStaleLock(lockPath, staleMs)) {
1597
- await fs16.remove(lockPath);
1645
+ await fs17.remove(lockPath);
1598
1646
  break;
1599
1647
  }
1600
1648
  if (Date.now() - startedAt > timeoutMs) {
@@ -1612,7 +1660,7 @@ async function withFileLock(lockPath, task, options = {}) {
1612
1660
  const acquired = await tryAcquire(lockPath, options.owner);
1613
1661
  if (acquired) break;
1614
1662
  if (await isStaleLock(lockPath, staleMs)) {
1615
- await fs16.remove(lockPath);
1663
+ await fs17.remove(lockPath);
1616
1664
  continue;
1617
1665
  }
1618
1666
  if (Date.now() - startedAt > timeoutMs) {
@@ -1626,7 +1674,7 @@ async function withFileLock(lockPath, task, options = {}) {
1626
1674
  try {
1627
1675
  return await task();
1628
1676
  } finally {
1629
- await fs16.remove(lockPath).catch(() => {
1677
+ await fs17.remove(lockPath).catch(() => {
1630
1678
  });
1631
1679
  }
1632
1680
  }
@@ -1645,30 +1693,30 @@ var ENGINE_MANAGED_AGENT_FILES = [
1645
1693
  "pr-template.md"
1646
1694
  ];
1647
1695
  var ENGINE_MANAGED_AGENT_DIRS = ["skills"];
1648
- var ENGINE_MANAGED_FEATURE_PATH = path22.join(
1696
+ var ENGINE_MANAGED_FEATURE_PATH = path23.join(
1649
1697
  "features",
1650
1698
  "feature-base"
1651
1699
  );
1652
1700
  async function pruneEngineManagedDocs(docsDir) {
1653
1701
  const removed = [];
1654
1702
  for (const file of ENGINE_MANAGED_AGENT_FILES) {
1655
- const target = path22.join(docsDir, "agents", file);
1656
- if (await fs16.pathExists(target)) {
1657
- await fs16.remove(target);
1658
- removed.push(path22.relative(docsDir, target));
1703
+ const target = path23.join(docsDir, "agents", file);
1704
+ if (await fs17.pathExists(target)) {
1705
+ await fs17.remove(target);
1706
+ removed.push(path23.relative(docsDir, target));
1659
1707
  }
1660
1708
  }
1661
1709
  for (const dir of ENGINE_MANAGED_AGENT_DIRS) {
1662
- const target = path22.join(docsDir, "agents", dir);
1663
- if (await fs16.pathExists(target)) {
1664
- await fs16.remove(target);
1665
- removed.push(path22.relative(docsDir, target));
1710
+ const target = path23.join(docsDir, "agents", dir);
1711
+ if (await fs17.pathExists(target)) {
1712
+ await fs17.remove(target);
1713
+ removed.push(path23.relative(docsDir, target));
1666
1714
  }
1667
1715
  }
1668
- const featureBasePath = path22.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1669
- if (await fs16.pathExists(featureBasePath)) {
1670
- await fs16.remove(featureBasePath);
1671
- removed.push(path22.relative(docsDir, featureBasePath));
1716
+ const featureBasePath = path23.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1717
+ if (await fs17.pathExists(featureBasePath)) {
1718
+ await fs17.remove(featureBasePath);
1719
+ removed.push(path23.relative(docsDir, featureBasePath));
1672
1720
  }
1673
1721
  return removed;
1674
1722
  }
@@ -1825,7 +1873,7 @@ ${tr(lang2, "cli", "common.canceled")}`)
1825
1873
  }
1826
1874
  async function runInit(options) {
1827
1875
  const cwd = process.cwd();
1828
- const defaultName = path22.basename(cwd);
1876
+ const defaultName = path23.basename(cwd);
1829
1877
  let projectName = options.name || defaultName;
1830
1878
  let projectType = options.type;
1831
1879
  let components = parseComponentsOption(options.components);
@@ -1836,7 +1884,7 @@ async function runInit(options) {
1836
1884
  let docsRemote = options.docsRemote;
1837
1885
  let projectRoot;
1838
1886
  const componentProjectRoots = options.componentProjectRoots ? parseComponentProjectRootsOption(options.componentProjectRoots) : {};
1839
- const targetDir = path22.resolve(cwd, options.dir || "./docs");
1887
+ const targetDir = path23.resolve(cwd, options.dir || "./docs");
1840
1888
  const skipPrompts = !!options.yes || !!options.nonInteractive;
1841
1889
  if (options.docsRepo && !["embedded", "standalone"].includes(options.docsRepo)) {
1842
1890
  throw createCliError(
@@ -2188,8 +2236,8 @@ async function runInit(options) {
2188
2236
  await withFileLock(
2189
2237
  initLockPath,
2190
2238
  async () => {
2191
- if (await fs16.pathExists(targetDir)) {
2192
- const files = await fs16.readdir(targetDir);
2239
+ if (await fs17.pathExists(targetDir)) {
2240
+ const files = await fs17.readdir(targetDir);
2193
2241
  if (files.length > 0) {
2194
2242
  if (options.force) {
2195
2243
  } else if (options.nonInteractive) {
@@ -2225,21 +2273,21 @@ async function runInit(options) {
2225
2273
  );
2226
2274
  console.log();
2227
2275
  const templatesDir = getTemplatesDir();
2228
- const commonPath = path22.join(templatesDir, lang, "common");
2229
- if (!await fs16.pathExists(commonPath)) {
2276
+ const commonPath = path23.join(templatesDir, lang, "common");
2277
+ if (!await fs17.pathExists(commonPath)) {
2230
2278
  throw new Error(
2231
2279
  tr(lang, "cli", "init.error.templateNotFound", { path: commonPath })
2232
2280
  );
2233
2281
  }
2234
2282
  await copyTemplates(commonPath, targetDir);
2235
2283
  if (projectType === "multi") {
2236
- const featuresRoot = path22.join(targetDir, "features");
2284
+ const featuresRoot = path23.join(targetDir, "features");
2237
2285
  for (const component of components) {
2238
- const componentDir = path22.join(featuresRoot, component);
2239
- await fs16.ensureDir(componentDir);
2240
- const readmePath = path22.join(componentDir, "README.md");
2241
- if (!await fs16.pathExists(readmePath)) {
2242
- await fs16.writeFile(
2286
+ const componentDir = path23.join(featuresRoot, component);
2287
+ await fs17.ensureDir(componentDir);
2288
+ const readmePath = path23.join(componentDir, "README.md");
2289
+ if (!await fs17.pathExists(readmePath)) {
2290
+ await fs17.writeFile(
2243
2291
  readmePath,
2244
2292
  getComponentFeaturesReadme(lang, component),
2245
2293
  "utf-8"
@@ -2274,7 +2322,6 @@ async function runInit(options) {
2274
2322
  skills: ["code-review-excellence"],
2275
2323
  fallback: "builtin-checklist",
2276
2324
  evidenceMode: "path_required",
2277
- findings: "required",
2278
2325
  decisionEnum: ["approve", "changes_requested", "blocked"]
2279
2326
  }
2280
2327
  },
@@ -2296,8 +2343,8 @@ async function runInit(options) {
2296
2343
  config.projectRoot = projectRoot;
2297
2344
  }
2298
2345
  }
2299
- const configPath = path22.join(targetDir, ".lee-spec-kit.json");
2300
- await fs16.writeJson(configPath, config, { spaces: 2 });
2346
+ const configPath = path23.join(targetDir, ".lee-spec-kit.json");
2347
+ await fs17.writeJson(configPath, config, { spaces: 2 });
2301
2348
  console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
2302
2349
  console.log();
2303
2350
  await initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote);
@@ -2360,7 +2407,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2360
2407
  console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
2361
2408
  runGitOrThrow(["init"], gitWorkdir);
2362
2409
  }
2363
- const relativePath = docsRepo === "standalone" ? "." : path22.relative(cwd, targetDir);
2410
+ const relativePath = docsRepo === "standalone" ? "." : path23.relative(cwd, targetDir);
2364
2411
  const stagedBeforeAdd = getCachedStagedFiles(gitWorkdir);
2365
2412
  if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
2366
2413
  console.log(
@@ -2417,17 +2464,17 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2417
2464
  }
2418
2465
  function getAncestorDirs(startDir) {
2419
2466
  const dirs = [];
2420
- let current = path22.resolve(startDir);
2467
+ let current = path23.resolve(startDir);
2421
2468
  while (true) {
2422
2469
  dirs.push(current);
2423
- const parent = path22.dirname(current);
2470
+ const parent = path23.dirname(current);
2424
2471
  if (parent === current) break;
2425
2472
  current = parent;
2426
2473
  }
2427
2474
  return dirs;
2428
2475
  }
2429
2476
  function hasWorkspaceBoundary(dir) {
2430
- return fs16.existsSync(path22.join(dir, "package.json")) || fs16.existsSync(path22.join(dir, ".git"));
2477
+ return fs17.existsSync(path23.join(dir, "package.json")) || fs17.existsSync(path23.join(dir, ".git"));
2431
2478
  }
2432
2479
  function getSearchBaseDirs(cwd) {
2433
2480
  const ancestors = getAncestorDirs(cwd);
@@ -2443,9 +2490,9 @@ function normalizeComponentKeys(value) {
2443
2490
  return Object.keys(value).map((key) => key.trim().toLowerCase()).filter(Boolean);
2444
2491
  }
2445
2492
  async function inferComponentsFromFeaturesDir(docsDir) {
2446
- const featuresPath = path22.join(docsDir, "features");
2447
- if (!await fs16.pathExists(featuresPath)) return [];
2448
- const entries = await fs16.readdir(featuresPath, { withFileTypes: true });
2493
+ const featuresPath = path23.join(docsDir, "features");
2494
+ if (!await fs17.pathExists(featuresPath)) return [];
2495
+ const entries = await fs17.readdir(featuresPath, { withFileTypes: true });
2449
2496
  const inferred = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name.trim().toLowerCase()).filter(
2450
2497
  (name) => !!name && name !== "feature-base" && !FEATURE_FOLDER_PATTERN.test(name)
2451
2498
  );
@@ -2454,24 +2501,24 @@ async function inferComponentsFromFeaturesDir(docsDir) {
2454
2501
  async function getConfig(cwd) {
2455
2502
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2456
2503
  const baseDirs = [
2457
- ...explicitDocsDir ? [path22.resolve(explicitDocsDir)] : [],
2504
+ ...explicitDocsDir ? [path23.resolve(explicitDocsDir)] : [],
2458
2505
  ...getSearchBaseDirs(cwd)
2459
2506
  ];
2460
2507
  const visitedBaseDirs = /* @__PURE__ */ new Set();
2461
2508
  const visitedDocsDirs = /* @__PURE__ */ new Set();
2462
2509
  for (const baseDir of baseDirs) {
2463
- const resolvedBaseDir = path22.resolve(baseDir);
2510
+ const resolvedBaseDir = path23.resolve(baseDir);
2464
2511
  if (visitedBaseDirs.has(resolvedBaseDir)) continue;
2465
2512
  visitedBaseDirs.add(resolvedBaseDir);
2466
- const possibleDocsDirs = [path22.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2513
+ const possibleDocsDirs = [path23.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2467
2514
  for (const docsDir of possibleDocsDirs) {
2468
- const resolvedDocsDir = path22.resolve(docsDir);
2515
+ const resolvedDocsDir = path23.resolve(docsDir);
2469
2516
  if (visitedDocsDirs.has(resolvedDocsDir)) continue;
2470
2517
  visitedDocsDirs.add(resolvedDocsDir);
2471
- const configPath = path22.join(resolvedDocsDir, ".lee-spec-kit.json");
2472
- if (await fs16.pathExists(configPath)) {
2518
+ const configPath = path23.join(resolvedDocsDir, ".lee-spec-kit.json");
2519
+ if (await fs17.pathExists(configPath)) {
2473
2520
  try {
2474
- const configFile = await fs16.readJson(configPath);
2521
+ const configFile = await fs17.readJson(configPath);
2475
2522
  const projectType = normalizeProjectType(configFile.projectType);
2476
2523
  const inferredComponents = [
2477
2524
  ...normalizeComponentKeys(configFile.projectRoot),
@@ -2498,21 +2545,21 @@ async function getConfig(cwd) {
2498
2545
  } catch {
2499
2546
  }
2500
2547
  }
2501
- const agentsPath = path22.join(resolvedDocsDir, "agents");
2502
- const featuresPath = path22.join(resolvedDocsDir, "features");
2503
- if (await fs16.pathExists(agentsPath) && await fs16.pathExists(featuresPath)) {
2548
+ const agentsPath = path23.join(resolvedDocsDir, "agents");
2549
+ const featuresPath = path23.join(resolvedDocsDir, "features");
2550
+ if (await fs17.pathExists(agentsPath) && await fs17.pathExists(featuresPath)) {
2504
2551
  const inferredComponents = await inferComponentsFromFeaturesDir(resolvedDocsDir);
2505
2552
  const projectType = inferredComponents.length > 0 ? "multi" : "single";
2506
2553
  const components = projectType === "multi" ? resolveProjectComponents("multi", inferredComponents) : void 0;
2507
2554
  const langProbeCandidates = [
2508
- path22.join(agentsPath, "custom.md"),
2509
- path22.join(agentsPath, "constitution.md"),
2510
- path22.join(agentsPath, "agents.md")
2555
+ path23.join(agentsPath, "custom.md"),
2556
+ path23.join(agentsPath, "constitution.md"),
2557
+ path23.join(agentsPath, "agents.md")
2511
2558
  ];
2512
2559
  let lang = "en";
2513
2560
  for (const candidate of langProbeCandidates) {
2514
- if (!await fs16.pathExists(candidate)) continue;
2515
- const content = await fs16.readFile(candidate, "utf-8");
2561
+ if (!await fs17.pathExists(candidate)) continue;
2562
+ const content = await fs17.readFile(candidate, "utf-8");
2516
2563
  if (/[가-힣]/.test(content)) {
2517
2564
  lang = "ko";
2518
2565
  break;
@@ -2547,7 +2594,7 @@ function sanitizeTasksForLocal(content, lang) {
2547
2594
  )) {
2548
2595
  continue;
2549
2596
  }
2550
- if (/^\s*-\s*\*\*(Pre-PR Findings|Pre-PR Evidence|PR 전 리뷰 Findings|PR 전 리뷰 Evidence)\*\*\s*:/.test(
2597
+ if (/^\s*-\s*\*\*(Pre-PR Evidence|PR 전 리뷰 Evidence)\*\*\s*:/.test(
2551
2598
  line
2552
2599
  )) {
2553
2600
  continue;
@@ -2561,8 +2608,6 @@ function sanitizeTasksForLocal(content, lang) {
2561
2608
  if (/^\s*-\s*(예|값)\s*:/.test(line)) continue;
2562
2609
  if (/^\s*-\s*Mark\s+`?Done`?/i.test(line)) continue;
2563
2610
  if (/^\s*-\s*사전 코드리뷰 완료 후/.test(line)) continue;
2564
- if (/^\s*-\s*Update with final findings counts from pre-PR review/i.test(line))
2565
- continue;
2566
2611
  if (/^\s*-\s*Record your key review decision/i.test(line)) continue;
2567
2612
  if (/^\s*-\s*사전 리뷰 주요 판단 근거를/.test(line)) continue;
2568
2613
  if (/^\s*-\s*Example:\s*review note link/i.test(line)) continue;
@@ -2575,18 +2620,18 @@ function sanitizeTasksForLocal(content, lang) {
2575
2620
  return normalizeTrailingBlankLines(next);
2576
2621
  }
2577
2622
  async function patchMarkdownIfExists(filePath, transform) {
2578
- if (!await fs16.pathExists(filePath)) return;
2579
- const content = await fs16.readFile(filePath, "utf-8");
2580
- await fs16.writeFile(filePath, transform(content), "utf-8");
2623
+ if (!await fs17.pathExists(filePath)) return;
2624
+ const content = await fs17.readFile(filePath, "utf-8");
2625
+ await fs17.writeFile(filePath, transform(content), "utf-8");
2581
2626
  }
2582
2627
  async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
2583
- await patchMarkdownIfExists(path22.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2628
+ await patchMarkdownIfExists(path23.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2584
2629
  await patchMarkdownIfExists(
2585
- path22.join(featureDir, "tasks.md"),
2630
+ path23.join(featureDir, "tasks.md"),
2586
2631
  (content) => sanitizeTasksForLocal(content, lang)
2587
2632
  );
2588
- await fs16.remove(path22.join(featureDir, "issue.md"));
2589
- await fs16.remove(path22.join(featureDir, "pr.md"));
2633
+ await fs17.remove(path23.join(featureDir, "issue.md"));
2634
+ await fs17.remove(path23.join(featureDir, "pr.md"));
2590
2635
  }
2591
2636
 
2592
2637
  // src/commands/feature.ts
@@ -2733,29 +2778,29 @@ async function runFeature(name, options) {
2733
2778
  }
2734
2779
  let featuresDir;
2735
2780
  if (projectType === "multi") {
2736
- featuresDir = path22.join(docsDir, "features", component);
2781
+ featuresDir = path23.join(docsDir, "features", component);
2737
2782
  } else {
2738
- featuresDir = path22.join(docsDir, "features");
2783
+ featuresDir = path23.join(docsDir, "features");
2739
2784
  }
2740
2785
  const featureFolderName = `${featureId}-${name}`;
2741
- const featureDir = path22.join(featuresDir, featureFolderName);
2742
- if (await fs16.pathExists(featureDir)) {
2786
+ const featureDir = path23.join(featuresDir, featureFolderName);
2787
+ if (await fs17.pathExists(featureDir)) {
2743
2788
  throw createCliError(
2744
2789
  "INVALID_ARGUMENT",
2745
2790
  tr(lang, "cli", "feature.folderExists", { path: featureDir })
2746
2791
  );
2747
2792
  }
2748
- const featureBasePath = path22.join(
2793
+ const featureBasePath = path23.join(
2749
2794
  getTemplatesDir(),
2750
2795
  lang,
2751
2796
  "common",
2752
2797
  "features",
2753
2798
  "feature-base"
2754
2799
  );
2755
- if (!await fs16.pathExists(featureBasePath)) {
2800
+ if (!await fs17.pathExists(featureBasePath)) {
2756
2801
  throw createCliError("DOCS_NOT_FOUND", tr(lang, "cli", "feature.baseNotFound"));
2757
2802
  }
2758
- await fs16.copy(featureBasePath, featureDir);
2803
+ await fs17.copy(featureBasePath, featureDir);
2759
2804
  const idNumber = featureId.replace("F", "");
2760
2805
  const repoName = projectType === "multi" ? `{{projectName}}-${component}` : "{{projectName}}";
2761
2806
  const replacements = {
@@ -2804,7 +2849,7 @@ async function runFeature(name, options) {
2804
2849
  featureName: name,
2805
2850
  component: projectType === "multi" ? component : void 0,
2806
2851
  featurePath: featureDir,
2807
- featurePathFromDocs: path22.relative(docsDir, featureDir)
2852
+ featurePathFromDocs: path23.relative(docsDir, featureDir)
2808
2853
  };
2809
2854
  },
2810
2855
  { owner: "feature" }
@@ -2813,9 +2858,9 @@ async function runFeature(name, options) {
2813
2858
  async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2814
2859
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2815
2860
  const candidates = [
2816
- ...explicitDocsDir ? [path22.resolve(explicitDocsDir)] : [],
2817
- path22.resolve(cwd, "docs"),
2818
- path22.resolve(cwd)
2861
+ ...explicitDocsDir ? [path23.resolve(explicitDocsDir)] : [],
2862
+ path23.resolve(cwd, "docs"),
2863
+ path23.resolve(cwd)
2819
2864
  ];
2820
2865
  const endAt = Date.now() + timeoutMs;
2821
2866
  while (Date.now() < endAt) {
@@ -2826,7 +2871,7 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2826
2871
  const initLockPath = getInitLockPath(dir);
2827
2872
  const docsLockPath = getDocsLockPath(dir);
2828
2873
  for (const lockPath of [initLockPath, docsLockPath]) {
2829
- if (await fs16.pathExists(lockPath)) {
2874
+ if (await fs17.pathExists(lockPath)) {
2830
2875
  sawLock = true;
2831
2876
  await waitForLockRelease(lockPath, {
2832
2877
  timeoutMs: Math.max(200, endAt - Date.now()),
@@ -2842,17 +2887,17 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2842
2887
  return getConfig(cwd);
2843
2888
  }
2844
2889
  async function getNextFeatureId(docsDir, projectType, components) {
2845
- const featuresDir = path22.join(docsDir, "features");
2890
+ const featuresDir = path23.join(docsDir, "features");
2846
2891
  let max = 0;
2847
2892
  const scanDirs = [];
2848
2893
  if (projectType === "multi") {
2849
- scanDirs.push(...components.map((component) => path22.join(featuresDir, component)));
2894
+ scanDirs.push(...components.map((component) => path23.join(featuresDir, component)));
2850
2895
  } else {
2851
2896
  scanDirs.push(featuresDir);
2852
2897
  }
2853
2898
  for (const dir of scanDirs) {
2854
- if (!await fs16.pathExists(dir)) continue;
2855
- const entries = await fs16.readdir(dir, { withFileTypes: true });
2899
+ if (!await fs17.pathExists(dir)) continue;
2900
+ const entries = await fs17.readdir(dir, { withFileTypes: true });
2856
2901
  for (const entry of entries) {
2857
2902
  if (!entry.isDirectory()) continue;
2858
2903
  const match = entry.name.match(/^F(\d+)-/);
@@ -2994,7 +3039,6 @@ function resolvePrePrReviewPolicy(workflow) {
2994
3039
  skills: configuredSkills.length > 0 ? configuredSkills : DEFAULT_PRE_PR_REVIEW_SKILLS,
2995
3040
  fallback: configured?.fallback === "builtin-checklist" ? configured.fallback : "builtin-checklist",
2996
3041
  evidenceMode: configured?.evidenceMode === "any" ? "any" : "path_required",
2997
- findings: configured?.findings === "optional" ? "optional" : "required",
2998
3042
  decisionEnum: configuredDecisionEnum.length > 0 ? configuredDecisionEnum : DEFAULT_PRE_PR_DECISION_ENUM
2999
3043
  };
3000
3044
  }
@@ -3023,9 +3067,6 @@ function isPrePrReviewSatisfied(feature, prePrReviewPolicy) {
3023
3067
  if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
3024
3068
  return false;
3025
3069
  }
3026
- if (prePrReviewPolicy.findings === "required" && (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findingsProvided)) {
3027
- return false;
3028
- }
3029
3070
  if (!feature.docs.prePrDecisionFieldExists || !feature.prePrReview.decisionProvided) {
3030
3071
  return false;
3031
3072
  }
@@ -3095,8 +3136,8 @@ function resolveProjectCommitTopic(feature) {
3095
3136
  }
3096
3137
  function resolveManagedWorktreeCleanupPaths(projectGitCwd) {
3097
3138
  if (!projectGitCwd) return null;
3098
- const normalized = path22.resolve(projectGitCwd);
3099
- const marker = `${path22.sep}.worktrees${path22.sep}`;
3139
+ const normalized = path23.resolve(projectGitCwd);
3140
+ const marker = `${path23.sep}.worktrees${path23.sep}`;
3100
3141
  const markerIndex = normalized.lastIndexOf(marker);
3101
3142
  if (markerIndex <= 0) return null;
3102
3143
  const projectRoot = normalized.slice(0, markerIndex);
@@ -3140,7 +3181,7 @@ function toTaskKey(rawTitle) {
3140
3181
  function countDoneTransitionsInLatestTasksCommit(feature) {
3141
3182
  const docsGitCwd = feature.git.docsGitCwd;
3142
3183
  const tasksRelativePath = normalizeGitRelativePath(
3143
- path22.join(feature.docs.featurePathFromDocs, "tasks.md")
3184
+ path23.join(feature.docs.featurePathFromDocs, "tasks.md")
3144
3185
  );
3145
3186
  const diff = readGitText(docsGitCwd, [
3146
3187
  "diff",
@@ -3213,7 +3254,7 @@ function checkTaskCommitGate(feature) {
3213
3254
  return { pass: true };
3214
3255
  }
3215
3256
  const args = ["log", "-n", "1", "--pretty=%s", "--", "."];
3216
- const relativeDocsDir = path22.relative(projectGitCwd, feature.git.docsGitCwd);
3257
+ const relativeDocsDir = path23.relative(projectGitCwd, feature.git.docsGitCwd);
3217
3258
  const normalizedDocsDir = normalizeGitRelativePath(relativeDocsDir);
3218
3259
  if (normalizedDocsDir && normalizedDocsDir !== "." && normalizedDocsDir !== ".." && !normalizedDocsDir.startsWith("../")) {
3219
3260
  args.push(`:(exclude)${normalizedDocsDir}/**`);
@@ -3339,6 +3380,7 @@ function getStepDefinitions(lang, workflow) {
3339
3380
  {
3340
3381
  type: "instruction",
3341
3382
  category: "tasks_write",
3383
+ uiDetailKey: "context.actionDetail.tasksWriteCreate",
3342
3384
  message: tr(lang, "messages", "tasksCreate")
3343
3385
  }
3344
3386
  ];
@@ -3348,6 +3390,7 @@ function getStepDefinitions(lang, workflow) {
3348
3390
  {
3349
3391
  type: "instruction",
3350
3392
  category: "tasks_write",
3393
+ uiDetailKey: "context.actionDetail.tasksWriteNeedAtLeastOne",
3351
3394
  message: tr(lang, "messages", "tasksNeedAtLeastOne")
3352
3395
  }
3353
3396
  ];
@@ -3357,6 +3400,7 @@ function getStepDefinitions(lang, workflow) {
3357
3400
  {
3358
3401
  type: "instruction",
3359
3402
  category: "tasks_write",
3403
+ uiDetailKey: "context.actionDetail.tasksWriteImprove",
3360
3404
  message: tr(lang, "messages", "tasksImprove")
3361
3405
  }
3362
3406
  ];
@@ -3375,6 +3419,7 @@ function getStepDefinitions(lang, workflow) {
3375
3419
  {
3376
3420
  type: "instruction",
3377
3421
  category: "tasks_write",
3422
+ uiDetailKey: "context.actionDetail.tasksWriteImprove",
3378
3423
  message: tr(lang, "messages", "tasksImprove")
3379
3424
  }
3380
3425
  ];
@@ -3443,6 +3488,7 @@ function getStepDefinitions(lang, workflow) {
3443
3488
  type: "instruction",
3444
3489
  category: "issue_create",
3445
3490
  requiresUserCheck: true,
3491
+ uiDetailKey: "context.actionDetail.issueCreateAndWrite",
3446
3492
  message: tr(lang, "messages", "issueCreateAndWrite", {
3447
3493
  featureRef: f.id || f.folderName
3448
3494
  })
@@ -3455,6 +3501,7 @@ function getStepDefinitions(lang, workflow) {
3455
3501
  type: "instruction",
3456
3502
  category: "issue_create",
3457
3503
  requiresUserCheck: true,
3504
+ uiDetailKey: "context.actionDetail.issueCreateFromDoc",
3458
3505
  message: tr(lang, "messages", "issueCreateFromDoc", {
3459
3506
  featureRef: f.id || f.folderName
3460
3507
  })
@@ -3466,6 +3513,7 @@ function getStepDefinitions(lang, workflow) {
3466
3513
  type: "instruction",
3467
3514
  category: "issue_create",
3468
3515
  requiresUserCheck: true,
3516
+ uiDetailKey: "context.actionDetail.issueCreatePrepareFromDoc",
3469
3517
  message: tr(lang, "messages", "issuePrepareFromDoc", {
3470
3518
  featureRef: f.id || f.folderName
3471
3519
  })
@@ -3610,6 +3658,7 @@ function getStepDefinitions(lang, workflow) {
3610
3658
  type: "instruction",
3611
3659
  category: "pr_metadata_migrate",
3612
3660
  requiresUserCheck: true,
3661
+ uiDetailKey: "context.actionDetail.prMetadataMigratePrFields",
3613
3662
  message: tr(lang, "messages", "prLegacyAsk")
3614
3663
  });
3615
3664
  }
@@ -3845,6 +3894,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3845
3894
  type: "instruction",
3846
3895
  category: "pr_metadata_migrate",
3847
3896
  requiresUserCheck: true,
3897
+ uiDetailKey: "context.actionDetail.prMetadataMigratePrePrReviewField",
3848
3898
  message: tr(lang, "messages", "prePrReviewFieldMissing")
3849
3899
  }
3850
3900
  ];
@@ -3882,6 +3932,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3882
3932
  type: "instruction",
3883
3933
  category: "pr_metadata_migrate",
3884
3934
  requiresUserCheck: true,
3935
+ uiDetailKey: "context.actionDetail.prMetadataMigratePrFields",
3885
3936
  message: tr(lang, "messages", "prLegacyAsk")
3886
3937
  }
3887
3938
  ];
@@ -3892,6 +3943,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3892
3943
  type: "instruction",
3893
3944
  category: "pr_create",
3894
3945
  requiresUserCheck: true,
3946
+ uiDetailKey: "context.actionDetail.prCreateRequiredSequence",
3895
3947
  message: tr(lang, "messages", "prCreateRequiredSequence", {
3896
3948
  featureRef: f.id || f.folderName
3897
3949
  })
@@ -3904,6 +3956,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3904
3956
  type: "instruction",
3905
3957
  category: "pr_create",
3906
3958
  requiresUserCheck: true,
3959
+ uiDetailKey: "context.actionDetail.prCreateExecuteFromDoc",
3907
3960
  message: tr(lang, "messages", "prCreateExecuteFromDoc", {
3908
3961
  featureRef: f.id || f.folderName
3909
3962
  })
@@ -3915,6 +3968,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3915
3968
  type: "instruction",
3916
3969
  category: "pr_create",
3917
3970
  requiresUserCheck: true,
3971
+ uiDetailKey: "context.actionDetail.prCreatePrepareFromDoc",
3918
3972
  message: tr(lang, "messages", "prCreatePrepareFromDoc", {
3919
3973
  featureRef: f.id || f.folderName
3920
3974
  })
@@ -3938,6 +3992,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3938
3992
  type: "instruction",
3939
3993
  category: "pr_status_update",
3940
3994
  requiresUserCheck: true,
3995
+ uiDetailKey: "context.actionDetail.prStatusUpdateSetReview",
3941
3996
  message: tr(lang, "messages", "prFillStatus")
3942
3997
  }
3943
3998
  ];
@@ -3949,6 +4004,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3949
4004
  type: "instruction",
3950
4005
  category: "pr_status_update",
3951
4006
  requiresUserCheck: true,
4007
+ uiDetailKey: "context.actionDetail.prStatusUpdateSyncApproved",
3952
4008
  message: tr(lang, "messages", "prReviewMergedSyncStatus")
3953
4009
  }
3954
4010
  ];
@@ -3959,6 +4015,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3959
4015
  type: "instruction",
3960
4016
  category: "code_review",
3961
4017
  requiresUserCheck: true,
4018
+ uiDetailKey: "context.actionDetail.codeReviewNeedEvidenceField",
3962
4019
  message: tr(lang, "messages", "prReviewEvidenceFieldMissing")
3963
4020
  }
3964
4021
  ];
@@ -3969,6 +4026,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3969
4026
  type: "instruction",
3970
4027
  category: "code_review",
3971
4028
  requiresUserCheck: true,
4029
+ uiDetailKey: "context.actionDetail.codeReviewNeedEvidence",
3972
4030
  message: tr(lang, "messages", "prReviewEvidenceMissing")
3973
4031
  }
3974
4032
  ];
@@ -3979,6 +4037,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3979
4037
  type: "instruction",
3980
4038
  category: "code_review",
3981
4039
  requiresUserCheck: true,
4040
+ uiDetailKey: "context.actionDetail.codeReviewNeedDecisionField",
3982
4041
  message: tr(lang, "messages", "prReviewDecisionFieldMissing")
3983
4042
  }
3984
4043
  ];
@@ -3989,6 +4048,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3989
4048
  type: "instruction",
3990
4049
  category: "code_review",
3991
4050
  requiresUserCheck: true,
4051
+ uiDetailKey: "context.actionDetail.codeReviewNeedDecision",
3992
4052
  message: tr(lang, "messages", "prReviewDecisionMissing")
3993
4053
  }
3994
4054
  ];
@@ -4000,6 +4060,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4000
4060
  type: "instruction",
4001
4061
  category: "code_review",
4002
4062
  requiresUserCheck: true,
4063
+ uiDetailKey: "context.actionDetail.codeReviewResolve",
4003
4064
  message: tr(lang, "messages", "prReviewResolve")
4004
4065
  }
4005
4066
  ];
@@ -4008,6 +4069,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4008
4069
  type: "instruction",
4009
4070
  category: "code_review",
4010
4071
  requiresUserCheck: true,
4072
+ uiDetailKey: "context.actionDetail.codeReviewNeedProjectRoot",
4011
4073
  message: tr(lang, "messages", "standaloneNeedsProjectRoot")
4012
4074
  });
4013
4075
  } else if ((f.git.projectBranchAhead || 0) > 0) {
@@ -4031,6 +4093,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4031
4093
  type: "instruction",
4032
4094
  category: "code_review",
4033
4095
  requiresUserCheck: true,
4096
+ uiDetailKey: "context.actionDetail.codeReviewRemoteBlocked",
4034
4097
  message: tr(lang, "messages", "prReviewRemoteBlocked", {
4035
4098
  reasons: reasons.join("; ")
4036
4099
  })
@@ -4052,6 +4115,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4052
4115
  type: "instruction",
4053
4116
  category: "code_review",
4054
4117
  requiresUserCheck: true,
4118
+ uiDetailKey: "context.actionDetail.codeReviewMergeAfterOk",
4055
4119
  message: tr(lang, "messages", "prReviewMerge", {
4056
4120
  featureRef: f.id || f.folderName
4057
4121
  })
@@ -4063,6 +4127,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4063
4127
  {
4064
4128
  type: "instruction",
4065
4129
  category: "code_review",
4130
+ uiDetailKey: "context.actionDetail.codeReviewRequestReview",
4066
4131
  message: tr(lang, "messages", "prRequestReview")
4067
4132
  }
4068
4133
  ];
@@ -4366,7 +4431,7 @@ function getGitTopLevel(cwd) {
4366
4431
  }
4367
4432
  function listGitWorktrees(cwd) {
4368
4433
  const topLevel = getGitTopLevel(cwd) || cwd;
4369
- const cacheKey = path22.resolve(topLevel);
4434
+ const cacheKey = path23.resolve(topLevel);
4370
4435
  const cached = GIT_WORKTREE_CACHE.get(cacheKey);
4371
4436
  if (cached) return cached;
4372
4437
  try {
@@ -4525,19 +4590,6 @@ function parsePrePrReviewStatus(value) {
4525
4590
  if (/^pending$/i.test(trimmed)) return "Pending";
4526
4591
  return void 0;
4527
4592
  }
4528
- function parseReviewFindings(value) {
4529
- if (!value) return void 0;
4530
- const trimmed = value.trim();
4531
- if (!trimmed || trimmed.includes("|")) return void 0;
4532
- const majorMatch = trimmed.match(/\bmajor\s*[:=]\s*(\d+)\b/i);
4533
- const minorMatch = trimmed.match(/\bminor\s*[:=]\s*(\d+)\b/i);
4534
- if (!majorMatch || !minorMatch) return void 0;
4535
- const major = Number(majorMatch[1]);
4536
- const minor = Number(minorMatch[1]);
4537
- if (!Number.isInteger(major) || !Number.isInteger(minor)) return void 0;
4538
- if (major < 0 || minor < 0) return void 0;
4539
- return { major, minor };
4540
- }
4541
4593
  function isPlaceholderReviewEvidence(value) {
4542
4594
  if (!value) return true;
4543
4595
  const trimmed = value.trim();
@@ -4592,15 +4644,15 @@ async function isPrePrEvidenceProvided(rawValue, policy, context) {
4592
4644
  if (!evidencePath) return false;
4593
4645
  if (/^https?:\/\//i.test(evidencePath)) return false;
4594
4646
  const candidates = /* @__PURE__ */ new Set();
4595
- if (path22.isAbsolute(evidencePath)) {
4596
- candidates.add(path22.resolve(evidencePath));
4647
+ if (path23.isAbsolute(evidencePath)) {
4648
+ candidates.add(path23.resolve(evidencePath));
4597
4649
  } else {
4598
- candidates.add(path22.resolve(context.featurePath, evidencePath));
4599
- candidates.add(path22.resolve(context.docsDir, evidencePath));
4600
- candidates.add(path22.resolve(path22.dirname(context.docsDir), evidencePath));
4650
+ candidates.add(path23.resolve(context.featurePath, evidencePath));
4651
+ candidates.add(path23.resolve(context.docsDir, evidencePath));
4652
+ candidates.add(path23.resolve(path23.dirname(context.docsDir), evidencePath));
4601
4653
  }
4602
4654
  for (const candidate of candidates) {
4603
- if (await fs16.pathExists(candidate)) return true;
4655
+ if (await fs17.pathExists(candidate)) return true;
4604
4656
  }
4605
4657
  return false;
4606
4658
  }
@@ -4621,13 +4673,13 @@ function parsePrLink(value) {
4621
4673
  return trimmed;
4622
4674
  }
4623
4675
  function normalizeGitPath(value) {
4624
- return value.split(path22.sep).join("/");
4676
+ return value.split(path23.sep).join("/");
4625
4677
  }
4626
4678
  function resolveProjectStatusPaths(projectGitCwd, docsDir) {
4627
- const relativeDocsDir = path22.relative(projectGitCwd, docsDir);
4679
+ const relativeDocsDir = path23.relative(projectGitCwd, docsDir);
4628
4680
  if (!relativeDocsDir) return [];
4629
- if (path22.isAbsolute(relativeDocsDir)) return [];
4630
- if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path22.sep}`)) {
4681
+ if (path23.isAbsolute(relativeDocsDir)) return [];
4682
+ if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path23.sep}`)) {
4631
4683
  return [];
4632
4684
  }
4633
4685
  const normalizedDocsDir = normalizeGitPath(relativeDocsDir).replace(/\/+$/, "");
@@ -4806,10 +4858,10 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4806
4858
  const normalizedCandidates = uniqueNormalizedPaths(
4807
4859
  candidates.map((candidate) => {
4808
4860
  if (!candidate) return "";
4809
- if (!path22.isAbsolute(candidate)) return candidate;
4810
- const relative = path22.relative(projectGitCwd, candidate);
4861
+ if (!path23.isAbsolute(candidate)) return candidate;
4862
+ const relative = path23.relative(projectGitCwd, candidate);
4811
4863
  if (!relative) return "";
4812
- if (relative === ".." || relative.startsWith(`..${path22.sep}`)) return "";
4864
+ if (relative === ".." || relative.startsWith(`..${path23.sep}`)) return "";
4813
4865
  return relative;
4814
4866
  }).filter(Boolean)
4815
4867
  );
@@ -4822,7 +4874,7 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4822
4874
  if (cached) return [...cached];
4823
4875
  const existing = [];
4824
4876
  for (const candidate of normalizedCandidates) {
4825
- if (await fs16.pathExists(path22.join(projectGitCwd, candidate))) {
4877
+ if (await fs17.pathExists(path23.join(projectGitCwd, candidate))) {
4826
4878
  existing.push(candidate);
4827
4879
  }
4828
4880
  }
@@ -4896,9 +4948,6 @@ function isPrePrReviewSatisfied2(feature, policy) {
4896
4948
  if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
4897
4949
  return false;
4898
4950
  }
4899
- if (policy.findings === "required" && (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findingsProvided)) {
4900
- return false;
4901
- }
4902
4951
  if (!feature.docs.prePrDecisionFieldExists || !feature.prePrReview.decisionProvided) {
4903
4952
  return false;
4904
4953
  }
@@ -4911,20 +4960,20 @@ async function parseFeature(featurePath, type, context, options) {
4911
4960
  const lang = options.lang;
4912
4961
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
4913
4962
  const prePrReviewPolicy = resolvePrePrReviewPolicy(options.workflow);
4914
- const folderName = path22.basename(featurePath);
4963
+ const folderName = path23.basename(featurePath);
4915
4964
  const match = folderName.match(/^(F\d+)-(.+)$/);
4916
4965
  const id = match?.[1];
4917
4966
  const slug = match?.[2] || folderName;
4918
- const specPath = path22.join(featurePath, "spec.md");
4919
- const planPath = path22.join(featurePath, "plan.md");
4920
- const tasksPath = path22.join(featurePath, "tasks.md");
4921
- const issueDocPath = path22.join(featurePath, "issue.md");
4922
- const prDocPath = path22.join(featurePath, "pr.md");
4967
+ const specPath = path23.join(featurePath, "spec.md");
4968
+ const planPath = path23.join(featurePath, "plan.md");
4969
+ const tasksPath = path23.join(featurePath, "tasks.md");
4970
+ const issueDocPath = path23.join(featurePath, "issue.md");
4971
+ const prDocPath = path23.join(featurePath, "pr.md");
4923
4972
  let specStatus;
4924
4973
  let issueNumber;
4925
- const specExists = await fs16.pathExists(specPath);
4974
+ const specExists = await fs17.pathExists(specPath);
4926
4975
  if (specExists) {
4927
- const content = await fs16.readFile(specPath, "utf-8");
4976
+ const content = await fs17.readFile(specPath, "utf-8");
4928
4977
  const statusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4929
4978
  specStatus = parseDocStatus(statusValue);
4930
4979
  const issueValue = extractFirstSpecValue(content, ["\uC774\uC288 \uBC88\uD638", "Issue Number", "Issue"]);
@@ -4955,13 +5004,13 @@ async function parseFeature(featurePath, type, context, options) {
4955
5004
  }
4956
5005
  }
4957
5006
  let planStatus;
4958
- const planExists = await fs16.pathExists(planPath);
5007
+ const planExists = await fs17.pathExists(planPath);
4959
5008
  if (planExists) {
4960
- const content = await fs16.readFile(planPath, "utf-8");
5009
+ const content = await fs17.readFile(planPath, "utf-8");
4961
5010
  const statusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4962
5011
  planStatus = parseDocStatus(statusValue);
4963
5012
  }
4964
- const tasksExists = await fs16.pathExists(tasksPath);
5013
+ const tasksExists = await fs17.pathExists(tasksPath);
4965
5014
  const tasksSummary = { total: 0, todo: 0, doing: 0, done: 0 };
4966
5015
  let activeTask;
4967
5016
  let lastDoneTask;
@@ -4970,14 +5019,11 @@ async function parseFeature(featurePath, type, context, options) {
4970
5019
  let tasksDocStatusFieldExists = false;
4971
5020
  let completionChecklist;
4972
5021
  let prePrReviewStatus;
4973
- let prePrFindings;
4974
- let prePrFindingsProvided = false;
4975
5022
  let prePrEvidence;
4976
5023
  let prePrEvidenceProvided = false;
4977
5024
  let prePrDecision;
4978
5025
  let prePrDecisionOutcome;
4979
5026
  let prePrDecisionProvided = false;
4980
- let prReviewFindings;
4981
5027
  let prReviewEvidence;
4982
5028
  let prReviewEvidenceProvided = false;
4983
5029
  let prReviewDecision;
@@ -4995,14 +5041,12 @@ async function parseFeature(featurePath, type, context, options) {
4995
5041
  let prDocPrFieldExists = false;
4996
5042
  let prDocReviewStatusFieldExists = false;
4997
5043
  let prePrReviewFieldExists = false;
4998
- let prePrFindingsFieldExists = false;
4999
5044
  let prePrEvidenceFieldExists = false;
5000
5045
  let prePrDecisionFieldExists = false;
5001
- let prReviewFindingsFieldExists = false;
5002
5046
  let prReviewEvidenceFieldExists = false;
5003
5047
  let prReviewDecisionFieldExists = false;
5004
5048
  if (tasksExists) {
5005
- const content = await fs16.readFile(tasksPath, "utf-8");
5049
+ const content = await fs17.readFile(tasksPath, "utf-8");
5006
5050
  const {
5007
5051
  summary,
5008
5052
  activeTask: active,
@@ -5041,16 +5085,6 @@ async function parseFeature(featurePath, type, context, options) {
5041
5085
  "Pre-PR Review"
5042
5086
  ]);
5043
5087
  prePrReviewStatus = parsePrePrReviewStatus(prePrReviewValue);
5044
- const prePrFindingsValue = extractFirstSpecValue(content, [
5045
- "PR \uC804 \uB9AC\uBDF0 Findings",
5046
- "Pre-PR Findings"
5047
- ]);
5048
- prePrFindingsFieldExists = hasAnySpecKey(content, [
5049
- "PR \uC804 \uB9AC\uBDF0 Findings",
5050
- "Pre-PR Findings"
5051
- ]);
5052
- prePrFindings = parseReviewFindings(prePrFindingsValue);
5053
- prePrFindingsProvided = !!prePrFindings;
5054
5088
  const prePrEvidenceValue = extractFirstSpecValue(content, [
5055
5089
  "PR \uC804 \uB9AC\uBDF0 Evidence",
5056
5090
  "Pre-PR Evidence"
@@ -5076,15 +5110,6 @@ async function parseFeature(featurePath, type, context, options) {
5076
5110
  prePrDecision = prePrDecisionValue?.trim();
5077
5111
  prePrDecisionOutcome = parsePrePrDecisionOutcome(prePrDecisionValue);
5078
5112
  prePrDecisionProvided = !isPlaceholderReviewEvidence(prePrDecisionValue) && hasStructuredReviewDecision(prePrDecisionValue) && !!prePrDecisionOutcome && prePrReviewPolicy.decisionEnum.includes(prePrDecisionOutcome);
5079
- const prReviewFindingsValue = extractFirstSpecValue(content, [
5080
- "PR \uB9AC\uBDF0 Findings",
5081
- "PR Review Findings"
5082
- ]);
5083
- prReviewFindingsFieldExists = hasAnySpecKey(content, [
5084
- "PR \uB9AC\uBDF0 Findings",
5085
- "PR Review Findings"
5086
- ]);
5087
- prReviewFindings = parseReviewFindings(prReviewFindingsValue);
5088
5113
  const prReviewEvidenceValue = extractFirstSpecValue(content, [
5089
5114
  "PR \uB9AC\uBDF0 Evidence",
5090
5115
  "PR Review Evidence"
@@ -5127,9 +5152,9 @@ async function parseFeature(featurePath, type, context, options) {
5127
5152
  }
5128
5153
  }
5129
5154
  }
5130
- const issueDocExists = await fs16.pathExists(issueDocPath);
5155
+ const issueDocExists = await fs17.pathExists(issueDocPath);
5131
5156
  if (issueDocExists) {
5132
- const content = await fs16.readFile(issueDocPath, "utf-8");
5157
+ const content = await fs17.readFile(issueDocPath, "utf-8");
5133
5158
  const issueDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
5134
5159
  issueDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
5135
5160
  issueDocStatus = parseWorkflowDocStatus(issueDocStatusValue);
@@ -5139,9 +5164,9 @@ async function parseFeature(featurePath, type, context, options) {
5139
5164
  "Issue"
5140
5165
  ]);
5141
5166
  }
5142
- const prDocExists = await fs16.pathExists(prDocPath);
5167
+ const prDocExists = await fs17.pathExists(prDocPath);
5143
5168
  if (prDocExists) {
5144
- const content = await fs16.readFile(prDocPath, "utf-8");
5169
+ const content = await fs17.readFile(prDocPath, "utf-8");
5145
5170
  const prDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
5146
5171
  prDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
5147
5172
  prDocStatus = parseWorkflowDocStatus(prDocStatusValue);
@@ -5161,7 +5186,7 @@ async function parseFeature(featurePath, type, context, options) {
5161
5186
  slug,
5162
5187
  folderName
5163
5188
  );
5164
- const relativeFeaturePathFromDocs = path22.relative(context.docsDir, featurePath);
5189
+ const relativeFeaturePathFromDocs = path23.relative(context.docsDir, featurePath);
5165
5190
  const normalizedFeaturePathFromDocs = normalizeGitPath(relativeFeaturePathFromDocs);
5166
5191
  const docsPathIgnored = typeof context.docsPathIgnored === "boolean" ? context.docsPathIgnored : isGitPathIgnored(context.docsGitCwd, normalizedFeaturePathFromDocs);
5167
5192
  let docsHasUncommittedChanges = typeof context.docsHasUncommittedChanges === "boolean" ? context.docsHasUncommittedChanges : false;
@@ -5250,9 +5275,6 @@ async function parseFeature(featurePath, type, context, options) {
5250
5275
  if (tasksExists && prePrReviewPolicy.enabled && !prePrReviewFieldExists) {
5251
5276
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrReviewField"));
5252
5277
  }
5253
- if (tasksExists && prePrReviewPolicy.enabled && prePrReviewPolicy.findings === "required" && !prePrFindingsFieldExists) {
5254
- warnings.push(tr(lang, "warnings", "legacyTasksPrePrFindingsField"));
5255
- }
5256
5278
  if (tasksExists && prePrReviewPolicy.enabled && !prePrEvidenceFieldExists) {
5257
5279
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrEvidenceField"));
5258
5280
  }
@@ -5297,13 +5319,11 @@ async function parseFeature(featurePath, type, context, options) {
5297
5319
  {
5298
5320
  docs: {
5299
5321
  prePrReviewFieldExists,
5300
- prePrFindingsFieldExists,
5301
5322
  prePrEvidenceFieldExists,
5302
5323
  prePrDecisionFieldExists
5303
5324
  },
5304
5325
  prePrReview: {
5305
5326
  status: prePrReviewStatus,
5306
- findingsProvided: prePrFindingsProvided,
5307
5327
  evidenceProvided: prePrEvidenceProvided,
5308
5328
  decisionOutcome: prePrDecisionOutcome,
5309
5329
  decisionProvided: prePrDecisionProvided
@@ -5346,8 +5366,6 @@ async function parseFeature(featurePath, type, context, options) {
5346
5366
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewMissing"));
5347
5367
  } else if (prePrReviewStatus !== "Done") {
5348
5368
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewNotDone"));
5349
- } else if (prePrReviewPolicy.findings === "required" && (!prePrFindingsFieldExists || !prePrFindingsProvided)) {
5350
- warnings.push(tr(lang, "warnings", "workflowPrePrFindingsMissing"));
5351
5369
  } else if (!prePrEvidenceFieldExists || !prePrEvidenceProvided) {
5352
5370
  warnings.push(tr(lang, "warnings", "workflowPrePrEvidenceMissing"));
5353
5371
  } else if (!prePrDecisionFieldExists || !prePrDecisionProvided) {
@@ -5382,8 +5400,6 @@ async function parseFeature(featurePath, type, context, options) {
5382
5400
  completionChecklist,
5383
5401
  prePrReview: {
5384
5402
  status: prePrReviewStatus,
5385
- findings: prePrFindings,
5386
- findingsProvided: prePrFindingsProvided,
5387
5403
  evidence: prePrEvidence,
5388
5404
  evidenceProvided: prePrEvidenceProvided,
5389
5405
  decision: prePrDecision,
@@ -5391,7 +5407,6 @@ async function parseFeature(featurePath, type, context, options) {
5391
5407
  decisionProvided: prePrDecisionProvided
5392
5408
  },
5393
5409
  prReview: {
5394
- findings: prReviewFindings,
5395
5410
  evidence: prReviewEvidence,
5396
5411
  evidenceProvided: prReviewEvidenceProvided,
5397
5412
  decision: prReviewDecision,
@@ -5431,10 +5446,8 @@ async function parseFeature(featurePath, type, context, options) {
5431
5446
  prFieldExists,
5432
5447
  prStatusFieldExists,
5433
5448
  prePrReviewFieldExists,
5434
- prePrFindingsFieldExists,
5435
5449
  prePrEvidenceFieldExists,
5436
5450
  prePrDecisionFieldExists,
5437
- prReviewFindingsFieldExists,
5438
5451
  prReviewEvidenceFieldExists,
5439
5452
  prReviewDecisionFieldExists
5440
5453
  }
@@ -5450,7 +5463,7 @@ async function parseFeature(featurePath, type, context, options) {
5450
5463
  async function listFeatureDirs(rootDir) {
5451
5464
  const dirs = await listSubdirectories(rootDir);
5452
5465
  return dirs.filter(
5453
- (value) => path22.basename(value).trim().toLowerCase() !== "feature-base"
5466
+ (value) => path23.basename(value).trim().toLowerCase() !== "feature-base"
5454
5467
  );
5455
5468
  }
5456
5469
  function normalizeRelPath(value) {
@@ -5570,21 +5583,21 @@ async function scanFeatures(config) {
5570
5583
  const allFeatureDirs = [];
5571
5584
  const componentFeatureDirs = /* @__PURE__ */ new Map();
5572
5585
  if (config.projectType === "single") {
5573
- const featureDirs = await listFeatureDirs(path22.join(config.docsDir, "features"));
5586
+ const featureDirs = await listFeatureDirs(path23.join(config.docsDir, "features"));
5574
5587
  componentFeatureDirs.set("single", featureDirs);
5575
5588
  allFeatureDirs.push(...featureDirs);
5576
5589
  } else {
5577
5590
  const components = resolveProjectComponents(config.projectType, config.components);
5578
5591
  for (const component of components) {
5579
5592
  const componentDirs = await listFeatureDirs(
5580
- path22.join(config.docsDir, "features", component)
5593
+ path23.join(config.docsDir, "features", component)
5581
5594
  );
5582
5595
  componentFeatureDirs.set(component, componentDirs);
5583
5596
  allFeatureDirs.push(...componentDirs);
5584
5597
  }
5585
5598
  }
5586
5599
  const relativeFeaturePaths = allFeatureDirs.map(
5587
- (dir) => normalizeRelPath(path22.relative(config.docsDir, dir))
5600
+ (dir) => normalizeRelPath(path23.relative(config.docsDir, dir))
5588
5601
  );
5589
5602
  const docsGitMeta = buildDocsFeatureGitMeta(config.docsDir, relativeFeaturePaths);
5590
5603
  const parseTargets = config.projectType === "single" ? [{ type: "single", dirs: componentFeatureDirs.get("single") || [] }] : resolveProjectComponents(config.projectType, config.components).map((component) => ({
@@ -5595,7 +5608,7 @@ async function scanFeatures(config) {
5595
5608
  const parsed = await Promise.all(
5596
5609
  target.dirs.map(async (dir) => {
5597
5610
  const relativeFeaturePathFromDocs = normalizeRelPath(
5598
- path22.relative(config.docsDir, dir)
5611
+ path23.relative(config.docsDir, dir)
5599
5612
  );
5600
5613
  const docsMeta = docsGitMeta.get(relativeFeaturePathFromDocs);
5601
5614
  return parseFeature(
@@ -5665,13 +5678,13 @@ async function runStatus(options) {
5665
5678
  );
5666
5679
  }
5667
5680
  const { docsDir, projectType, projectName, lang } = config;
5668
- const featuresDir = path22.join(docsDir, "features");
5681
+ const featuresDir = path23.join(docsDir, "features");
5669
5682
  const scan = await scanFeatures(config);
5670
5683
  const features = [];
5671
5684
  const idMap = /* @__PURE__ */ new Map();
5672
5685
  for (const f of scan.features) {
5673
5686
  const id = f.id || "UNKNOWN";
5674
- const relPath = path22.relative(docsDir, f.path);
5687
+ const relPath = path23.relative(docsDir, f.path);
5675
5688
  if (!idMap.has(id)) idMap.set(id, []);
5676
5689
  idMap.get(id).push(relPath);
5677
5690
  if (!f.docs.specExists || !f.docs.tasksExists) continue;
@@ -5752,7 +5765,7 @@ async function runStatus(options) {
5752
5765
  }
5753
5766
  console.log();
5754
5767
  if (options.write) {
5755
- const outputPath = path22.join(featuresDir, "status.md");
5768
+ const outputPath = path23.join(featuresDir, "status.md");
5756
5769
  const date = getLocalDateString();
5757
5770
  const content = [
5758
5771
  "# Feature Status",
@@ -5767,7 +5780,7 @@ async function runStatus(options) {
5767
5780
  ),
5768
5781
  ""
5769
5782
  ].join("\n");
5770
- await fs16.writeFile(outputPath, content, "utf-8");
5783
+ await fs17.writeFile(outputPath, content, "utf-8");
5771
5784
  console.log(
5772
5785
  chalk6.green(
5773
5786
  tr(lang, "cli", "status.wrote", { path: outputPath })
@@ -5780,9 +5793,9 @@ function escapeRegExp2(value) {
5780
5793
  }
5781
5794
  async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderName) {
5782
5795
  try {
5783
- const specPath = path22.join(featureDir, "spec.md");
5784
- if (!await fs16.pathExists(specPath)) return fallbackSlug;
5785
- const content = await fs16.readFile(specPath, "utf-8");
5796
+ const specPath = path23.join(featureDir, "spec.md");
5797
+ if (!await fs17.pathExists(specPath)) return fallbackSlug;
5798
+ const content = await fs17.readFile(specPath, "utf-8");
5786
5799
  const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
5787
5800
  for (const key of keys) {
5788
5801
  const regex = new RegExp(
@@ -5863,8 +5876,8 @@ async function runUpdate(options) {
5863
5876
  console.log(chalk6.blue(tr(lang, "cli", "update.updatingAgents")));
5864
5877
  }
5865
5878
  if (agentsMode === "all") {
5866
- const commonAgentsBase = path22.join(templatesDir, lang, "common", "agents");
5867
- const targetAgentsBase = path22.join(docsDir, "agents");
5879
+ const commonAgentsBase = path23.join(templatesDir, lang, "common", "agents");
5880
+ const targetAgentsBase = path23.join(docsDir, "agents");
5868
5881
  const commonAgents = commonAgentsBase;
5869
5882
  const targetAgents = targetAgentsBase;
5870
5883
  const featurePath = projectType === "multi" ? "docs/features/{component}" : "docs/features";
@@ -5873,7 +5886,7 @@ async function runUpdate(options) {
5873
5886
  "{{projectName}}": projectName,
5874
5887
  "{{featurePath}}": featurePath
5875
5888
  };
5876
- if (await fs16.pathExists(commonAgents)) {
5889
+ if (await fs17.pathExists(commonAgents)) {
5877
5890
  const count = await updateFolder(
5878
5891
  commonAgents,
5879
5892
  targetAgents,
@@ -5958,11 +5971,11 @@ function normalizeDecisionEnumList2(raw) {
5958
5971
  return [...deduped];
5959
5972
  }
5960
5973
  async function backfillMissingConfigDefaults(docsDir) {
5961
- const configPath = path22.join(docsDir, ".lee-spec-kit.json");
5962
- if (!await fs16.pathExists(configPath)) {
5974
+ const configPath = path23.join(docsDir, ".lee-spec-kit.json");
5975
+ if (!await fs17.pathExists(configPath)) {
5963
5976
  return { changed: false, changedPaths: [] };
5964
5977
  }
5965
- const raw = await fs16.readJson(configPath);
5978
+ const raw = await fs17.readJson(configPath);
5966
5979
  if (!isPlainObject(raw)) {
5967
5980
  return { changed: false, changedPaths: [] };
5968
5981
  }
@@ -6015,14 +6028,8 @@ async function backfillMissingConfigDefaults(docsDir) {
6015
6028
  prePrReview.evidenceMode = "path_required";
6016
6029
  changedPaths.push("workflow.prePrReview.evidenceMode");
6017
6030
  }
6018
- setIfMissing(
6019
- prePrReview,
6020
- "findings",
6021
- "required",
6022
- "workflow.prePrReview.findings"
6023
- );
6024
- if (prePrReview.findings !== void 0 && prePrReview.findings !== "required" && prePrReview.findings !== "optional") {
6025
- prePrReview.findings = "required";
6031
+ if ("findings" in prePrReview) {
6032
+ delete prePrReview.findings;
6026
6033
  changedPaths.push("workflow.prePrReview.findings");
6027
6034
  }
6028
6035
  if (prePrReview.decisionEnum === void 0) {
@@ -6058,30 +6065,30 @@ async function backfillMissingConfigDefaults(docsDir) {
6058
6065
  if (changedPaths.length === 0) {
6059
6066
  return { changed: false, changedPaths: [] };
6060
6067
  }
6061
- await fs16.writeJson(configPath, raw, { spaces: 2 });
6068
+ await fs17.writeJson(configPath, raw, { spaces: 2 });
6062
6069
  return { changed: true, changedPaths };
6063
6070
  }
6064
6071
  async function updateFolder(sourceDir, targetDir, force, replacements, lang = DEFAULT_LANG, options = {}) {
6065
6072
  const protectedFiles = options.protectedFiles ?? /* @__PURE__ */ new Set(["custom.md", "constitution.md"]);
6066
6073
  const skipDirectories = options.skipDirectories ?? /* @__PURE__ */ new Set();
6067
- await fs16.ensureDir(targetDir);
6068
- const files = await fs16.readdir(sourceDir);
6074
+ await fs17.ensureDir(targetDir);
6075
+ const files = await fs17.readdir(sourceDir);
6069
6076
  let updatedCount = 0;
6070
6077
  for (const file of files) {
6071
- const sourcePath = path22.join(sourceDir, file);
6072
- const targetPath = path22.join(targetDir, file);
6073
- const stat = await fs16.stat(sourcePath);
6078
+ const sourcePath = path23.join(sourceDir, file);
6079
+ const targetPath = path23.join(targetDir, file);
6080
+ const stat = await fs17.stat(sourcePath);
6074
6081
  if (stat.isFile()) {
6075
6082
  if (protectedFiles.has(file)) {
6076
6083
  continue;
6077
6084
  }
6078
- let sourceContent = await fs16.readFile(sourcePath, "utf-8");
6085
+ let sourceContent = await fs17.readFile(sourcePath, "utf-8");
6079
6086
  if (replacements) {
6080
6087
  sourceContent = applyReplacements(sourceContent, replacements);
6081
6088
  }
6082
6089
  let shouldUpdate = true;
6083
- if (await fs16.pathExists(targetPath)) {
6084
- const targetContent = await fs16.readFile(targetPath, "utf-8");
6090
+ if (await fs17.pathExists(targetPath)) {
6091
+ const targetContent = await fs17.readFile(targetPath, "utf-8");
6085
6092
  if (sourceContent === targetContent) {
6086
6093
  continue;
6087
6094
  }
@@ -6095,7 +6102,7 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
6095
6102
  }
6096
6103
  }
6097
6104
  if (shouldUpdate) {
6098
- await fs16.writeFile(targetPath, sourceContent);
6105
+ await fs17.writeFile(targetPath, sourceContent);
6099
6106
  console.log(
6100
6107
  chalk6.gray(` \u{1F4C4} ${tr(lang, "cli", "update.fileUpdated", { file })}`)
6101
6108
  );
@@ -6152,7 +6159,7 @@ function extractPorcelainPaths(line) {
6152
6159
  function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
6153
6160
  const top = getGitTopLevel2(docsDir);
6154
6161
  if (!top) return null;
6155
- const rel = path22.relative(top, docsDir) || ".";
6162
+ const rel = path23.relative(top, docsDir) || ".";
6156
6163
  try {
6157
6164
  const output = execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
6158
6165
  cwd: top,
@@ -6164,7 +6171,7 @@ function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
6164
6171
  }
6165
6172
  const ignoredRelPaths = new Set(
6166
6173
  ignoredAbsPaths.map(
6167
- (absPath) => normalizeGitPath2(path22.relative(top, absPath) || ".")
6174
+ (absPath) => normalizeGitPath2(path23.relative(top, absPath) || ".")
6168
6175
  )
6169
6176
  );
6170
6177
  const filtered = output.split("\n").filter((line) => {
@@ -6222,7 +6229,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
6222
6229
  }
6223
6230
  async function runConfig(options) {
6224
6231
  const cwd = process.cwd();
6225
- const targetCwd = options.dir ? path22.resolve(cwd, options.dir) : cwd;
6232
+ const targetCwd = options.dir ? path23.resolve(cwd, options.dir) : cwd;
6226
6233
  const config = await getConfig(targetCwd);
6227
6234
  if (!config) {
6228
6235
  throw createCliError(
@@ -6230,7 +6237,7 @@ async function runConfig(options) {
6230
6237
  tr(DEFAULT_LANG, "cli", "common.configNotFound")
6231
6238
  );
6232
6239
  }
6233
- const configPath = path22.join(config.docsDir, ".lee-spec-kit.json");
6240
+ const configPath = path23.join(config.docsDir, ".lee-spec-kit.json");
6234
6241
  if (!options.projectRoot) {
6235
6242
  console.log();
6236
6243
  console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
@@ -6241,7 +6248,7 @@ async function runConfig(options) {
6241
6248
  )
6242
6249
  );
6243
6250
  console.log();
6244
- const configFile = await fs16.readJson(configPath);
6251
+ const configFile = await fs17.readJson(configPath);
6245
6252
  console.log(JSON.stringify(configFile, null, 2));
6246
6253
  console.log();
6247
6254
  return;
@@ -6250,7 +6257,7 @@ async function runConfig(options) {
6250
6257
  await withFileLock(
6251
6258
  getDocsLockPath(config.docsDir),
6252
6259
  async () => {
6253
- const configFile = await fs16.readJson(configPath);
6260
+ const configFile = await fs17.readJson(configPath);
6254
6261
  if (configFile.docsRepo !== "standalone") {
6255
6262
  console.log(
6256
6263
  chalk6.yellow(tr(config.lang, "cli", "config.projectRootStandaloneOnly"))
@@ -6326,7 +6333,7 @@ async function runConfig(options) {
6326
6333
  )
6327
6334
  );
6328
6335
  }
6329
- await fs16.writeJson(configPath, configFile, { spaces: 2 });
6336
+ await fs17.writeJson(configPath, configFile, { spaces: 2 });
6330
6337
  console.log();
6331
6338
  },
6332
6339
  { owner: "config" }
@@ -6407,6 +6414,14 @@ function annotateActions(actions) {
6407
6414
  return actions.map((action) => annotateActionOperationType(action));
6408
6415
  }
6409
6416
  function getActionSummary(action, lang) {
6417
+ if (action.uiSummaryKey) {
6418
+ const localized = tr(lang, "cli", action.uiSummaryKey);
6419
+ if (localized !== `cli.${action.uiSummaryKey}`) return localized;
6420
+ }
6421
+ if (action.uiDetailKey) {
6422
+ const localized = tr(lang, "cli", action.uiDetailKey);
6423
+ if (localized !== `cli.${action.uiDetailKey}`) return localized;
6424
+ }
6410
6425
  const detailKey = action.category ? ACTION_DETAIL_KEY_BY_CATEGORY[action.category] : void 0;
6411
6426
  if (detailKey) {
6412
6427
  const localized = tr(lang, "cli", detailKey);
@@ -6428,6 +6443,10 @@ function toOneLine(text) {
6428
6443
  return `${normalized.slice(0, 157).trimEnd()}...`;
6429
6444
  }
6430
6445
  function buildActionDetail(action, lang) {
6446
+ if (action.uiDetailKey) {
6447
+ const localized = tr(lang, "cli", action.uiDetailKey);
6448
+ if (localized !== `cli.${action.uiDetailKey}`) return localized;
6449
+ }
6431
6450
  const formatBranchCreateDetail = (command) => {
6432
6451
  const worktreeMatch = command.match(/\.worktrees\/([A-Za-z0-9._-]+)/);
6433
6452
  const branchMatch = command.match(/\bfeat\/([A-Za-z0-9._-]+)/);
@@ -6483,6 +6502,11 @@ function buildActionDetail(action, lang) {
6483
6502
  });
6484
6503
  }
6485
6504
  }
6505
+ if (action.category === "pre_pr_review") {
6506
+ return tr(lang, "cli", "context.commandDetail.prePrReviewRun", {
6507
+ scope: action.scope
6508
+ });
6509
+ }
6486
6510
  if (action.category === "worktree_cleanup") {
6487
6511
  return `(${action.scope}) ${tr(lang, "cli", "context.actionDetail.worktreeCleanup")}`;
6488
6512
  }
@@ -6531,7 +6555,9 @@ function buildActionSnapshot(actionOptions) {
6531
6555
  cmd: action.cmd,
6532
6556
  category: action.category,
6533
6557
  operationType: action.operationType,
6534
- requiresUserCheck: !!action.requiresUserCheck
6558
+ requiresUserCheck: !!action.requiresUserCheck,
6559
+ uiSummaryKey: action.uiSummaryKey,
6560
+ uiDetailKey: action.uiDetailKey
6535
6561
  };
6536
6562
  }
6537
6563
  return {
@@ -6540,7 +6566,9 @@ function buildActionSnapshot(actionOptions) {
6540
6566
  message: action.message,
6541
6567
  category: action.category,
6542
6568
  operationType: action.operationType,
6543
- requiresUserCheck: !!action.requiresUserCheck
6569
+ requiresUserCheck: !!action.requiresUserCheck,
6570
+ uiSummaryKey: action.uiSummaryKey,
6571
+ uiDetailKey: action.uiDetailKey
6544
6572
  };
6545
6573
  });
6546
6574
  }
@@ -6726,13 +6754,13 @@ function getApprovalSessionId() {
6726
6754
  function getApprovalTicketPaths(config) {
6727
6755
  return {
6728
6756
  runtimePath: getApprovalTicketStorePath(config.docsDir),
6729
- legacyPath: path22.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
6757
+ legacyPath: path23.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
6730
6758
  };
6731
6759
  }
6732
6760
  async function loadApprovalTicketStore(storePath) {
6733
- if (!await fs16.pathExists(storePath)) return { tickets: [] };
6761
+ if (!await fs17.pathExists(storePath)) return { tickets: [] };
6734
6762
  try {
6735
- const parsed = await fs16.readJson(storePath);
6763
+ const parsed = await fs17.readJson(storePath);
6736
6764
  if (!parsed || !Array.isArray(parsed.tickets)) return { tickets: [] };
6737
6765
  return { tickets: parsed.tickets };
6738
6766
  } catch {
@@ -6740,8 +6768,8 @@ async function loadApprovalTicketStore(storePath) {
6740
6768
  }
6741
6769
  }
6742
6770
  async function saveApprovalTicketStore(storePath, payload) {
6743
- await fs16.ensureDir(path22.dirname(storePath));
6744
- await fs16.writeJson(storePath, payload, { spaces: 2 });
6771
+ await fs17.ensureDir(path23.dirname(storePath));
6772
+ await fs17.writeJson(storePath, payload, { spaces: 2 });
6745
6773
  }
6746
6774
  function pruneApprovalTickets(tickets, nowMs) {
6747
6775
  return tickets.filter((ticket) => {
@@ -6753,13 +6781,13 @@ function pruneApprovalTickets(tickets, nowMs) {
6753
6781
  }
6754
6782
  async function resolveApprovalTicketStoreAndPath(config, nowMs) {
6755
6783
  const { runtimePath, legacyPath } = getApprovalTicketPaths(config);
6756
- if (await fs16.pathExists(runtimePath)) {
6784
+ if (await fs17.pathExists(runtimePath)) {
6757
6785
  return {
6758
6786
  storePath: runtimePath,
6759
6787
  store: await loadApprovalTicketStore(runtimePath)
6760
6788
  };
6761
6789
  }
6762
- if (!await fs16.pathExists(legacyPath)) {
6790
+ if (!await fs17.pathExists(legacyPath)) {
6763
6791
  return {
6764
6792
  storePath: runtimePath,
6765
6793
  store: { tickets: [] }
@@ -6775,7 +6803,7 @@ async function resolveApprovalTicketStoreAndPath(config, nowMs) {
6775
6803
  migratedFrom: legacyPath
6776
6804
  }
6777
6805
  );
6778
- await fs16.remove(legacyPath).catch(() => {
6806
+ await fs17.remove(legacyPath).catch(() => {
6779
6807
  });
6780
6808
  return {
6781
6809
  storePath: runtimePath,
@@ -6907,42 +6935,42 @@ var BUILTIN_DOC_DEFINITIONS = [
6907
6935
  {
6908
6936
  id: "agents",
6909
6937
  title: { ko: "\uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uADDC\uCE59", en: "Agent Operating Rules" },
6910
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "agents.md")
6938
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "agents.md")
6911
6939
  },
6912
6940
  {
6913
6941
  id: "git-workflow",
6914
6942
  title: { ko: "Git \uC6CC\uD06C\uD50C\uB85C\uC6B0", en: "Git Workflow" },
6915
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "git-workflow.md")
6943
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "git-workflow.md")
6916
6944
  },
6917
6945
  {
6918
6946
  id: "issue-doc",
6919
6947
  title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
6920
- relativePath: (_, lang) => path22.join(lang, "common", "features", "feature-base", "issue.md")
6948
+ relativePath: (_, lang) => path23.join(lang, "common", "features", "feature-base", "issue.md")
6921
6949
  },
6922
6950
  {
6923
6951
  id: "pr-doc",
6924
6952
  title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
6925
- relativePath: (_, lang) => path22.join(lang, "common", "features", "feature-base", "pr.md")
6953
+ relativePath: (_, lang) => path23.join(lang, "common", "features", "feature-base", "pr.md")
6926
6954
  },
6927
6955
  {
6928
6956
  id: "create-feature",
6929
6957
  title: { ko: "create-feature \uC2A4\uD0AC", en: "create-feature skill" },
6930
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "skills", "create-feature.md")
6958
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "skills", "create-feature.md")
6931
6959
  },
6932
6960
  {
6933
6961
  id: "execute-task",
6934
6962
  title: { ko: "execute-task \uC2A4\uD0AC", en: "execute-task skill" },
6935
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "skills", "execute-task.md")
6963
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "skills", "execute-task.md")
6936
6964
  },
6937
6965
  {
6938
6966
  id: "create-issue",
6939
6967
  title: { ko: "create-issue \uC2A4\uD0AC", en: "create-issue skill" },
6940
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "skills", "create-issue.md")
6968
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "skills", "create-issue.md")
6941
6969
  },
6942
6970
  {
6943
6971
  id: "create-pr",
6944
6972
  title: { ko: "create-pr \uC2A4\uD0AC", en: "create-pr skill" },
6945
- relativePath: (_, lang) => path22.join(lang, "common", "agents", "skills", "create-pr.md")
6973
+ relativePath: (_, lang) => path23.join(lang, "common", "agents", "skills", "create-pr.md")
6946
6974
  }
6947
6975
  ];
6948
6976
  var DOC_FOLLOWUPS = {
@@ -7031,7 +7059,7 @@ function listBuiltinDocs(projectType, lang) {
7031
7059
  id: doc.id,
7032
7060
  title: doc.title[lang],
7033
7061
  relativePath,
7034
- absolutePath: path22.join(templatesDir, relativePath)
7062
+ absolutePath: path23.join(templatesDir, relativePath)
7035
7063
  };
7036
7064
  });
7037
7065
  }
@@ -7040,7 +7068,7 @@ async function getBuiltinDoc(docId, projectType, lang) {
7040
7068
  if (!entry) {
7041
7069
  throw new Error(`Unknown builtin doc: ${docId}`);
7042
7070
  }
7043
- const content = await fs16.readFile(entry.absolutePath, "utf-8");
7071
+ const content = await fs17.readFile(entry.absolutePath, "utf-8");
7044
7072
  const hash = createHash("sha256").update(content).digest("hex").slice(0, 12);
7045
7073
  return {
7046
7074
  entry,
@@ -7051,6 +7079,56 @@ async function getBuiltinDoc(docId, projectType, lang) {
7051
7079
  }
7052
7080
 
7053
7081
  // src/commands/context.ts
7082
+ var LONG_RUNNING_DELEGATION_CATEGORIES = [
7083
+ "task_execute",
7084
+ "code_review",
7085
+ "review_fix_commit",
7086
+ "pre_pr_review"
7087
+ ];
7088
+ function shouldDelegateCurrentAction(actionOptions, autoRunAvailable) {
7089
+ const primaryCategory = actionOptions[0]?.action?.category || null;
7090
+ const longRunningSet = new Set(LONG_RUNNING_DELEGATION_CATEGORIES);
7091
+ const shouldDelegate = autoRunAvailable || !!primaryCategory && longRunningSet.has(primaryCategory);
7092
+ return {
7093
+ shouldDelegate,
7094
+ category: primaryCategory
7095
+ };
7096
+ }
7097
+ function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable) {
7098
+ const delegation = shouldDelegateCurrentAction(actionOptions, autoRunAvailable);
7099
+ return {
7100
+ mode: "main_orchestrates_subagent_execution",
7101
+ delegationPolicy: "prefer_main_delegate_long_running_fallback_main",
7102
+ delegateCommandExecution: "long_running_only",
7103
+ delegateAutoRunExecution: true,
7104
+ fallbackToMainAgentWhenSubAgentUnavailable: true,
7105
+ longRunningCategories: [...LONG_RUNNING_DELEGATION_CATEGORIES],
7106
+ currentActionShouldDelegate: delegation.shouldDelegate,
7107
+ currentActionCategory: delegation.category,
7108
+ mainAgentResponsibilities: [
7109
+ "Keep user conversation state and approval boundaries",
7110
+ "Run the same execution loop directly when sub-agent is unavailable",
7111
+ "Delegate only long-running command/auto loops to sub-agents",
7112
+ "Report only on approval/manual/error boundaries"
7113
+ ],
7114
+ subAgentResponsibilities: [
7115
+ "Run flow/context command loops",
7116
+ "Execute only currently selected atomic command actions",
7117
+ "Return structured status to main agent"
7118
+ ],
7119
+ pauseAndReportWhen: [
7120
+ "approvalRequest.required=true",
7121
+ "AUTO_GATE_REACHED",
7122
+ "AUTO_MANUAL_REQUIRED",
7123
+ "command execution error"
7124
+ ],
7125
+ resumePriority: [
7126
+ "flow --resume <RUN_ID>",
7127
+ "autoRun.resume.flowCommand",
7128
+ "context --json"
7129
+ ]
7130
+ };
7131
+ }
7054
7132
  async function resolveContextState(config, featureName, options) {
7055
7133
  if (!config) {
7056
7134
  throw createCliError(
@@ -7116,6 +7194,72 @@ function buildSuggestionFinalPrompt(lang, suggestionOptions) {
7116
7194
  example
7117
7195
  });
7118
7196
  }
7197
+ function normalizeCategoryToken(value) {
7198
+ if (typeof value !== "string") return null;
7199
+ const normalized = value.trim().toLowerCase();
7200
+ if (!normalized) return null;
7201
+ return normalized;
7202
+ }
7203
+ function resolveAutoRunCategories(approval) {
7204
+ const known = new Set(ACTION_CATEGORIES);
7205
+ const unique2 = /* @__PURE__ */ new Set();
7206
+ const unknown = /* @__PURE__ */ new Set();
7207
+ for (const raw of approval?.requireCheckCategories ?? approval?.requireOkCategories ?? []) {
7208
+ const normalized = normalizeCategoryToken(raw);
7209
+ if (!normalized) continue;
7210
+ if (known.has(normalized)) {
7211
+ unique2.add(normalized);
7212
+ } else {
7213
+ unknown.add(normalized);
7214
+ }
7215
+ }
7216
+ return {
7217
+ untilCategories: Array.from(unique2),
7218
+ unknownCategories: Array.from(unknown)
7219
+ };
7220
+ }
7221
+ function buildAutoRunCommand(state, featureName, selectedComponent, untilCategories) {
7222
+ if (untilCategories.length === 0) return "";
7223
+ const featureRef = resolveFeatureRefForApproval(state, featureName);
7224
+ const componentArg = selectedComponent ? ` --component ${selectedComponent}` : "";
7225
+ return `npx lee-spec-kit flow ${featureRef}${componentArg} --auto-until-category ${untilCategories.join(",")}`;
7226
+ }
7227
+ function resolveAutoRunPlan(lang, state, featureName, selectedComponent, approval, approvalRequired) {
7228
+ const base = (reasonCode, untilCategories2 = [], unknownCategories2 = []) => ({
7229
+ available: false,
7230
+ reasonCode,
7231
+ summary: tr(lang, "cli", "context.autoRunUnavailable"),
7232
+ command: "",
7233
+ untilCategories: untilCategories2,
7234
+ unknownCategories: unknownCategories2
7235
+ });
7236
+ if (state.status !== "single_matched") return base("NOT_SINGLE_MATCHED");
7237
+ if (state.actionOptions.length === 0) return base("NO_ACTION_OPTIONS");
7238
+ if (approvalRequired) return base("APPROVAL_REQUIRED");
7239
+ const mode = approval?.mode ?? "builtin";
7240
+ if (mode !== "category") return base("APPROVAL_MODE_NOT_CATEGORY");
7241
+ const defaultPolicy = approval?.default ?? "keep";
7242
+ if (defaultPolicy !== "skip") return base("DEFAULT_NOT_SKIP");
7243
+ const { untilCategories, unknownCategories } = resolveAutoRunCategories(approval);
7244
+ if (untilCategories.length === 0) {
7245
+ return base("NO_REQUIRE_CHECK_CATEGORIES", [], unknownCategories);
7246
+ }
7247
+ return {
7248
+ available: true,
7249
+ reasonCode: "AVAILABLE",
7250
+ summary: tr(lang, "cli", "context.autoRunSummary", {
7251
+ categories: untilCategories.join(", ")
7252
+ }),
7253
+ command: buildAutoRunCommand(
7254
+ state,
7255
+ featureName,
7256
+ selectedComponent,
7257
+ untilCategories
7258
+ ),
7259
+ untilCategories,
7260
+ unknownCategories
7261
+ };
7262
+ }
7119
7263
  function toSuggestionLabel(index) {
7120
7264
  let n = index + 1;
7121
7265
  let label = "";
@@ -7309,9 +7453,6 @@ function getListLabel(f, stepsMap, lang, workflowPolicy, prePrReviewPolicy) {
7309
7453
  if (prePrReviewPolicy.enabled && f.prePrReview.status !== "Done") {
7310
7454
  return tr(lang, "cli", "context.list.completePrePrReview");
7311
7455
  }
7312
- if (prePrReviewPolicy.enabled && prePrReviewPolicy.findings === "required" && (!f.docs.prePrFindingsFieldExists || !f.prePrReview.findingsProvided)) {
7313
- return tr(lang, "cli", "context.list.addPrePrFindings");
7314
- }
7315
7456
  if (prePrReviewPolicy.enabled && (!f.docs.prePrEvidenceFieldExists || !f.prePrReview.evidenceProvided)) {
7316
7457
  return tr(lang, "cli", "context.list.addPrePrEvidence");
7317
7458
  }
@@ -7376,14 +7517,11 @@ function toCompactFeature(feature) {
7376
7517
  tasks: feature.tasks,
7377
7518
  prePrReview: {
7378
7519
  status: feature.prePrReview.status,
7379
- findings: feature.prePrReview.findings,
7380
- findingsProvided: feature.prePrReview.findingsProvided,
7381
7520
  evidenceProvided: feature.prePrReview.evidenceProvided,
7382
7521
  decisionOutcome: feature.prePrReview.decisionOutcome,
7383
7522
  decisionProvided: feature.prePrReview.decisionProvided
7384
7523
  },
7385
7524
  prReview: {
7386
- findings: feature.prReview.findings,
7387
7525
  evidenceProvided: feature.prReview.evidenceProvided,
7388
7526
  decisionProvided: feature.prReview.decisionProvided
7389
7527
  },
@@ -7415,10 +7553,8 @@ function toCompactFeature(feature) {
7415
7553
  prFieldExists: feature.docs.prFieldExists,
7416
7554
  prStatusFieldExists: feature.docs.prStatusFieldExists,
7417
7555
  prePrReviewFieldExists: feature.docs.prePrReviewFieldExists,
7418
- prePrFindingsFieldExists: feature.docs.prePrFindingsFieldExists,
7419
7556
  prePrEvidenceFieldExists: feature.docs.prePrEvidenceFieldExists,
7420
7557
  prePrDecisionFieldExists: feature.docs.prePrDecisionFieldExists,
7421
- prReviewFindingsFieldExists: feature.docs.prReviewFindingsFieldExists,
7422
7558
  prReviewEvidenceFieldExists: feature.docs.prReviewEvidenceFieldExists,
7423
7559
  prReviewDecisionFieldExists: feature.docs.prReviewDecisionFieldExists
7424
7560
  },
@@ -7520,6 +7656,30 @@ async function runContext(featureName, options) {
7520
7656
  selectedComponent
7521
7657
  );
7522
7658
  const suggestionFinalPrompt = buildSuggestionFinalPrompt(lang, suggestionOptions);
7659
+ const checkRequiredLabels = state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.label);
7660
+ const checkRequiredCategories = [
7661
+ ...new Set(
7662
+ state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.action.category || "uncategorized")
7663
+ )
7664
+ ];
7665
+ const approvalRequired = checkRequiredLabels.length > 0;
7666
+ const finalApprovalPrompt = approvalRequired ? buildFinalApprovalPrompt(lang, state.actionOptions) : "";
7667
+ const approvalUserFacingLines = approvalRequired ? [
7668
+ ...state.actionOptions.map((o) => o.approvalPrompt),
7669
+ finalApprovalPrompt
7670
+ ].filter((line) => line.length > 0) : [];
7671
+ const autoRunPlan = resolveAutoRunPlan(
7672
+ lang,
7673
+ state,
7674
+ featureName,
7675
+ selectedComponent,
7676
+ config.approval,
7677
+ approvalRequired
7678
+ );
7679
+ const agentOrchestration = buildAgentOrchestrationPolicy(
7680
+ state.actionOptions,
7681
+ autoRunPlan.available
7682
+ );
7523
7683
  if (options.approve || options.execute) {
7524
7684
  await runApprovedOption(
7525
7685
  state,
@@ -7534,18 +7694,6 @@ async function runContext(featureName, options) {
7534
7694
  const jsonMode = !!options.json || !!options.jsonCompact;
7535
7695
  if (jsonMode) {
7536
7696
  const primaryAction = state.actionOptions[0] ?? null;
7537
- const checkRequiredLabels = state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.label);
7538
- const checkRequiredCategories = [
7539
- ...new Set(
7540
- state.actionOptions.filter((option) => !!option.action.requiresUserCheck).map((option) => option.action.category || "uncategorized")
7541
- )
7542
- ];
7543
- const approvalRequired = checkRequiredLabels.length > 0;
7544
- const finalApprovalPrompt = approvalRequired ? buildFinalApprovalPrompt(lang, state.actionOptions) : "";
7545
- const approvalUserFacingLines = approvalRequired ? [
7546
- ...state.actionOptions.map((o) => o.approvalPrompt),
7547
- finalApprovalPrompt
7548
- ].filter((line) => line.length > 0) : [];
7549
7697
  const approveCommand = buildApprovalCommand(
7550
7698
  state,
7551
7699
  featureName,
@@ -7607,6 +7755,15 @@ async function runContext(featureName, options) {
7607
7755
  contextVersion: state.contextVersion,
7608
7756
  config: config.approval ?? { mode: "builtin" }
7609
7757
  },
7758
+ agentOrchestration,
7759
+ autoRun: {
7760
+ available: autoRunPlan.available,
7761
+ reasonCode: autoRunPlan.reasonCode,
7762
+ summary: autoRunPlan.summary,
7763
+ command: autoRunPlan.command,
7764
+ untilCategories: autoRunPlan.untilCategories,
7765
+ unknownCategories: autoRunPlan.unknownCategories
7766
+ },
7610
7767
  approvalRequest: {
7611
7768
  required: approvalRequired,
7612
7769
  finalPrompt: finalApprovalPrompt,
@@ -7680,14 +7837,24 @@ async function runContext(featureName, options) {
7680
7837
  "actionOptions[].detail",
7681
7838
  "actionOptions[].approvalPrompt"
7682
7839
  ] : [],
7683
- recommendation: "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user. Keep `requiredDocs`, `checkPolicy`, and raw execution commands as internal guidance. For commit actions, include scope (`docs`/`project`) and commit message in the visible prompt. User replies should include the label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`). For command execution, prefer one-shot `npx lee-spec-kit flow <featureRef> --approve <LABEL> --execute` to avoid session mismatch after context compression/reset. Use ticket-based `context --execute --ticket` only when explicitly needed.",
7840
+ recommendation: "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user. Keep `requiredDocs`, `checkPolicy`, and raw execution commands as internal guidance. For commit actions, include scope (`docs`/`project`) and commit message in the visible prompt. User replies should include the label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`). For command execution, prefer one-shot `npx lee-spec-kit flow <featureRef> --approve <LABEL> --execute` to avoid session mismatch after context compression/reset. Use ticket-based `context --execute --ticket` only when explicitly needed. Use main-agent orchestration: keep short steps in main agent, and delegate only long-running command/auto loops to sub-agents.",
7684
7841
  oneApprovalPerAction: approvalRequired,
7685
7842
  requireFreshContext: true,
7686
7843
  contextVersion: state.contextVersion,
7687
7844
  config: config.approval ?? { mode: "builtin" }
7688
7845
  },
7846
+ agentOrchestration,
7847
+ autoRun: {
7848
+ available: autoRunPlan.available,
7849
+ reasonCode: autoRunPlan.reasonCode,
7850
+ summary: autoRunPlan.summary,
7851
+ command: autoRunPlan.command,
7852
+ untilCategories: autoRunPlan.untilCategories,
7853
+ unknownCategories: autoRunPlan.unknownCategories,
7854
+ guidance: "Use auto-run only when `autoRun.available=true`. Stop and request approval when `approvalRequest.required=true` or when auto mode reaches configured gate categories."
7855
+ },
7689
7856
  approvalRequest: {
7690
- guidance: "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`. Do not expose `requiredDocs`, `checkPolicy`, or raw `cmd` unless explicitly requested. For approved command actions, prefer one-shot `flow --approve <LABEL> --execute`.",
7857
+ guidance: "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`. Do not expose `requiredDocs`, `checkPolicy`, or raw `cmd` unless explicitly requested. For approved command actions, prefer one-shot `flow --approve <LABEL> --execute`. Keep short steps in main agent and delegate only long-running command/auto loops to sub-agents.",
7691
7858
  required: approvalRequired,
7692
7859
  finalPrompt: finalApprovalPrompt,
7693
7860
  userFacingLines: approvalUserFacingLines,
@@ -7899,7 +8066,7 @@ async function runContext(featureName, options) {
7899
8066
  const f = state.targetFeatures[0];
7900
8067
  const stepName = stepsMap[f.currentStep] || "Unknown";
7901
8068
  const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk6.yellow(tr(lang, "cli", "context.checkRequired")) : "";
7902
- const hasCheckAction = (f.actions || []).some((a) => !!a.requiresUserCheck);
8069
+ const hasCheckAction = approvalRequired;
7903
8070
  console.log(
7904
8071
  `\u{1F539} Feature: ${chalk6.bold(f.folderName)} ${config.projectType === "multi" ? chalk6.cyan(`(${f.type})`) : ""}`
7905
8072
  );
@@ -7909,7 +8076,7 @@ async function runContext(featureName, options) {
7909
8076
  if (f.issueNumber) {
7910
8077
  console.log(` \u2022 Issue: #${f.issueNumber}`);
7911
8078
  }
7912
- console.log(` \u2022 Path: ${path22.relative(cwd, f.path)}`);
8079
+ console.log(` \u2022 Path: ${path23.relative(cwd, f.path)}`);
7913
8080
  if (f.git.projectBranch) {
7914
8081
  console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
7915
8082
  }
@@ -7943,6 +8110,11 @@ async function runContext(featureName, options) {
7943
8110
  return;
7944
8111
  }
7945
8112
  const actionOptions = state.actionOptions;
8113
+ const hasCommandOption = actionOptions.some((option) => option.action.type === "command");
8114
+ const longRunningDelegation = shouldDelegateCurrentAction(
8115
+ actionOptions,
8116
+ autoRunPlan.available
8117
+ );
7946
8118
  console.log(chalk6.green(chalk6.bold("\u{1F449} Next Options (Atomic):")));
7947
8119
  let hasDocsCommand = false;
7948
8120
  actionOptions.forEach((option) => {
@@ -7956,6 +8128,9 @@ async function runContext(featureName, options) {
7956
8128
  if (hasDocsCommand) {
7957
8129
  console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`));
7958
8130
  }
8131
+ if (hasCommandOption && longRunningDelegation.shouldDelegate) {
8132
+ console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.subAgentOrchestrationHint")}`));
8133
+ }
7959
8134
  if (hasCheckAction) {
7960
8135
  console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.actionOptionHint")}`));
7961
8136
  console.log(chalk6.gray(` \u21B3 ${tr(lang, "cli", "context.actionExplainHint")}`));
@@ -7971,8 +8146,17 @@ async function runContext(featureName, options) {
7971
8146
  );
7972
8147
  }
7973
8148
  }
8149
+ if (autoRunPlan.available) {
8150
+ console.log(chalk6.gray(` \u21B3 ${autoRunPlan.summary}`));
8151
+ console.log(
8152
+ chalk6.gray(
8153
+ ` \u21B3 ${tr(lang, "cli", "context.autoRunCommandHint", {
8154
+ command: autoRunPlan.command
8155
+ })}`
8156
+ )
8157
+ );
8158
+ }
7974
8159
  if (actionOptions.length > 0 && hasCheckAction) {
7975
- const finalApprovalPrompt = buildFinalApprovalPrompt(lang, actionOptions);
7976
8160
  const approveCommand = buildApprovalCommand(
7977
8161
  state,
7978
8162
  featureName,
@@ -8264,7 +8448,7 @@ var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
8264
8448
  ]);
8265
8449
  function formatPath(cwd, p) {
8266
8450
  if (!p) return "";
8267
- return path22.isAbsolute(p) ? path22.relative(cwd, p) : p;
8451
+ return path23.isAbsolute(p) ? path23.relative(cwd, p) : p;
8268
8452
  }
8269
8453
  function detectPlaceholders(content) {
8270
8454
  const patterns = [
@@ -8413,7 +8597,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
8413
8597
  const placeholderContext = {
8414
8598
  projectName: config.projectName,
8415
8599
  featureName: f.slug,
8416
- featurePath: f.docs.featurePathFromDocs || path22.relative(config.docsDir, f.path),
8600
+ featurePath: f.docs.featurePathFromDocs || path23.relative(config.docsDir, f.path),
8417
8601
  repoType: f.type,
8418
8602
  featureNumber
8419
8603
  };
@@ -8423,9 +8607,9 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
8423
8607
  "tasks.md"
8424
8608
  ];
8425
8609
  for (const file of files) {
8426
- const fullPath = path22.join(f.path, file);
8427
- if (!await fs16.pathExists(fullPath)) continue;
8428
- const original = await fs16.readFile(fullPath, "utf-8");
8610
+ const fullPath = path23.join(f.path, file);
8611
+ if (!await fs17.pathExists(fullPath)) continue;
8612
+ const original = await fs17.readFile(fullPath, "utf-8");
8429
8613
  let next = original;
8430
8614
  const changes = [];
8431
8615
  const placeholderFix = applyPlaceholderFixes(next, placeholderContext, config.lang);
@@ -8449,7 +8633,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
8449
8633
  }
8450
8634
  if (next === original) continue;
8451
8635
  if (!dryRun) {
8452
- await fs16.writeFile(fullPath, next, "utf-8");
8636
+ await fs17.writeFile(fullPath, next, "utf-8");
8453
8637
  }
8454
8638
  entries.push({
8455
8639
  path: formatPath(cwd, fullPath),
@@ -8468,8 +8652,8 @@ async function checkDocsStructure(config, cwd) {
8468
8652
  const issues = [];
8469
8653
  const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
8470
8654
  for (const dir of requiredDirs) {
8471
- const p = path22.join(config.docsDir, dir);
8472
- if (!await fs16.pathExists(p)) {
8655
+ const p = path23.join(config.docsDir, dir);
8656
+ if (!await fs17.pathExists(p)) {
8473
8657
  issues.push({
8474
8658
  level: "error",
8475
8659
  code: "missing_dir",
@@ -8478,8 +8662,8 @@ async function checkDocsStructure(config, cwd) {
8478
8662
  });
8479
8663
  }
8480
8664
  }
8481
- const configPath = path22.join(config.docsDir, ".lee-spec-kit.json");
8482
- if (!await fs16.pathExists(configPath)) {
8665
+ const configPath = path23.join(config.docsDir, ".lee-spec-kit.json");
8666
+ if (!await fs17.pathExists(configPath)) {
8483
8667
  issues.push({
8484
8668
  level: "warn",
8485
8669
  code: "missing_config",
@@ -8501,7 +8685,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8501
8685
  }
8502
8686
  const idMap = /* @__PURE__ */ new Map();
8503
8687
  for (const f of features) {
8504
- const rel = f.docs.featurePathFromDocs || path22.relative(config.docsDir, f.path);
8688
+ const rel = f.docs.featurePathFromDocs || path23.relative(config.docsDir, f.path);
8505
8689
  const id = f.id || "UNKNOWN";
8506
8690
  if (!idMap.has(id)) idMap.set(id, []);
8507
8691
  idMap.get(id).push(rel);
@@ -8509,9 +8693,9 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8509
8693
  if (!isInitialTemplateState) {
8510
8694
  const featureDocs = ["spec.md", "plan.md", "tasks.md"];
8511
8695
  for (const file of featureDocs) {
8512
- const p = path22.join(f.path, file);
8513
- if (!await fs16.pathExists(p)) continue;
8514
- const content = await fs16.readFile(p, "utf-8");
8696
+ const p = path23.join(f.path, file);
8697
+ if (!await fs17.pathExists(p)) continue;
8698
+ const content = await fs17.readFile(p, "utf-8");
8515
8699
  const placeholders = detectPlaceholders(content);
8516
8700
  if (placeholders.length === 0) continue;
8517
8701
  issues.push({
@@ -8524,9 +8708,9 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8524
8708
  });
8525
8709
  }
8526
8710
  if (decisionsPlaceholderMode !== "off") {
8527
- const decisionsPath = path22.join(f.path, "decisions.md");
8528
- if (await fs16.pathExists(decisionsPath)) {
8529
- const content = await fs16.readFile(decisionsPath, "utf-8");
8711
+ const decisionsPath = path23.join(f.path, "decisions.md");
8712
+ if (await fs17.pathExists(decisionsPath)) {
8713
+ const content = await fs17.readFile(decisionsPath, "utf-8");
8530
8714
  const placeholders = detectPlaceholders(content);
8531
8715
  if (placeholders.length > 0) {
8532
8716
  issues.push({
@@ -8553,7 +8737,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8553
8737
  level: "warn",
8554
8738
  code: "spec_status_unset",
8555
8739
  message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
8556
- path: formatPath(cwd, path22.join(f.path, "spec.md"))
8740
+ path: formatPath(cwd, path23.join(f.path, "spec.md"))
8557
8741
  });
8558
8742
  }
8559
8743
  if (f.docs.planExists && !f.planStatus && !isInitialTemplateState) {
@@ -8561,7 +8745,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8561
8745
  level: "warn",
8562
8746
  code: "plan_status_unset",
8563
8747
  message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
8564
- path: formatPath(cwd, path22.join(f.path, "plan.md"))
8748
+ path: formatPath(cwd, path23.join(f.path, "plan.md"))
8565
8749
  });
8566
8750
  }
8567
8751
  if (f.docs.tasksExists && f.tasks.total === 0 && !isInitialTemplateState) {
@@ -8569,7 +8753,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8569
8753
  level: "warn",
8570
8754
  code: "tasks_empty",
8571
8755
  message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
8572
- path: formatPath(cwd, path22.join(f.path, "tasks.md"))
8756
+ path: formatPath(cwd, path23.join(f.path, "tasks.md"))
8573
8757
  });
8574
8758
  }
8575
8759
  if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists && !isInitialTemplateState) {
@@ -8577,7 +8761,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8577
8761
  level: "warn",
8578
8762
  code: "tasks_doc_status_missing",
8579
8763
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
8580
- path: formatPath(cwd, path22.join(f.path, "tasks.md"))
8764
+ path: formatPath(cwd, path23.join(f.path, "tasks.md"))
8581
8765
  });
8582
8766
  }
8583
8767
  if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus && !isInitialTemplateState) {
@@ -8585,7 +8769,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8585
8769
  level: "warn",
8586
8770
  code: "tasks_doc_status_unset",
8587
8771
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
8588
- path: formatPath(cwd, path22.join(f.path, "tasks.md"))
8772
+ path: formatPath(cwd, path23.join(f.path, "tasks.md"))
8589
8773
  });
8590
8774
  }
8591
8775
  }
@@ -8609,7 +8793,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
8609
8793
  level: "warn",
8610
8794
  code: "missing_feature_id",
8611
8795
  message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
8612
- path: formatPath(cwd, path22.join(config.docsDir, p))
8796
+ path: formatPath(cwd, path23.join(config.docsDir, p))
8613
8797
  });
8614
8798
  }
8615
8799
  return issues;
@@ -8732,7 +8916,7 @@ function doctorCommand(program2) {
8732
8916
  }
8733
8917
  console.log();
8734
8918
  console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
8735
- console.log(chalk6.gray(`- Docs: ${path22.relative(cwd, docsDir)}`));
8919
+ console.log(chalk6.gray(`- Docs: ${path23.relative(cwd, docsDir)}`));
8736
8920
  console.log(chalk6.gray(`- Type: ${projectType}`));
8737
8921
  console.log(chalk6.gray(`- Lang: ${lang}`));
8738
8922
  console.log();
@@ -8904,7 +9088,7 @@ async function runView(featureName, options) {
8904
9088
  }
8905
9089
  console.log();
8906
9090
  console.log(chalk6.bold("\u{1F4CA} Workflow View"));
8907
- console.log(chalk6.gray(`- Docs: ${path22.relative(cwd, config.docsDir)}`));
9091
+ console.log(chalk6.gray(`- Docs: ${path23.relative(cwd, config.docsDir)}`));
8908
9092
  console.log(
8909
9093
  chalk6.gray(
8910
9094
  `- Features: ${state.features.length} (open ${state.openFeatures.length} / done ${state.doneFeatures.length})`
@@ -8974,9 +9158,145 @@ async function runView(featureName, options) {
8974
9158
  }
8975
9159
  console.log();
8976
9160
  }
9161
+ function normalizeRunId(raw) {
9162
+ const value = raw.trim();
9163
+ if (!/^[A-Za-z0-9_-]{6,64}$/.test(value)) {
9164
+ throw createCliError(
9165
+ "INVALID_ARGUMENT",
9166
+ "Invalid flow run id format. Use an id returned by `flow --start-auto --json`."
9167
+ );
9168
+ }
9169
+ return value;
9170
+ }
9171
+ function getFlowRunBaseDir(cwd) {
9172
+ return path23.join(getRuntimeStateDir(cwd), "flow-runs");
9173
+ }
9174
+ function getFlowRunPath(cwd, runId) {
9175
+ return path23.join(getFlowRunBaseDir(cwd), `${runId}.json`);
9176
+ }
9177
+ function getFlowRunLockPath(cwd, runId) {
9178
+ return path23.join(getRuntimeStateDir(cwd), "locks", `flow-run-${runId}.lock`);
9179
+ }
9180
+ async function readFlowRunRecordUnsafe(cwd, runId) {
9181
+ const normalized = normalizeRunId(runId);
9182
+ const filePath = getFlowRunPath(cwd, normalized);
9183
+ if (!await fs17.pathExists(filePath)) {
9184
+ throw createCliError(
9185
+ "INVALID_ARGUMENT",
9186
+ `Unknown flow run id: ${normalized}. Start with \`flow <feature> --auto-... --start-auto\`.`
9187
+ );
9188
+ }
9189
+ try {
9190
+ const parsed = await fs17.readJson(filePath);
9191
+ if (!parsed || typeof parsed !== "object" || parsed.runId !== normalized) {
9192
+ throw new Error("invalid payload");
9193
+ }
9194
+ return parsed;
9195
+ } catch {
9196
+ throw createCliError(
9197
+ "INVALID_ARGUMENT",
9198
+ `Cannot load flow run record: ${normalized}`
9199
+ );
9200
+ }
9201
+ }
9202
+ async function writeFlowRunRecord(cwd, record) {
9203
+ const filePath = getFlowRunPath(cwd, record.runId);
9204
+ await fs17.ensureDir(path23.dirname(filePath));
9205
+ await fs17.writeJson(filePath, record, { spaces: 2 });
9206
+ }
9207
+ async function createFlowRunRecord(cwd, input) {
9208
+ const runId = randomUUID().replace(/-/g, "").slice(0, 16);
9209
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
9210
+ const record = {
9211
+ runId,
9212
+ featureName: input.featureName,
9213
+ selection: {
9214
+ component: input.selection.component || void 0,
9215
+ all: !!input.selection.all,
9216
+ done: !!input.selection.done
9217
+ },
9218
+ auto: {
9219
+ untilCategories: [...input.auto.untilCategories],
9220
+ requestText: input.auto.requestText?.trim() || void 0,
9221
+ requestPending: input.auto.requestPending,
9222
+ preset: input.auto.preset ?? null,
9223
+ source: input.auto.source ?? null
9224
+ },
9225
+ status: "running",
9226
+ createdAt: nowIso,
9227
+ updatedAt: nowIso
9228
+ };
9229
+ const lockPath = getFlowRunLockPath(cwd, runId);
9230
+ return withFileLock(
9231
+ lockPath,
9232
+ async () => {
9233
+ await writeFlowRunRecord(cwd, record);
9234
+ return record;
9235
+ },
9236
+ { owner: "flow-run:create" }
9237
+ );
9238
+ }
9239
+ async function getFlowRunRecord(cwd, runId) {
9240
+ const normalized = normalizeRunId(runId);
9241
+ return readFlowRunRecordUnsafe(cwd, normalized);
9242
+ }
9243
+ async function updateFlowRunRecord(cwd, runId, updater) {
9244
+ const normalized = normalizeRunId(runId);
9245
+ const lockPath = getFlowRunLockPath(cwd, normalized);
9246
+ return withFileLock(
9247
+ lockPath,
9248
+ async () => {
9249
+ const current = await readFlowRunRecordUnsafe(cwd, normalized);
9250
+ const next = updater(current);
9251
+ const updated = {
9252
+ ...next,
9253
+ runId: normalized,
9254
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
9255
+ };
9256
+ await writeFlowRunRecord(cwd, updated);
9257
+ return updated;
9258
+ },
9259
+ { owner: "flow-run:update" }
9260
+ );
9261
+ }
9262
+
9263
+ // src/commands/flow.ts
9264
+ var LONG_RUNNING_DELEGATION_CATEGORIES2 = [
9265
+ "task_execute",
9266
+ "code_review",
9267
+ "review_fix_commit",
9268
+ "pre_pr_review"
9269
+ ];
8977
9270
  var BUILTIN_AUTO_PRESETS = {
8978
9271
  "pr-handoff": ["pr_create", "code_review", "pr_status_update"]
8979
9272
  };
9273
+ function shellEscape(arg) {
9274
+ if (/^[A-Za-z0-9_./:@%-]+$/.test(arg)) return arg;
9275
+ return `'${arg.replace(/'/g, `'\\''`)}'`;
9276
+ }
9277
+ function toLeeSpecKitCommand(args) {
9278
+ return ["npx", "lee-spec-kit", ...args].map((arg) => shellEscape(arg)).join(" ");
9279
+ }
9280
+ function buildResumeRunCommand(runId) {
9281
+ return toLeeSpecKitCommand(["flow", "--resume", runId]);
9282
+ }
9283
+ function buildAutoResume(featureName, selectionOptions, untilCategories, requestText, requestPending) {
9284
+ const selectionArgs = buildSelectionArgs(featureName, selectionOptions);
9285
+ const flowArgs = ["flow", ...selectionArgs];
9286
+ if (requestPending && requestText) {
9287
+ flowArgs.push("--request", requestText);
9288
+ }
9289
+ flowArgs.push("--auto-until-category", untilCategories.join(","));
9290
+ const contextArgs = ["context", ...selectionArgs];
9291
+ return {
9292
+ flowArgs,
9293
+ flowCommand: toLeeSpecKitCommand(flowArgs),
9294
+ contextArgs,
9295
+ contextCommand: toLeeSpecKitCommand(contextArgs),
9296
+ requiresFreshContext: true,
9297
+ requestPending
9298
+ };
9299
+ }
8980
9300
  function runSelfCli(args) {
8981
9301
  const entry = process.argv[1];
8982
9302
  const result = spawnSync(process.execPath, [entry, "--no-banner", ...args], {
@@ -9165,6 +9485,51 @@ function toAutoReasonCode(status) {
9165
9485
  function isAutoRunFailureStatus(status) {
9166
9486
  return status === "manual_required" || status === "selection_required" || status === "no_progress" || status === "request_label_missing" || status === "request_failed" || status === "execution_failed";
9167
9487
  }
9488
+ function toFlowRunStatus(status) {
9489
+ switch (status) {
9490
+ case "gate_reached":
9491
+ case "manual_required":
9492
+ return "paused";
9493
+ case "no_action_options":
9494
+ return "completed";
9495
+ case "selection_required":
9496
+ case "no_progress":
9497
+ case "request_label_missing":
9498
+ case "request_failed":
9499
+ case "execution_failed":
9500
+ default:
9501
+ return "failed";
9502
+ }
9503
+ }
9504
+ function buildAgentOrchestrationPolicy2(autoRun) {
9505
+ const preferredResumeCommand = autoRun?.run?.resumeCommand || autoRun?.resume?.flowCommand || null;
9506
+ return {
9507
+ mode: "main_orchestrates_subagent_execution",
9508
+ delegationPolicy: "prefer_main_delegate_long_running_fallback_main",
9509
+ delegateCommandExecution: "long_running_only",
9510
+ delegateAutoRunExecution: true,
9511
+ fallbackToMainAgentWhenSubAgentUnavailable: true,
9512
+ longRunningCategories: [...LONG_RUNNING_DELEGATION_CATEGORIES2],
9513
+ mainAgentResponsibilities: [
9514
+ "Keep user conversation state and approval boundaries",
9515
+ "Run the same execution loop directly when sub-agent is unavailable",
9516
+ "Delegate only long-running command/auto loops to sub-agents",
9517
+ "Report only on approval/manual/error boundaries"
9518
+ ],
9519
+ subAgentResponsibilities: [
9520
+ "Run flow/context command loops",
9521
+ "Execute selected atomic command actions",
9522
+ "Return structured status and errors to main agent"
9523
+ ],
9524
+ pauseAndReportWhen: [
9525
+ "approvalRequest.required=true",
9526
+ "AUTO_GATE_REACHED",
9527
+ "AUTO_MANUAL_REQUIRED",
9528
+ "command execution error"
9529
+ ],
9530
+ preferredResumeCommand
9531
+ };
9532
+ }
9168
9533
  async function runAutoUntilCategory(config, featureName, selectionOptions, untilCategories, requestText, metadata) {
9169
9534
  const contextArgs = ["context", ...buildSelectionArgs(featureName, selectionOptions)];
9170
9535
  const gateSet = new Set(untilCategories);
@@ -9175,6 +9540,13 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9175
9540
  let requestHandled = !requestText;
9176
9541
  let iterations = 0;
9177
9542
  while (true) {
9543
+ const resume = buildAutoResume(
9544
+ featureName,
9545
+ selectionOptions,
9546
+ untilCategories,
9547
+ requestText,
9548
+ !requestHandled
9549
+ );
9178
9550
  iterations += 1;
9179
9551
  const state = await resolveContextSelection(config, featureName, selectionOptions);
9180
9552
  const actionOptions = state.actionOptions;
@@ -9200,6 +9572,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9200
9572
  request: requestText,
9201
9573
  preset: metadata?.preset ?? null,
9202
9574
  source: metadata?.source ?? null,
9575
+ resume,
9203
9576
  status: "no_progress",
9204
9577
  reasonCode: toAutoReasonCode("no_progress"),
9205
9578
  iterations,
@@ -9216,6 +9589,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9216
9589
  request: requestText,
9217
9590
  preset: metadata?.preset ?? null,
9218
9591
  source: metadata?.source ?? null,
9592
+ resume,
9219
9593
  status: "selection_required",
9220
9594
  reasonCode: toAutoReasonCode("selection_required"),
9221
9595
  iterations,
@@ -9232,6 +9606,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9232
9606
  request: requestText,
9233
9607
  preset: metadata?.preset ?? null,
9234
9608
  source: metadata?.source ?? null,
9609
+ resume,
9235
9610
  status: "no_action_options",
9236
9611
  reasonCode: toAutoReasonCode("no_action_options"),
9237
9612
  iterations,
@@ -9251,6 +9626,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9251
9626
  request: requestText,
9252
9627
  preset: metadata?.preset ?? null,
9253
9628
  source: metadata?.source ?? null,
9629
+ resume,
9254
9630
  status: "request_label_missing",
9255
9631
  reasonCode: toAutoReasonCode("request_label_missing"),
9256
9632
  iterations,
@@ -9284,6 +9660,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9284
9660
  request: requestText,
9285
9661
  preset: metadata?.preset ?? null,
9286
9662
  source: metadata?.source ?? null,
9663
+ resume,
9287
9664
  status: "request_failed",
9288
9665
  reasonCode: toAutoReasonCode("request_failed"),
9289
9666
  iterations,
@@ -9307,6 +9684,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9307
9684
  request: requestText,
9308
9685
  preset: metadata?.preset ?? null,
9309
9686
  source: metadata?.source ?? null,
9687
+ resume,
9310
9688
  status: "gate_reached",
9311
9689
  reasonCode: toAutoReasonCode("gate_reached"),
9312
9690
  iterations,
@@ -9329,6 +9707,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9329
9707
  request: requestText,
9330
9708
  preset: metadata?.preset ?? null,
9331
9709
  source: metadata?.source ?? null,
9710
+ resume,
9332
9711
  status: "manual_required",
9333
9712
  reasonCode: toAutoReasonCode("manual_required"),
9334
9713
  iterations,
@@ -9364,6 +9743,7 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9364
9743
  request: requestText,
9365
9744
  preset: metadata?.preset ?? null,
9366
9745
  source: metadata?.source ?? null,
9746
+ resume,
9367
9747
  status: "execution_failed",
9368
9748
  reasonCode: toAutoReasonCode("execution_failed"),
9369
9749
  iterations,
@@ -9399,6 +9779,9 @@ async function runAutoUntilCategory(config, featureName, selectionOptions, until
9399
9779
  enabled: true,
9400
9780
  untilCategories,
9401
9781
  request: requestText,
9782
+ preset: metadata?.preset ?? null,
9783
+ source: metadata?.source ?? null,
9784
+ resume,
9402
9785
  status: "execution_failed",
9403
9786
  reasonCode: toAutoReasonCode("execution_failed"),
9404
9787
  iterations,
@@ -9420,6 +9803,12 @@ function flowCommand(program2) {
9420
9803
  ).option(
9421
9804
  "--auto-until-category <categories>",
9422
9805
  "Auto-run command actions until one of categories appears (comma-separated)"
9806
+ ).option(
9807
+ "--start-auto",
9808
+ "Persist auto-run checkpoint and emit resumable run id in JSON output"
9809
+ ).option(
9810
+ "--resume <run-id>",
9811
+ "Resume previously started auto-run checkpoint by run id"
9423
9812
  ).option(
9424
9813
  "--approve <reply>",
9425
9814
  "Approve one labeled context option (examples: A, A OK, A proceed, A \uC9C4\uD589\uD574)"
@@ -9475,14 +9864,79 @@ async function runFlow(featureName, options) {
9475
9864
  "`--execute` requires `--approve <reply>`."
9476
9865
  );
9477
9866
  }
9478
- const requestText = options.request?.trim() || void 0;
9867
+ const resumeRunId = (options.resume || "").trim() || void 0;
9868
+ if (options.startAuto && resumeRunId) {
9869
+ throw createCliError(
9870
+ "INVALID_ARGUMENT",
9871
+ "`--start-auto` cannot be combined with `--resume`."
9872
+ );
9873
+ }
9874
+ if (resumeRunId) {
9875
+ if (featureName) {
9876
+ throw createCliError(
9877
+ "INVALID_ARGUMENT",
9878
+ "`--resume` cannot be combined with <feature-name>."
9879
+ );
9880
+ }
9881
+ if (options.autoPreset || options.autoUntilCategory || options.request) {
9882
+ throw createCliError(
9883
+ "INVALID_ARGUMENT",
9884
+ "`--resume` cannot be combined with `--auto-*` or `--request`."
9885
+ );
9886
+ }
9887
+ if (options.component || options.all || options.done) {
9888
+ throw createCliError(
9889
+ "INVALID_ARGUMENT",
9890
+ "`--resume` cannot be combined with `--component`, `--all`, or `--done`."
9891
+ );
9892
+ }
9893
+ }
9894
+ let requestText = options.request?.trim() || void 0;
9479
9895
  if (options.autoPreset && options.autoUntilCategory) {
9480
9896
  throw createCliError(
9481
9897
  "INVALID_ARGUMENT",
9482
9898
  "`--auto-preset` cannot be combined with `--auto-until-category`."
9483
9899
  );
9484
9900
  }
9485
- const autoMode = resolveAutoMode(config, options, requestText);
9901
+ let resolvedFeatureName = featureName;
9902
+ let selectedComponent = resolveComponentOption(options.component);
9903
+ const selectionOptions = {
9904
+ component: selectedComponent,
9905
+ all: options.all,
9906
+ done: options.done
9907
+ };
9908
+ let autoMode = resolveAutoMode(config, options, requestText);
9909
+ let flowRunRecord = null;
9910
+ let flowRunMode = null;
9911
+ if (resumeRunId) {
9912
+ flowRunRecord = await getFlowRunRecord(process.cwd(), resumeRunId);
9913
+ if (flowRunRecord.status === "completed") {
9914
+ throw createCliError(
9915
+ "INVALID_ARGUMENT",
9916
+ `Flow run ${resumeRunId} is already completed.`
9917
+ );
9918
+ }
9919
+ resolvedFeatureName = flowRunRecord.featureName;
9920
+ selectedComponent = resolveComponentOption(flowRunRecord.selection.component);
9921
+ selectionOptions.component = selectedComponent;
9922
+ selectionOptions.all = !!flowRunRecord.selection.all;
9923
+ selectionOptions.done = !!flowRunRecord.selection.done;
9924
+ requestText = flowRunRecord.auto.requestPending ? flowRunRecord.auto.requestText?.trim() || void 0 : void 0;
9925
+ autoMode = {
9926
+ untilCategories: [...flowRunRecord.auto.untilCategories],
9927
+ preset: flowRunRecord.auto.preset ?? null,
9928
+ source: `resume:${resumeRunId}`
9929
+ };
9930
+ flowRunMode = "resumed";
9931
+ flowRunRecord = await updateFlowRunRecord(
9932
+ process.cwd(),
9933
+ resumeRunId,
9934
+ (current) => ({
9935
+ ...current,
9936
+ status: "running"
9937
+ })
9938
+ );
9939
+ }
9486
9940
  if (autoMode && options.approve) {
9487
9941
  throw createCliError(
9488
9942
  "INVALID_ARGUMENT",
@@ -9502,26 +9956,46 @@ async function runFlow(featureName, options) {
9502
9956
  );
9503
9957
  }
9504
9958
  if (autoMode && !featureName) {
9959
+ if (!resolvedFeatureName) {
9960
+ throw createCliError(
9961
+ "CONTEXT_SELECTION_REQUIRED",
9962
+ "Auto mode requires explicit <feature-name> (e.g. F004)."
9963
+ );
9964
+ }
9965
+ }
9966
+ if (options.startAuto && !autoMode) {
9505
9967
  throw createCliError(
9506
- "CONTEXT_SELECTION_REQUIRED",
9507
- "Auto mode requires explicit <feature-name> (e.g. F004)."
9968
+ "INVALID_ARGUMENT",
9969
+ "`--start-auto` requires auto mode (`--auto-until-category` or `--auto-preset`)."
9508
9970
  );
9509
9971
  }
9510
- const selectedComponent = resolveComponentOption(options.component);
9511
- const selectionOptions = {
9512
- component: selectedComponent,
9513
- all: options.all,
9514
- done: options.done
9515
- };
9972
+ if (options.startAuto && autoMode && !flowRunRecord && resolvedFeatureName) {
9973
+ flowRunRecord = await createFlowRunRecord(process.cwd(), {
9974
+ featureName: resolvedFeatureName,
9975
+ selection: {
9976
+ component: selectedComponent || void 0,
9977
+ all: !!selectionOptions.all,
9978
+ done: !!selectionOptions.done
9979
+ },
9980
+ auto: {
9981
+ untilCategories: [...autoMode.untilCategories],
9982
+ requestText,
9983
+ requestPending: !!requestText,
9984
+ preset: autoMode.preset ?? null,
9985
+ source: autoMode.source
9986
+ }
9987
+ });
9988
+ flowRunMode = "started";
9989
+ }
9516
9990
  const componentHint = selectedComponent ? ` --component ${selectedComponent}` : "";
9517
- const before = await resolveContextSelection(config, featureName, selectionOptions);
9991
+ const before = await resolveContextSelection(config, resolvedFeatureName, selectionOptions);
9518
9992
  let approvalResult = null;
9519
9993
  let autoRun = null;
9520
- const contextArgs = ["context", ...buildSelectionArgs(featureName, selectionOptions)];
9994
+ const contextArgs = ["context", ...buildSelectionArgs(resolvedFeatureName, selectionOptions)];
9521
9995
  if (autoMode) {
9522
9996
  autoRun = await runAutoUntilCategory(
9523
9997
  config,
9524
- featureName,
9998
+ resolvedFeatureName,
9525
9999
  selectionOptions,
9526
10000
  autoMode.untilCategories,
9527
10001
  requestText,
@@ -9553,7 +10027,31 @@ async function runFlow(featureName, options) {
9553
10027
  approvalResult = selected;
9554
10028
  }
9555
10029
  }
9556
- const after = await resolveContextSelection(config, featureName, selectionOptions);
10030
+ if (autoRun && flowRunRecord && flowRunMode) {
10031
+ const runStatus2 = toFlowRunStatus(autoRun.status);
10032
+ flowRunRecord = await updateFlowRunRecord(
10033
+ process.cwd(),
10034
+ flowRunRecord.runId,
10035
+ (current) => ({
10036
+ ...current,
10037
+ status: runStatus2,
10038
+ auto: {
10039
+ ...current.auto,
10040
+ requestPending: autoRun.resume.requestPending
10041
+ },
10042
+ lastAutoStatus: autoRun.status,
10043
+ lastReasonCode: autoRun.reasonCode,
10044
+ lastError: autoRun.error
10045
+ })
10046
+ );
10047
+ autoRun.run = {
10048
+ runId: flowRunRecord.runId,
10049
+ mode: flowRunMode,
10050
+ status: flowRunRecord.status,
10051
+ resumeCommand: buildResumeRunCommand(flowRunRecord.runId)
10052
+ };
10053
+ }
10054
+ const after = await resolveContextSelection(config, resolvedFeatureName, selectionOptions);
9557
10055
  const statusReport = runSelfCliJson(["status"]);
9558
10056
  const doctorReport = runSelfCliJson(["doctor"]);
9559
10057
  let strictChecks = null;
@@ -9574,6 +10072,7 @@ async function runFlow(featureName, options) {
9574
10072
  }
9575
10073
  if (options.json) {
9576
10074
  const autoRunFailed = !!(autoRun && isAutoRunFailureStatus(autoRun.status));
10075
+ const agentOrchestration2 = buildAgentOrchestrationPolicy2(autoRun);
9577
10076
  const payload = {
9578
10077
  status: autoRunFailed ? "error" : "ok",
9579
10078
  reasonCode: autoRunFailed ? autoRun?.reasonCode || "AUTO_EXECUTION_FAILED" : "FLOW_SUMMARY",
@@ -9599,6 +10098,7 @@ async function runFlow(featureName, options) {
9599
10098
  },
9600
10099
  approval: approvalResult,
9601
10100
  autoRun,
10101
+ agentOrchestration: agentOrchestration2,
9602
10102
  statusReport,
9603
10103
  doctorReport,
9604
10104
  strictChecks,
@@ -9632,7 +10132,22 @@ async function runFlow(featureName, options) {
9632
10132
  `- Auto: ${autoRun.status} (${autoRun.reasonCode}), iterations ${autoRun.iterations}, executions ${autoRun.executions.length}${presetSuffix}`
9633
10133
  )
9634
10134
  );
10135
+ console.log(chalk6.gray(`- Auto resume: ${autoRun.resume.flowCommand}`));
10136
+ if (autoRun.run) {
10137
+ console.log(
10138
+ chalk6.gray(
10139
+ `- Auto run: ${autoRun.run.mode} ${autoRun.run.runId} (${autoRun.run.status})`
10140
+ )
10141
+ );
10142
+ console.log(chalk6.gray(`- Resume with: ${autoRun.run.resumeCommand}`));
10143
+ }
9635
10144
  }
10145
+ const agentOrchestration = buildAgentOrchestrationPolicy2(autoRun);
10146
+ console.log(
10147
+ chalk6.gray(
10148
+ `- Orchestration: ${agentOrchestration.mode}, delegate long-running loops to sub-agent`
10149
+ )
10150
+ );
9636
10151
  const statusCounts = statusReport.counts;
9637
10152
  const doctorCounts = doctorReport.counts;
9638
10153
  console.log(chalk6.gray(`- Status features: ${statusCounts?.features ?? 0}`));
@@ -9780,40 +10295,40 @@ function tg(lang, key, vars = {}) {
9780
10295
  }
9781
10296
  function detectGithubCliLangSync(cwd) {
9782
10297
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
9783
- const startDirs = [explicitDocsDir ? path22.resolve(explicitDocsDir) : "", path22.resolve(cwd)].filter(Boolean);
10298
+ const startDirs = [explicitDocsDir ? path23.resolve(explicitDocsDir) : "", path23.resolve(cwd)].filter(Boolean);
9784
10299
  const scanOrder = [];
9785
10300
  const seen = /* @__PURE__ */ new Set();
9786
10301
  for (const start of startDirs) {
9787
10302
  let current = start;
9788
10303
  while (true) {
9789
- const abs = path22.resolve(current);
10304
+ const abs = path23.resolve(current);
9790
10305
  if (!seen.has(abs)) {
9791
10306
  scanOrder.push(abs);
9792
10307
  seen.add(abs);
9793
10308
  }
9794
- const parent = path22.dirname(abs);
10309
+ const parent = path23.dirname(abs);
9795
10310
  if (parent === abs) break;
9796
10311
  current = parent;
9797
10312
  }
9798
10313
  }
9799
10314
  for (const base of scanOrder) {
9800
- for (const docsDir of [path22.join(base, "docs"), base]) {
9801
- const configPath = path22.join(docsDir, ".lee-spec-kit.json");
9802
- if (fs16.existsSync(configPath)) {
10315
+ for (const docsDir of [path23.join(base, "docs"), base]) {
10316
+ const configPath = path23.join(docsDir, ".lee-spec-kit.json");
10317
+ if (fs17.existsSync(configPath)) {
9803
10318
  try {
9804
- const parsed = fs16.readJsonSync(configPath);
10319
+ const parsed = fs17.readJsonSync(configPath);
9805
10320
  if (parsed?.lang === "ko" || parsed?.lang === "en") return parsed.lang;
9806
10321
  } catch {
9807
10322
  }
9808
10323
  }
9809
- const agentsPath = path22.join(docsDir, "agents");
9810
- const featuresPath = path22.join(docsDir, "features");
9811
- if (!fs16.existsSync(agentsPath) || !fs16.existsSync(featuresPath)) continue;
10324
+ const agentsPath = path23.join(docsDir, "agents");
10325
+ const featuresPath = path23.join(docsDir, "features");
10326
+ if (!fs17.existsSync(agentsPath) || !fs17.existsSync(featuresPath)) continue;
9812
10327
  for (const probe of ["custom.md", "constitution.md", "agents.md"]) {
9813
- const file = path22.join(agentsPath, probe);
9814
- if (!fs16.existsSync(file)) continue;
10328
+ const file = path23.join(agentsPath, probe);
10329
+ if (!fs17.existsSync(file)) continue;
9815
10330
  try {
9816
- const content = fs16.readFileSync(file, "utf-8");
10331
+ const content = fs17.readFileSync(file, "utf-8");
9817
10332
  if (/[가-힣]/.test(content)) return "ko";
9818
10333
  } catch {
9819
10334
  }
@@ -9890,8 +10405,8 @@ async function prepareGithubBody(params) {
9890
10405
  kindLabel,
9891
10406
  lang
9892
10407
  } = params;
9893
- if (create && explicitBodyFile && await fs16.pathExists(defaultBodyFile)) {
9894
- const body = await fs16.readFile(defaultBodyFile, "utf-8");
10408
+ if (create && explicitBodyFile && await fs17.pathExists(defaultBodyFile)) {
10409
+ const body = await fs17.readFile(defaultBodyFile, "utf-8");
9895
10410
  ensureSections(body, requiredSections, kindLabel, lang);
9896
10411
  return {
9897
10412
  body,
@@ -9899,8 +10414,8 @@ async function prepareGithubBody(params) {
9899
10414
  source: "explicit"
9900
10415
  };
9901
10416
  }
9902
- if (create && !explicitBodyFile && await fs16.pathExists(workflowDraftPath)) {
9903
- const body = await fs16.readFile(workflowDraftPath, "utf-8");
10417
+ if (create && !explicitBodyFile && await fs17.pathExists(workflowDraftPath)) {
10418
+ const body = await fs17.readFile(workflowDraftPath, "utf-8");
9904
10419
  const draftMetadata = parseWorkflowDraftMetadata(body);
9905
10420
  if (draftMetadata.status === "ready") {
9906
10421
  ensureSections(body, requiredSections, kindLabel, lang);
@@ -9912,8 +10427,8 @@ async function prepareGithubBody(params) {
9912
10427
  };
9913
10428
  }
9914
10429
  }
9915
- await fs16.ensureDir(path22.dirname(defaultBodyFile));
9916
- await fs16.writeFile(defaultBodyFile, generatedBody, "utf-8");
10430
+ await fs17.ensureDir(path23.dirname(defaultBodyFile));
10431
+ await fs17.writeFile(defaultBodyFile, generatedBody, "utf-8");
9917
10432
  return {
9918
10433
  body: generatedBody,
9919
10434
  bodyFile: defaultBodyFile,
@@ -9973,7 +10488,7 @@ function ensureSections(body, sections, kind, lang) {
9973
10488
  }
9974
10489
  function ensureDocsExist(docsDir, relativePaths, lang) {
9975
10490
  const missing = relativePaths.filter(
9976
- (relativePath) => !fs16.existsSync(path22.join(docsDir, relativePath))
10491
+ (relativePath) => !fs17.existsSync(path23.join(docsDir, relativePath))
9977
10492
  );
9978
10493
  if (missing.length > 0) {
9979
10494
  throw createCliError(
@@ -9983,18 +10498,18 @@ function ensureDocsExist(docsDir, relativePaths, lang) {
9983
10498
  }
9984
10499
  }
9985
10500
  function buildDefaultBodyFileName(kind, docsDir, component) {
9986
- const key = `${path22.resolve(docsDir)}::${component.trim().toLowerCase()}`;
10501
+ const key = `${path23.resolve(docsDir)}::${component.trim().toLowerCase()}`;
9987
10502
  const digest = createHash("sha1").update(key).digest("hex").slice(0, 12);
9988
10503
  return `lee-spec-kit.${digest}.${kind}.md`;
9989
10504
  }
9990
10505
  function toBodyFilePath(raw, kind, docsDir, component, lang) {
9991
- const selected = raw?.trim() || path22.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
10506
+ const selected = raw?.trim() || path23.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
9992
10507
  assertValid(
9993
10508
  validatePathWithLang(selected, lang),
9994
10509
  `github.${kind}.bodyFile`,
9995
10510
  lang
9996
10511
  );
9997
- return path22.resolve(selected);
10512
+ return path23.resolve(selected);
9998
10513
  }
9999
10514
  function toProjectRootDocsPath(relativePathFromDocs) {
10000
10515
  const normalized = relativePathFromDocs.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -10761,10 +11276,10 @@ function insertFieldInGithubIssueSection(content, key, value) {
10761
11276
  return { content: lines.join("\n"), changed: true };
10762
11277
  }
10763
11278
  function syncTasksPrMetadata(tasksPath, prUrl, nextStatus, lang) {
10764
- if (!fs16.existsSync(tasksPath)) {
11279
+ if (!fs17.existsSync(tasksPath)) {
10765
11280
  throw createCliError("DOCS_NOT_FOUND", tg(lang, "tasksNotFound", { path: tasksPath }));
10766
11281
  }
10767
- const original = fs16.readFileSync(tasksPath, "utf-8");
11282
+ const original = fs17.readFileSync(tasksPath, "utf-8");
10768
11283
  let next = original;
10769
11284
  let changed = false;
10770
11285
  const prReplaced = replaceListField(next, ["PR", "Pull Request"], prUrl);
@@ -10788,7 +11303,7 @@ function syncTasksPrMetadata(tasksPath, prUrl, nextStatus, lang) {
10788
11303
  changed = changed || inserted.changed;
10789
11304
  }
10790
11305
  if (changed) {
10791
- fs16.writeFileSync(tasksPath, next, "utf-8");
11306
+ fs17.writeFileSync(tasksPath, next, "utf-8");
10792
11307
  }
10793
11308
  return { changed, path: tasksPath };
10794
11309
  }
@@ -10816,7 +11331,7 @@ function ensureCleanWorktree(cwd, lang) {
10816
11331
  }
10817
11332
  }
10818
11333
  function commitAndPushPath(cwd, absPath, message, lang, options) {
10819
- const relativePath = path22.relative(cwd, absPath) || absPath;
11334
+ const relativePath = path23.relative(cwd, absPath) || absPath;
10820
11335
  const status = runProcessOrThrow(
10821
11336
  "git",
10822
11337
  ["status", "--porcelain=v1", "--", relativePath],
@@ -10985,9 +11500,9 @@ function githubCommand(program2) {
10985
11500
  [paths.specPath, paths.planPath, paths.tasksPath],
10986
11501
  config.lang
10987
11502
  );
10988
- const specContent = await fs16.readFile(path22.join(config.docsDir, paths.specPath), "utf-8");
10989
- const planContent = await fs16.readFile(path22.join(config.docsDir, paths.planPath), "utf-8");
10990
- const tasksContent = await fs16.readFile(path22.join(config.docsDir, paths.tasksPath), "utf-8");
11503
+ const specContent = await fs17.readFile(path23.join(config.docsDir, paths.specPath), "utf-8");
11504
+ const planContent = await fs17.readFile(path23.join(config.docsDir, paths.planPath), "utf-8");
11505
+ const tasksContent = await fs17.readFile(path23.join(config.docsDir, paths.tasksPath), "utf-8");
10991
11506
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
10992
11507
  const defaultTitle = tg(config.lang, "issueDefaultTitle", {
10993
11508
  slug: feature.slug,
@@ -11020,7 +11535,7 @@ function githubCommand(program2) {
11020
11535
  create: options.create,
11021
11536
  explicitBodyFile,
11022
11537
  defaultBodyFile,
11023
- workflowDraftPath: path22.join(config.docsDir, paths.issuePath),
11538
+ workflowDraftPath: path23.join(config.docsDir, paths.issuePath),
11024
11539
  generatedBody,
11025
11540
  requiredSections: getRequiredIssueSections(config.lang),
11026
11541
  kindLabel: tg(config.lang, "kindIssue"),
@@ -11131,10 +11646,10 @@ function githubCommand(program2) {
11131
11646
  const generatedLabels = parseLabels(optionLabels || void 0, config.lang);
11132
11647
  const paths = getFeatureDocPaths(feature);
11133
11648
  ensureDocsExist(config.docsDir, [paths.specPath, paths.tasksPath], config.lang);
11134
- const specContent = await fs16.readFile(path22.join(config.docsDir, paths.specPath), "utf-8");
11135
- const planPath = path22.join(config.docsDir, paths.planPath);
11136
- const planContent = await fs16.pathExists(planPath) ? await fs16.readFile(planPath, "utf-8") : "";
11137
- const tasksContent = await fs16.readFile(path22.join(config.docsDir, paths.tasksPath), "utf-8");
11649
+ const specContent = await fs17.readFile(path23.join(config.docsDir, paths.specPath), "utf-8");
11650
+ const planPath = path23.join(config.docsDir, paths.planPath);
11651
+ const planContent = await fs17.pathExists(planPath) ? await fs17.readFile(planPath, "utf-8") : "";
11652
+ const tasksContent = await fs17.readFile(path23.join(config.docsDir, paths.tasksPath), "utf-8");
11138
11653
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
11139
11654
  const defaultTitle = feature.issueNumber ? tg(config.lang, "prDefaultTitleWithIssue", {
11140
11655
  issue: feature.issueNumber,
@@ -11173,7 +11688,7 @@ function githubCommand(program2) {
11173
11688
  create: options.create,
11174
11689
  explicitBodyFile,
11175
11690
  defaultBodyFile,
11176
- workflowDraftPath: path22.join(config.docsDir, paths.prPath),
11691
+ workflowDraftPath: path23.join(config.docsDir, paths.prPath),
11177
11692
  generatedBody,
11178
11693
  requiredSections: getRequiredPrSections(config.lang),
11179
11694
  kindLabel: tg(config.lang, "kindPr"),
@@ -11244,7 +11759,7 @@ function githubCommand(program2) {
11244
11759
  }
11245
11760
  if (prUrl && options.syncTasks !== false) {
11246
11761
  const synced = syncTasksPrMetadata(
11247
- path22.join(config.docsDir, paths.tasksPath),
11762
+ path23.join(config.docsDir, paths.tasksPath),
11248
11763
  prUrl,
11249
11764
  "Review",
11250
11765
  config.lang
@@ -11280,7 +11795,7 @@ function githubCommand(program2) {
11280
11795
  mergeAlreadyMerged = merged.alreadyMerged;
11281
11796
  if (prUrl && options.syncTasks !== false) {
11282
11797
  const mergedSync = syncTasksPrMetadata(
11283
- path22.join(config.docsDir, paths.tasksPath),
11798
+ path23.join(config.docsDir, paths.tasksPath),
11284
11799
  prUrl,
11285
11800
  "Approved",
11286
11801
  config.lang
@@ -11524,7 +12039,7 @@ function docsCommand(program2) {
11524
12039
  );
11525
12040
  return;
11526
12041
  }
11527
- const relativeFromCwd = path22.relative(process.cwd(), loaded.entry.absolutePath);
12042
+ const relativeFromCwd = path23.relative(process.cwd(), loaded.entry.absolutePath);
11528
12043
  console.log();
11529
12044
  console.log(chalk6.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
11530
12045
  console.log(
@@ -11604,7 +12119,7 @@ function detectCommand(program2) {
11604
12119
  }
11605
12120
  async function runDetect(options) {
11606
12121
  const cwd = process.cwd();
11607
- const targetCwd = options.dir ? path22.resolve(cwd, options.dir) : cwd;
12122
+ const targetCwd = options.dir ? path23.resolve(cwd, options.dir) : cwd;
11608
12123
  const config = await getConfig(targetCwd);
11609
12124
  const detected = !!config;
11610
12125
  const reasonCode = detected ? "PROJECT_DETECTED" : "PROJECT_NOT_DETECTED";
@@ -11631,8 +12146,8 @@ async function runDetect(options) {
11631
12146
  );
11632
12147
  return;
11633
12148
  }
11634
- const configPath2 = path22.join(config.docsDir, ".lee-spec-kit.json");
11635
- const configFilePresent2 = await fs16.pathExists(configPath2);
12149
+ const configPath2 = path23.join(config.docsDir, ".lee-spec-kit.json");
12150
+ const configFilePresent2 = await fs17.pathExists(configPath2);
11636
12151
  const detectionSource2 = configFilePresent2 ? "config" : "heuristic";
11637
12152
  console.log(
11638
12153
  JSON.stringify(
@@ -11665,8 +12180,8 @@ async function runDetect(options) {
11665
12180
  console.log();
11666
12181
  return;
11667
12182
  }
11668
- const configPath = path22.join(config.docsDir, ".lee-spec-kit.json");
11669
- const configFilePresent = await fs16.pathExists(configPath);
12183
+ const configPath = path23.join(config.docsDir, ".lee-spec-kit.json");
12184
+ const configFilePresent = await fs17.pathExists(configPath);
11670
12185
  const detectionSource = configFilePresent ? "config" : "heuristic";
11671
12186
  console.log(chalk6.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
11672
12187
  console.log(chalk6.gray(`- ${tr(lang, "cli", "detect.labelDocsDir")}: ${config.docsDir}`));
@@ -11742,28 +12257,28 @@ function hasTemplateMarkers(content) {
11742
12257
  return patterns.some((pattern) => pattern.test(content));
11743
12258
  }
11744
12259
  async function countFeatureDirs(docsDir, projectType) {
11745
- const featuresRoot = path22.join(docsDir, "features");
12260
+ const featuresRoot = path23.join(docsDir, "features");
11746
12261
  if (projectType === "single") {
11747
12262
  const dirs = await listSubdirectories(featuresRoot);
11748
- return dirs.filter((value) => path22.basename(value) !== "feature-base").length;
12263
+ return dirs.filter((value) => path23.basename(value) !== "feature-base").length;
11749
12264
  }
11750
12265
  const components = await listSubdirectories(featuresRoot);
11751
12266
  let total = 0;
11752
12267
  for (const componentDir of components) {
11753
- const componentName = path22.basename(componentDir).trim().toLowerCase();
12268
+ const componentName = path23.basename(componentDir).trim().toLowerCase();
11754
12269
  if (!componentName || componentName === "feature-base") continue;
11755
12270
  const dirs = await listSubdirectories(componentDir);
11756
- total += dirs.filter((value) => path22.basename(value) !== "feature-base").length;
12271
+ total += dirs.filter((value) => path23.basename(value) !== "feature-base").length;
11757
12272
  }
11758
12273
  return total;
11759
12274
  }
11760
12275
  async function hasUserPrdFile(prdDir) {
11761
- if (!await fs16.pathExists(prdDir)) return false;
12276
+ if (!await fs17.pathExists(prdDir)) return false;
11762
12277
  const files = await walkFiles(prdDir, {
11763
12278
  extensions: [".md"],
11764
12279
  ignoreDirs: ["node_modules"]
11765
12280
  });
11766
- return files.some((absolutePath) => path22.basename(absolutePath).toLowerCase() !== "readme.md");
12281
+ return files.some((absolutePath) => path23.basename(absolutePath).toLowerCase() !== "readme.md");
11767
12282
  }
11768
12283
  function finalizeChecks(checks) {
11769
12284
  const summary = checks.reduce(
@@ -11892,8 +12407,8 @@ async function runOnboardChecks(config) {
11892
12407
  });
11893
12408
  }
11894
12409
  }
11895
- const constitutionPath = path22.join(docsDir, "agents", "constitution.md");
11896
- if (!await fs16.pathExists(constitutionPath)) {
12410
+ const constitutionPath = path23.join(docsDir, "agents", "constitution.md");
12411
+ if (!await fs17.pathExists(constitutionPath)) {
11897
12412
  checks.push({
11898
12413
  id: "constitution_exists",
11899
12414
  status: "block",
@@ -11907,7 +12422,7 @@ async function runOnboardChecks(config) {
11907
12422
  suggestedCommand: `npx lee-spec-kit update --agents`
11908
12423
  });
11909
12424
  } else {
11910
- const content = await fs16.readFile(constitutionPath, "utf-8");
12425
+ const content = await fs17.readFile(constitutionPath, "utf-8");
11911
12426
  if (hasTemplateMarkers(content)) {
11912
12427
  checks.push({
11913
12428
  id: "constitution_filled",
@@ -11930,9 +12445,9 @@ async function runOnboardChecks(config) {
11930
12445
  });
11931
12446
  }
11932
12447
  }
11933
- const customPath = path22.join(docsDir, "agents", "custom.md");
11934
- if (await fs16.pathExists(customPath)) {
11935
- const content = await fs16.readFile(customPath, "utf-8");
12448
+ const customPath = path23.join(docsDir, "agents", "custom.md");
12449
+ if (await fs17.pathExists(customPath)) {
12450
+ const content = await fs17.readFile(customPath, "utf-8");
11936
12451
  if (hasTemplateMarkers(content)) {
11937
12452
  checks.push({
11938
12453
  id: "custom_optional",
@@ -11955,7 +12470,7 @@ async function runOnboardChecks(config) {
11955
12470
  });
11956
12471
  }
11957
12472
  }
11958
- const prdDir = path22.join(docsDir, "prd");
12473
+ const prdDir = path23.join(docsDir, "prd");
11959
12474
  const featureCount = await countFeatureDirs(docsDir, config.projectType);
11960
12475
  const prdReady = await hasUserPrdFile(prdDir);
11961
12476
  if (!prdReady) {
@@ -11973,7 +12488,7 @@ async function runOnboardChecks(config) {
11973
12488
  "PRD is empty. If features already exist, fill PRD as soon as possible."
11974
12489
  ),
11975
12490
  path: prdDir,
11976
- suggestedCommand: `touch ${quotePath(path22.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
12491
+ suggestedCommand: `touch ${quotePath(path23.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
11977
12492
  });
11978
12493
  } else {
11979
12494
  checks.push({
@@ -12157,17 +12672,6 @@ function normalizeDecision(raw) {
12157
12672
  if (value === "blocked" || value === "block") return "blocked";
12158
12673
  return null;
12159
12674
  }
12160
- function parseNonNegativeInt(raw, label) {
12161
- if (raw === void 0) return null;
12162
- const value = Number(raw);
12163
- if (!Number.isInteger(value) || value < 0) {
12164
- throw createCliError(
12165
- "INVALID_ARGUMENT",
12166
- `\`${label}\` must be a non-negative integer.`
12167
- );
12168
- }
12169
- return value;
12170
- }
12171
12675
  function findSpecLineIndex(lines, keys) {
12172
12676
  const escaped = keys.map((key) => escapeRegExp4(key));
12173
12677
  const re = new RegExp(`^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`);
@@ -12214,7 +12718,6 @@ function getPreferredKeys(lang) {
12214
12718
  if (lang === "ko") {
12215
12719
  return {
12216
12720
  review: "PR \uC804 \uB9AC\uBDF0",
12217
- findings: "PR \uC804 \uB9AC\uBDF0 Findings",
12218
12721
  evidence: "PR \uC804 \uB9AC\uBDF0 Evidence",
12219
12722
  decision: "PR \uC804 \uB9AC\uBDF0 Decision",
12220
12723
  prStatus: "PR \uC0C1\uD0DC"
@@ -12222,7 +12725,6 @@ function getPreferredKeys(lang) {
12222
12725
  }
12223
12726
  return {
12224
12727
  review: "Pre-PR Review",
12225
- findings: "Pre-PR Findings",
12226
12728
  evidence: "Pre-PR Evidence",
12227
12729
  decision: "Pre-PR Decision",
12228
12730
  prStatus: "PR Status"
@@ -12230,28 +12732,30 @@ function getPreferredKeys(lang) {
12230
12732
  }
12231
12733
  function buildReportContent(input) {
12232
12734
  const skills = input.skills.length > 0 ? input.skills.join(", ") : "code-review-excellence";
12233
- return `# Pre-PR Review Report: ${input.folderName}
12735
+ return `## Pre-PR Review Log (${input.date})
12234
12736
 
12235
- - Date: ${input.date}
12236
- - Baseline: ${input.fallback}
12237
- - Skills: ${skills}
12238
- - Findings: major=${input.major}, minor=${input.minor}
12239
- - Decision: ${input.decision}
12240
- - Note: ${input.note}
12241
-
12242
- ## Baseline Checklist
12737
+ - **Feature**: ${input.folderName}
12738
+ - **Baseline**: ${input.fallback}
12739
+ - **Skills**: ${skills}
12740
+ - **Decision**: ${input.decision}
12741
+ - **Note**: ${input.note}
12742
+ - **Trace**: pre-pr-review command executed and synced with tasks.md
12743
+ `;
12744
+ }
12745
+ function appendDecisionLog(content, entry) {
12746
+ const normalized = content.trimEnd();
12747
+ if (!normalized) return `${entry.trim()}
12748
+ `;
12749
+ return `${normalized}
12243
12750
 
12244
- - [x] Checked alignment with spec/plan/tasks.
12245
- - [x] Reviewed risk areas (regression, security, side effects, release readiness).
12246
- - [x] Reviewed maintainability (structure, reuse, obsolete code cleanup).
12247
- - [x] Reviewed test/verification coverage (or recorded reason if not run).
12751
+ ${entry.trim()}
12248
12752
  `;
12249
12753
  }
12250
12754
  function prePrReviewCommand(program2) {
12251
12755
  program2.command("pre-pr-review [feature-name]").description("Run and record pre-PR review evidence for a feature").option("--component <component>", "Component name for multi projects").option(
12252
12756
  "--decision <outcome>",
12253
12757
  "Decision outcome: approve | changes_requested | blocked"
12254
- ).option("--major <count>", "Pre-PR major findings count").option("--minor <count>", "Pre-PR minor findings count").option("--note <text>", "Decision note text").option("--json", "Output JSON").action(async (featureName, options) => {
12758
+ ).option("--note <text>", "Decision note text").option("--json", "Output JSON").action(async (featureName, options) => {
12255
12759
  try {
12256
12760
  await runPrePrReview(featureName, options);
12257
12761
  } catch (error) {
@@ -12301,13 +12805,11 @@ async function runPrePrReview(featureName, options) {
12301
12805
  `tasks.md not found for feature: ${feature.folderName}`
12302
12806
  );
12303
12807
  }
12304
- const tasksPath = path22.join(feature.path, "tasks.md");
12305
- const tasksContent = await fs16.readFile(tasksPath, "utf-8");
12808
+ const tasksPath = path23.join(feature.path, "tasks.md");
12809
+ const tasksContent = await fs17.readFile(tasksPath, "utf-8");
12306
12810
  const policy = resolvePrePrReviewPolicy(config.workflow);
12307
12811
  const preferred = getPreferredKeys(config.lang);
12308
12812
  const date = getLocalDateString();
12309
- const major = parseNonNegativeInt(options.major, "--major") ?? feature.prePrReview.findings?.major ?? 0;
12310
- const minor = parseNonNegativeInt(options.minor, "--minor") ?? feature.prePrReview.findings?.minor ?? 0;
12311
12813
  const explicitDecision = normalizeDecision(options.decision);
12312
12814
  if (options.decision && !explicitDecision) {
12313
12815
  throw createCliError(
@@ -12315,31 +12817,32 @@ async function runPrePrReview(featureName, options) {
12315
12817
  "`--decision` must be one of: approve, changes_requested, blocked."
12316
12818
  );
12317
12819
  }
12318
- const inferredDecision = major > 0 ? "changes_requested" : "approve";
12319
- const decision = explicitDecision || inferredDecision;
12820
+ const decision = explicitDecision || feature.prePrReview.decisionOutcome || "approve";
12320
12821
  if (!policy.decisionEnum.includes(decision)) {
12321
12822
  throw createCliError(
12322
12823
  "INVALID_ARGUMENT",
12323
12824
  `Decision "${decision}" is not allowed by workflow.prePrReview.decisionEnum.`
12324
12825
  );
12325
12826
  }
12326
- const note = options.note?.trim() || (decision === "approve" ? "baseline review completed without blocking findings" : decision === "changes_requested" ? "resolve findings before PR creation" : "blocked until prerequisite risk is resolved");
12327
- const reportPath = path22.join(feature.path, "pre-pr-review.md");
12328
- const reportContent = buildReportContent({
12827
+ const note = options.note?.trim() || (decision === "approve" ? "baseline review completed" : decision === "changes_requested" ? "follow-up changes are required before PR creation" : "blocked until prerequisite risk is resolved");
12828
+ const decisionsPath = path23.join(feature.path, "decisions.md");
12829
+ const decisionLogEntry = buildReportContent({
12329
12830
  folderName: feature.folderName,
12330
12831
  date,
12331
12832
  decision,
12332
- major,
12333
- minor,
12334
12833
  note,
12335
12834
  fallback: policy.fallback,
12336
12835
  skills: policy.skills
12337
12836
  });
12338
- await fs16.writeFile(reportPath, reportContent, "utf-8");
12339
- const reportPathFromDocs = normalizePathForDoc(
12340
- path22.join(feature.docs.featurePathFromDocs, "pre-pr-review.md")
12837
+ const decisionsContent = await fs17.pathExists(decisionsPath) ? await fs17.readFile(decisionsPath, "utf-8") : "";
12838
+ const nextDecisions = appendDecisionLog(decisionsContent, decisionLogEntry);
12839
+ if (nextDecisions !== decisionsContent) {
12840
+ await fs17.writeFile(decisionsPath, nextDecisions, "utf-8");
12841
+ }
12842
+ const decisionsPathFromDocs = normalizePathForDoc(
12843
+ path23.join(feature.docs.featurePathFromDocs, "decisions.md")
12341
12844
  );
12342
- const evidencePath = path22.basename(config.docsDir) === "docs" ? normalizePathForDoc(path22.join("docs", reportPathFromDocs)) : reportPathFromDocs;
12845
+ const evidencePath = path23.basename(config.docsDir) === "docs" ? normalizePathForDoc(path23.join("docs", decisionsPathFromDocs)) : decisionsPathFromDocs;
12343
12846
  let nextTasks = tasksContent;
12344
12847
  nextTasks = upsertSpecLine(
12345
12848
  nextTasks,
@@ -12348,19 +12851,12 @@ async function runPrePrReview(featureName, options) {
12348
12851
  "Done",
12349
12852
  ["PR \uC0C1\uD0DC", "PR Status"]
12350
12853
  );
12351
- nextTasks = upsertSpecLine(
12352
- nextTasks,
12353
- ["PR \uC804 \uB9AC\uBDF0 Findings", "Pre-PR Findings"],
12354
- preferred.findings,
12355
- `major=${major}, minor=${minor}`,
12356
- ["PR \uC804 \uB9AC\uBDF0", "Pre-PR Review"]
12357
- );
12358
12854
  nextTasks = upsertSpecLine(
12359
12855
  nextTasks,
12360
12856
  ["PR \uC804 \uB9AC\uBDF0 Evidence", "Pre-PR Evidence"],
12361
12857
  preferred.evidence,
12362
12858
  evidencePath,
12363
- ["PR \uC804 \uB9AC\uBDF0 Findings", "Pre-PR Findings", "PR \uC804 \uB9AC\uBDF0", "Pre-PR Review"]
12859
+ ["PR \uC804 \uB9AC\uBDF0", "Pre-PR Review"]
12364
12860
  );
12365
12861
  nextTasks = upsertSpecLine(
12366
12862
  nextTasks,
@@ -12370,7 +12866,7 @@ async function runPrePrReview(featureName, options) {
12370
12866
  ["PR \uC804 \uB9AC\uBDF0 Evidence", "Pre-PR Evidence"]
12371
12867
  );
12372
12868
  if (nextTasks !== tasksContent) {
12373
- await fs16.writeFile(tasksPath, nextTasks, "utf-8");
12869
+ await fs17.writeFile(tasksPath, nextTasks, "utf-8");
12374
12870
  }
12375
12871
  if (options.json) {
12376
12872
  console.log(
@@ -12379,10 +12875,10 @@ async function runPrePrReview(featureName, options) {
12379
12875
  status: "ok",
12380
12876
  reasonCode: "PRE_PR_REVIEW_RECORDED",
12381
12877
  feature: feature.folderName,
12382
- reportPath: normalizePathForDoc(reportPath),
12878
+ reportPath: normalizePathForDoc(decisionsPath),
12879
+ decisionsPath: normalizePathForDoc(decisionsPath),
12383
12880
  evidencePath,
12384
12881
  decision,
12385
- findings: { major, minor },
12386
12882
  tasksUpdated: nextTasks !== tasksContent
12387
12883
  },
12388
12884
  null,
@@ -12394,8 +12890,7 @@ async function runPrePrReview(featureName, options) {
12394
12890
  console.log();
12395
12891
  console.log(chalk6.green(`\u2705 pre-pr-review completed: ${feature.folderName}`));
12396
12892
  console.log(chalk6.gray(`- Decision: ${decision}`));
12397
- console.log(chalk6.gray(`- Findings: major=${major}, minor=${minor}`));
12398
- console.log(chalk6.gray(`- Report: ${reportPath}`));
12893
+ console.log(chalk6.gray(`- Decisions log: ${decisionsPath}`));
12399
12894
  if (nextTasks !== tasksContent) {
12400
12895
  console.log(chalk6.gray(`- tasks.md updated: ${tasksPath}`));
12401
12896
  }
@@ -12444,13 +12939,13 @@ ${version}
12444
12939
  }
12445
12940
  return `${ascii}${footer}`;
12446
12941
  }
12447
- var CACHE_FILE = path22.join(os.homedir(), ".lee-spec-kit-version-cache.json");
12942
+ var CACHE_FILE = path23.join(os.homedir(), ".lee-spec-kit-version-cache.json");
12448
12943
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
12449
12944
  function getCurrentVersion() {
12450
12945
  try {
12451
- const packageJsonPath = path22.join(__dirname$1, "..", "package.json");
12452
- if (fs16.existsSync(packageJsonPath)) {
12453
- const pkg = fs16.readJsonSync(packageJsonPath);
12946
+ const packageJsonPath = path23.join(__dirname$1, "..", "package.json");
12947
+ if (fs17.existsSync(packageJsonPath)) {
12948
+ const pkg = fs17.readJsonSync(packageJsonPath);
12454
12949
  return pkg.version;
12455
12950
  }
12456
12951
  } catch {
@@ -12459,8 +12954,8 @@ function getCurrentVersion() {
12459
12954
  }
12460
12955
  function readCache() {
12461
12956
  try {
12462
- if (fs16.existsSync(CACHE_FILE)) {
12463
- return fs16.readJsonSync(CACHE_FILE);
12957
+ if (fs17.existsSync(CACHE_FILE)) {
12958
+ return fs17.readJsonSync(CACHE_FILE);
12464
12959
  }
12465
12960
  } catch {
12466
12961
  }
@@ -12552,9 +13047,9 @@ function shouldCheckForUpdates() {
12552
13047
  if (shouldCheckForUpdates()) checkForUpdates();
12553
13048
  function getCliVersion() {
12554
13049
  try {
12555
- const packageJsonPath = path22.join(__dirname$1, "..", "package.json");
12556
- if (fs16.existsSync(packageJsonPath)) {
12557
- const pkg = fs16.readJsonSync(packageJsonPath);
13050
+ const packageJsonPath = path23.join(__dirname$1, "..", "package.json");
13051
+ if (fs17.existsSync(packageJsonPath)) {
13052
+ const pkg = fs17.readJsonSync(packageJsonPath);
12558
13053
  if (pkg?.version) return String(pkg.version);
12559
13054
  }
12560
13055
  } catch {