lee-spec-kit 0.7.1 → 0.7.2

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,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import path12 from 'path';
2
+ import path13 from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { program } from 'commander';
5
5
  import fs from 'fs-extra';
6
6
  import prompts from 'prompts';
7
- import chalk8 from 'chalk';
7
+ import chalk9 from 'chalk';
8
8
  import { spawn, spawnSync, execFileSync, execSync } from 'child_process';
9
9
  import os from 'os';
10
10
  import { createHash, randomUUID } from 'crypto';
11
- import fs9 from 'fs';
11
+ import fs10 from 'fs';
12
12
  import { Buffer as Buffer$1 } from 'buffer';
13
13
 
14
14
  var getFilename = () => fileURLToPath(import.meta.url);
15
- var getDirname = () => path12.dirname(getFilename());
15
+ var getDirname = () => path13.dirname(getFilename());
16
16
  var __dirname$1 = /* @__PURE__ */ getDirname();
17
17
  async function walkFiles(fsAdapter, rootDir, options = {}) {
18
18
  const out = [];
@@ -25,7 +25,7 @@ async function walkFiles(fsAdapter, rootDir, options = {}) {
25
25
  async function visit(current) {
26
26
  const entries = await fsAdapter.readdir(current);
27
27
  for (const entryName of entries) {
28
- const absolute = path12.join(current, entryName);
28
+ const absolute = path13.join(current, entryName);
29
29
  const stat = await fsAdapter.stat(absolute);
30
30
  if (stat.isDirectory()) {
31
31
  if (ignored.has(entryName.trim().toLowerCase())) continue;
@@ -34,7 +34,7 @@ async function walkFiles(fsAdapter, rootDir, options = {}) {
34
34
  }
35
35
  if (!stat.isFile()) continue;
36
36
  if (normalizedExtensions.size > 0) {
37
- const ext = path12.extname(entryName).toLowerCase();
37
+ const ext = path13.extname(entryName).toLowerCase();
38
38
  if (!normalizedExtensions.has(ext)) continue;
39
39
  }
40
40
  out.push(absolute);
@@ -50,7 +50,7 @@ async function listSubdirectories(fsAdapter, rootDir) {
50
50
  const entries = await fsAdapter.readdir(rootDir);
51
51
  const dirs = [];
52
52
  for (const entryName of entries) {
53
- const absolute = path12.join(rootDir, entryName);
53
+ const absolute = path13.join(rootDir, entryName);
54
54
  const stat = await fsAdapter.stat(absolute);
55
55
  if (stat.isDirectory()) {
56
56
  dirs.push(absolute);
@@ -151,10 +151,10 @@ var DefaultFileSystemAdapter = class {
151
151
  }
152
152
  };
153
153
  var __filename2 = fileURLToPath(import.meta.url);
154
- var __dirname2 = path12.dirname(__filename2);
154
+ var __dirname2 = path13.dirname(__filename2);
155
155
  function getTemplatesDir() {
156
- const rootDir = path12.resolve(__dirname2, "..");
157
- return path12.join(rootDir, "templates");
156
+ const rootDir = path13.resolve(__dirname2, "..");
157
+ return path13.join(rootDir, "templates");
158
158
  }
159
159
 
160
160
  // src/utils/locales/ko/cli.ts
@@ -175,6 +175,8 @@ var koCli = {
175
175
  "feature.nextSteps1": " 1. {path}/spec.md \uC791\uC131",
176
176
  "feature.nextSteps2": " 2. \uC0AC\uC6A9\uC790 \uB9AC\uBDF0 \uC694\uCCAD",
177
177
  "feature.nextSteps3": " 3. \uC2B9\uC778 \uD6C4 plan.md \uC791\uC131",
178
+ "feature.ideaNotFound": "Idea \uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {ref}",
179
+ "feature.ideaAmbiguous": "{ref}\uC640 \uB9E4\uCE6D\uB418\uB294 Idea \uBB38\uC11C\uAC00 \uC5EC\uB7EC \uAC1C\uC785\uB2C8\uB2E4. \uC815\uD655\uD55C \uACBD\uB85C\uB098 \uC804\uCCB4 indexed \uC774\uB984\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.",
178
180
  "config.currentTitle": "\u{1F4CB} \uD604\uC7AC \uC124\uC815:",
179
181
  "config.pathLabel": "\uACBD\uB85C",
180
182
  "config.projectRootStandaloneOnly": "\u26A0\uFE0F projectRoot\uB294 standalone \uBAA8\uB4DC\uC5D0\uC11C\uB9CC \uC124\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.",
@@ -268,6 +270,13 @@ var koCli = {
268
270
  "init.log.gitInitialCommitDone": "\u2705 Git \uCD08\uAE30 \uCEE4\uBC0B \uC644\uB8CC!",
269
271
  "init.warn.skipGitInit": "\u26A0\uFE0F Git \uCD08\uAE30\uD654\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4 (\uC218\uB3D9\uC73C\uB85C \uCEE4\uBC0B\uD574\uC8FC\uC138\uC694)",
270
272
  "init.error.templateNotFound": "\uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: {path}",
273
+ "idea.fileExists": "\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 Idea \uBB38\uC11C\uC785\uB2C8\uB2E4: {path}",
274
+ "idea.templateNotFound": "CLI \uB0B4\uC7A5 idea \uD15C\uD50C\uB9BF\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
275
+ "idea.created": "\u2705 Idea \uBB38\uC11C \uC0DD\uC131 \uC644\uB8CC: {path}",
276
+ "idea.nextStepsTitle": "\uB2E4\uC74C \uB2E8\uACC4:",
277
+ "idea.nextSteps1": " 1. \uBC94\uC704, PRD Refs, \uC2B9\uACA9 \uBA54\uBAA8\uB97C \uC791\uC131",
278
+ "idea.nextSteps2": " 2. Feature\uB85C \uC2B9\uACA9: npx lee-spec-kit feature <name> --idea {ideaId}",
279
+ "idea.nextSteps3": " 3. Feature\uB85C \uB9CC\uB4E4\uC9C0 \uC54A\uC744 \uACBD\uC6B0 Dropped\uB85C \uD45C\uC2DC",
271
280
  "github.cmdGithubDescription": "GitHub \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uB3C4\uC6B0\uBBF8 (issue/pr \uBCF8\uBB38 \uD15C\uD50C\uB9BF \uC0DD\uC131, \uAC80\uC99D, merge \uC7AC\uC2DC\uB3C4)",
272
281
  "github.cmdIssueDescription": "feature \uBB38\uC11C \uAE30\uBC18 GitHub issue \uBCF8\uBB38 \uC0DD\uC131/\uC0DD\uC131",
273
282
  "github.cmdPrDescription": "GitHub PR \uBCF8\uBB38 \uC0DD\uC131/\uC0DD\uC131 + tasks \uB3D9\uAE30\uD654 + merge \uC7AC\uC2DC\uB3C4",
@@ -434,11 +443,15 @@ var koCli = {
434
443
  "validation.workflowModeInvalid": "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uBAA8\uB4DC\uB294 {values} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
435
444
  "validation.featureIdEmpty": "Feature ID\uB294 \uBE44\uC5B4\uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
436
445
  "validation.featureIdFormat": "Feature ID\uB294 'F' + \uC22B\uC790 \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 (\uC608: F001).",
446
+ "validation.ideaIdEmpty": "Idea ID\uB294 \uBE44\uC5B4\uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
447
+ "validation.ideaIdFormat": "Idea ID\uB294 'I' + \uC22B\uC790 \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 (\uC608: I001).",
437
448
  "validation.pathEmpty": "\uACBD\uB85C\uB294 \uBE44\uC5B4\uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
438
449
  "validation.pathNullByte": "\uACBD\uB85C\uC5D0 null \uBB38\uC790\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
439
450
  "validation.genericFailed": "\uAC80\uC99D \uC2E4\uD328",
440
451
  "validation.context.featureName": "\uAE30\uB2A5 \uC774\uB984",
441
452
  "validation.context.featureId": "Feature ID",
453
+ "validation.context.ideaName": "Idea \uC774\uB984",
454
+ "validation.context.ideaId": "Idea ID",
442
455
  "validation.context.projectName": "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984",
443
456
  "validation.context.projectType": "\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785",
444
457
  "validation.context.language": "\uC5B8\uC5B4",
@@ -626,9 +639,9 @@ var koMessages = {
626
639
  taskCommitGateReasonMismatchLastDone: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B\uC774 \uC9C1\uC804 \uC644\uB8CC \uD0DC\uC2A4\uD06C\uC640 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
627
640
  prLegacyAsk: "tasks.md\uC5D0 PR/PR \uC0C1\uD0DC \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD15C\uD50C\uB9BF\uC744 \uCD5C\uC2E0 \uD3EC\uB9F7\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD560\uAE4C\uC694? (\uD655\uC778 \uD544\uC694)",
628
641
  prePrReviewFieldMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0**: Pending | Running | Done` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
629
- prePrReviewRun: "\uCF54\uB4DC \uB9AC\uBDF0 \uC5D0\uC774\uC804\uD2B8\uB97C \uC2E4\uD589\uD574 `spec.md`/`plan.md`/`tasks.md` \uB300\uBE44 \uAD6C\uD604 \uC801\uD569\uC131\uC744 \uAC80\uD1A0\uD558\uACE0, `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Findings`/`Residual Risks`\uAC00 \uD3EC\uD568\uB41C `review-trace.json`\uC744 \uC0DD\uC131\uD55C \uB4A4 `pre-pr-review`\uB85C \uB9AC\uBDF0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. `pre-pr-review-run` \uC790\uCCB4\uB294 evidence\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC73C\uBA70, \uD604\uC7AC evidence \uC815\uCC45\uC774 \uACBD\uB85C\uB97C \uC694\uAD6C\uD560 \uB54C\uB9CC `--evidence review-trace.json`\uC744 \uD568\uAED8 \uC0AC\uC6A9\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
630
- prePrReviewRunning: "Pre-PR \uB9AC\uBDF0 handoff\uAC00 \uC774\uBBF8 \uC900\uBE44\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uAE30\uC874 delegated review\uB97C \uC7AC\uC0AC\uC6A9\uD558\uAC70\uB098 \uC774\uC5B4\uC11C \uC218\uD589\uD574 `review-trace.json`\uC744 \uB9CC\uB4E0 \uB4A4 `pre-pr-review`\uB85C \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. \uAC19\uC740 \uB77C\uBCA8\uC744 \uB2E4\uC2DC \uC2B9\uC778 \uB8E8\uD504\uB85C \uC5F4\uC9C0 \uB9C8\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
631
- prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC2E4\uC81C \uD30C\uC77C \uACBD\uB85C\uC640 `Pre-PR Review Log`(\uB610\uB294 `PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`)\uC5D0 placeholder\uAC00 \uC544\uB2CC `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Decision`/`Findings`(\uB610\uB294 \uBA85\uC2DC\uC801 `0 findings`)/`Residual Risks`\uB97C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
642
+ prePrReviewRun: "Pre-PR \uB9AC\uBDF0 handoff\uB97C \uC900\uBE44\uD55C \uB4A4 \uC2E4\uC81C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uC11C \uC218\uD589\uD558\uC138\uC694. `review-trace.json`\uC5D0\uB294 `baseSha`, `headSha`, `changedFiles`, `reviewedFiles`, `riskSummaries`, `Approval Rationale`, \uD30C\uC77C\uBCC4 findings, `Residual Risks`\uB97C \uAD6C\uC870\uD654\uD574 \uB123\uACE0, \uC774\uD6C4 `pre-pr-review`\uB85C \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. `pre-pr-review-run` \uC790\uCCB4\uB294 \uB9AC\uBDF0 \uC644\uB8CC\uB098 \uC0C1\uD0DC \uC804\uC774\uB97C \uC758\uBBF8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (\uD655\uC778 \uD544\uC694)",
643
+ prePrReviewRunning: "Pre-PR \uB9AC\uBDF0\uAC00 \uC774\uBBF8 \uC9C4\uD589 \uC911\uC785\uB2C8\uB2E4. \uAE30\uC874 delegated review\uB97C \uC7AC\uC0AC\uC6A9\uD558\uAC70\uB098 \uC774\uC5B4\uC11C \uC218\uD589\uD574 \uAD6C\uC870\uD654\uB41C `review-trace.json`\uC744 \uB9CC\uB4E0 \uB4A4 `pre-pr-review`\uB85C \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. \uAC19\uC740 \uB77C\uBCA8\uC744 \uB2E4\uC2DC \uC2B9\uC778 \uB8E8\uD504\uB85C \uC5F4\uC9C0 \uB9C8\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
644
+ prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. repo \uB8E8\uD2B8 \uAE30\uC900 \uC0C1\uB300\uACBD\uB85C\uB97C \uC4F0\uB294 \uC2E4\uC81C JSON \uD30C\uC77C\uC744 \uAC00\uB9AC\uD0A4\uACE0, `baseSha`, `headSha`, `changedFiles`, `reviewedFiles`, `riskSummaries`, `Approval Rationale`, \uD30C\uC77C\uBCC4 findings, `Residual Risks`\uB97C \uD3EC\uD568\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
632
645
  prePrReviewDecisionMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uACB0\uC815 \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `\uACB0\uC815: ...`(\uB610\uB294 `decision: ...`) \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
633
646
  prePrReviewFixRequired: "\uD604\uC7AC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{decision}`\uC785\uB2C8\uB2E4. PR \uC0DD\uC131 \uB2E8\uACC4\uB85C \uC774\uB3D9\uD558\uAE30 \uC804\uC5D0 pre-PR \uC9C0\uC801\uC0AC\uD56D\uC744 \uCF54\uB4DC\uC5D0 \uBC18\uC601\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
634
647
  prePrReviewDecisionReconfirm: "\uD604\uC7AC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{decision}`\uC785\uB2C8\uB2E4. \uC9C0\uC801\uC0AC\uD56D\uC744 \uBC18\uC601\uD55C \uB4A4 \uC774\uC804 \uC0C1\uD0DC \uC7AC\uC0AC\uC6A9\uC744 \uB9C9\uAE30 \uC704\uD574 \uBA85\uC2DC\uC801\uC73C\uB85C Decision\uC744 \uC9C0\uC815\uD574 \uC7AC\uC2E4\uD589\uD558\uC138\uC694: `{command}` (\uD655\uC778 \uD544\uC694)",
@@ -731,6 +744,8 @@ var enCli = {
731
744
  "feature.nextSteps1": " 1. Write {path}/spec.md",
732
745
  "feature.nextSteps2": " 2. Ask for review",
733
746
  "feature.nextSteps3": " 3. After approval, write plan.md",
747
+ "feature.ideaNotFound": "Idea document not found: {ref}",
748
+ "feature.ideaAmbiguous": "Multiple idea documents matched {ref}. Use an exact path or full indexed name.",
734
749
  "config.currentTitle": "\u{1F4CB} Current config:",
735
750
  "config.pathLabel": "Path",
736
751
  "config.projectRootStandaloneOnly": "\u26A0\uFE0F projectRoot can only be set in standalone mode.",
@@ -824,6 +839,13 @@ var enCli = {
824
839
  "init.log.gitInitialCommitDone": "\u2705 Initial Git commit created!",
825
840
  "init.warn.skipGitInit": "\u26A0\uFE0F Skipping Git initialization (please commit manually)",
826
841
  "init.error.templateNotFound": "Template not found: {path}",
842
+ "idea.fileExists": "Idea document already exists: {path}",
843
+ "idea.templateNotFound": "Built-in idea template not found.",
844
+ "idea.created": "\u2705 Idea document created: {path}",
845
+ "idea.nextStepsTitle": "Next steps:",
846
+ "idea.nextSteps1": " 1. Fill scope, PRD refs, and promotion notes",
847
+ "idea.nextSteps2": " 2. Promote it with: npx lee-spec-kit feature <name> --idea {ideaId}",
848
+ "idea.nextSteps3": " 3. Mark it dropped if it should not become a feature",
827
849
  "github.cmdGithubDescription": "GitHub workflow helpers (issue/pr templates, validation, merge retry)",
828
850
  "github.cmdIssueDescription": "Generate/create GitHub issue body from feature docs with validation",
829
851
  "github.cmdPrDescription": "Generate/create GitHub PR body with validation, tasks PR sync, and merge retry",
@@ -990,11 +1012,15 @@ var enCli = {
990
1012
  "validation.workflowModeInvalid": "Workflow mode must be one of: {values}.",
991
1013
  "validation.featureIdEmpty": "Feature ID cannot be empty.",
992
1014
  "validation.featureIdFormat": "Feature ID must be 'F' + digits (e.g., F001).",
1015
+ "validation.ideaIdEmpty": "Idea ID cannot be empty.",
1016
+ "validation.ideaIdFormat": "Idea ID must be 'I' + digits (e.g., I001).",
993
1017
  "validation.pathEmpty": "Path cannot be empty.",
994
1018
  "validation.pathNullByte": "Path cannot contain null bytes.",
995
1019
  "validation.genericFailed": "Validation failed",
996
1020
  "validation.context.featureName": "Feature name",
997
1021
  "validation.context.featureId": "Feature ID",
1022
+ "validation.context.ideaName": "Idea name",
1023
+ "validation.context.ideaId": "Idea ID",
998
1024
  "validation.context.projectName": "Project name",
999
1025
  "validation.context.projectType": "Project type",
1000
1026
  "validation.context.language": "Language",
@@ -1182,9 +1208,9 @@ var enMessages = {
1182
1208
  taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
1183
1209
  prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
1184
1210
  prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Running | Done` and run context again. (CHECK required)",
1185
- prePrReviewRun: "Run the code review agent, compare the implementation against `spec.md`/`plan.md`/`tasks.md`, and generate `review-trace.json` with `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Findings`, and `Residual Risks`. Then record findings with `pre-pr-review`; `pre-pr-review-run` itself does not generate evidence or advance state, and you should use `--evidence review-trace.json` only when the active evidence policy requires a path. (CHECK required)",
1186
- prePrReviewRunning: "Pre-PR review handoff is already prepared. Reuse or resume the delegated review, generate `review-trace.json`, then record the result with `pre-pr-review`. Do not re-approve the same label. (CHECK required)",
1187
- prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty/invalid. Point to a real file and include a `Pre-PR Review Log` section with non-placeholder `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Decision`, `Findings` (or explicit `0 findings`), and `Residual Risks`. (CHECK required)",
1211
+ prePrReviewRun: "Prepare the pre-PR review handoff, then continue the real review before recording anything. Generate structured `review-trace.json` evidence with `baseSha`, `headSha`, `changedFiles`, `reviewedFiles`, `riskSummaries`, `Approval Rationale`, per-file findings, and `Residual Risks`, then record the outcome with `pre-pr-review`. `pre-pr-review-run` itself does not complete the review or advance state. (CHECK required)",
1212
+ prePrReviewRunning: "A pre-PR review is already in progress. Reuse or resume the delegated review, generate structured `review-trace.json` evidence, then record the result with `pre-pr-review`. Do not re-approve the same label. (CHECK required)",
1213
+ prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty/invalid. Point it to a real JSON file that uses repo-relative paths and includes `baseSha`, `headSha`, `changedFiles`, `reviewedFiles`, `riskSummaries`, `Approval Rationale`, per-file findings, and `Residual Risks`. (CHECK required)",
1188
1214
  prePrReviewDecisionMissing: "tasks.md `Pre-PR Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
1189
1215
  prePrReviewFixRequired: "Current `Pre-PR Decision` is `{decision}`. Apply the requested fixes from pre-PR findings before moving to PR creation. (CHECK required)",
1190
1216
  prePrReviewDecisionReconfirm: "Current `Pre-PR Decision` is `{decision}`. After fixing findings, rerun pre-PR review with an explicit decision to avoid replaying the prior state: `{command}` (CHECK required)",
@@ -1674,6 +1700,19 @@ function validateFeatureIdWithLang(id, lang) {
1674
1700
  }
1675
1701
  return { valid: true };
1676
1702
  }
1703
+ function validateIdeaIdWithLang(id, lang) {
1704
+ if (!id || id.trim().length === 0) {
1705
+ return { valid: false, error: tr(lang, "cli", "validation.ideaIdEmpty") };
1706
+ }
1707
+ const ideaIdPattern = /^I\d{3,}$/;
1708
+ if (!ideaIdPattern.test(id)) {
1709
+ return {
1710
+ valid: false,
1711
+ error: tr(lang, "cli", "validation.ideaIdFormat")
1712
+ };
1713
+ }
1714
+ return { valid: true };
1715
+ }
1677
1716
  function validatePathWithLang(inputPath, lang) {
1678
1717
  if (!inputPath || inputPath.trim().length === 0) {
1679
1718
  return { valid: false, error: tr(lang, "cli", "validation.pathEmpty") };
@@ -1702,10 +1741,10 @@ var DEFAULT_STALE_MS = 2 * 6e4;
1702
1741
  var RUNTIME_GIT_DIRNAME = "lee-spec-kit.runtime";
1703
1742
  var RUNTIME_TEMP_DIRNAME = "lee-spec-kit-runtime";
1704
1743
  function toScopeKey(value) {
1705
- return createHash("sha1").update(path12.resolve(value)).digest("hex").slice(0, 16);
1744
+ return createHash("sha1").update(path13.resolve(value)).digest("hex").slice(0, 16);
1706
1745
  }
1707
1746
  function getTempRuntimeDir(scopePath) {
1708
- return path12.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1747
+ return path13.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1709
1748
  }
1710
1749
  function resolveGitRuntimeDir(cwd) {
1711
1750
  try {
@@ -1719,38 +1758,38 @@ function resolveGitRuntimeDir(cwd) {
1719
1758
  }
1720
1759
  ).trim();
1721
1760
  if (!out) return null;
1722
- return path12.isAbsolute(out) ? out : path12.resolve(cwd, out);
1761
+ return path13.isAbsolute(out) ? out : path13.resolve(cwd, out);
1723
1762
  } catch {
1724
1763
  return null;
1725
1764
  }
1726
1765
  }
1727
1766
  function getRuntimeStateDir(cwd) {
1728
- const resolved = path12.resolve(cwd);
1767
+ const resolved = path13.resolve(cwd);
1729
1768
  return resolveGitRuntimeDir(resolved) ?? getTempRuntimeDir(resolved);
1730
1769
  }
1731
1770
  function getDocsLockPath(docsDir) {
1732
- return path12.join(
1771
+ return path13.join(
1733
1772
  getRuntimeStateDir(docsDir),
1734
1773
  "locks",
1735
1774
  `docs-${toScopeKey(docsDir)}.lock`
1736
1775
  );
1737
1776
  }
1738
1777
  function getInitLockPath(targetDir) {
1739
- return path12.join(
1740
- getRuntimeStateDir(path12.dirname(path12.resolve(targetDir))),
1778
+ return path13.join(
1779
+ getRuntimeStateDir(path13.dirname(path13.resolve(targetDir))),
1741
1780
  "locks",
1742
1781
  `init-${toScopeKey(targetDir)}.lock`
1743
1782
  );
1744
1783
  }
1745
1784
  function getApprovalTicketStorePath(docsDir) {
1746
- return path12.join(
1785
+ return path13.join(
1747
1786
  getRuntimeStateDir(docsDir),
1748
1787
  "tickets",
1749
1788
  `approval-${toScopeKey(docsDir)}.json`
1750
1789
  );
1751
1790
  }
1752
1791
  function getProjectExecutionLockPath(cwd) {
1753
- return path12.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1792
+ return path13.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1754
1793
  }
1755
1794
  async function isStaleLock(lockPath, staleMs) {
1756
1795
  try {
@@ -1791,7 +1830,7 @@ function isProcessAlive(pid) {
1791
1830
  }
1792
1831
  }
1793
1832
  async function tryAcquire(lockPath, owner) {
1794
- await fs.ensureDir(path12.dirname(lockPath));
1833
+ await fs.ensureDir(path13.dirname(lockPath));
1795
1834
  try {
1796
1835
  const fd = await fs.open(lockPath, "wx");
1797
1836
  const payload = JSON.stringify(
@@ -1868,30 +1907,30 @@ var ENGINE_MANAGED_AGENT_FILES = [
1868
1907
  "pr-template.md"
1869
1908
  ];
1870
1909
  var ENGINE_MANAGED_AGENT_DIRS = ["skills"];
1871
- var ENGINE_MANAGED_FEATURE_PATH = path12.join(
1910
+ var ENGINE_MANAGED_FEATURE_PATH = path13.join(
1872
1911
  "features",
1873
1912
  "feature-base"
1874
1913
  );
1875
1914
  async function pruneEngineManagedDocs(docsDir) {
1876
1915
  const removed = [];
1877
1916
  for (const file of ENGINE_MANAGED_AGENT_FILES) {
1878
- const target = path12.join(docsDir, "agents", file);
1917
+ const target = path13.join(docsDir, "agents", file);
1879
1918
  if (await fs.pathExists(target)) {
1880
1919
  await fs.remove(target);
1881
- removed.push(path12.relative(docsDir, target));
1920
+ removed.push(path13.relative(docsDir, target));
1882
1921
  }
1883
1922
  }
1884
1923
  for (const dir of ENGINE_MANAGED_AGENT_DIRS) {
1885
- const target = path12.join(docsDir, "agents", dir);
1924
+ const target = path13.join(docsDir, "agents", dir);
1886
1925
  if (await fs.pathExists(target)) {
1887
1926
  await fs.remove(target);
1888
- removed.push(path12.relative(docsDir, target));
1927
+ removed.push(path13.relative(docsDir, target));
1889
1928
  }
1890
1929
  }
1891
- const featureBasePath = path12.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1930
+ const featureBasePath = path13.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1892
1931
  if (await fs.pathExists(featureBasePath)) {
1893
1932
  await fs.remove(featureBasePath);
1894
- removed.push(path12.relative(docsDir, featureBasePath));
1933
+ removed.push(path13.relative(docsDir, featureBasePath));
1895
1934
  }
1896
1935
  return removed;
1897
1936
  }
@@ -2171,7 +2210,7 @@ function initCommand(program2) {
2171
2210
  } catch (error) {
2172
2211
  if (error instanceof Error && error.message === "canceled") {
2173
2212
  const lang2 = options.lang ?? DEFAULT_LANG;
2174
- console.log(chalk8.yellow(`
2213
+ console.log(chalk9.yellow(`
2175
2214
  ${tr(lang2, "cli", "common.canceled")}`));
2176
2215
  return;
2177
2216
  }
@@ -2179,8 +2218,8 @@ ${tr(lang2, "cli", "common.canceled")}`));
2179
2218
  const cliError = toCliError(error);
2180
2219
  const suggestions = getCliErrorSuggestions(cliError.code, lang);
2181
2220
  console.error(
2182
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
2183
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
2221
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
2222
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
2184
2223
  );
2185
2224
  printCliErrorSuggestions(suggestions, lang);
2186
2225
  process.exitCode = 1;
@@ -2190,7 +2229,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
2190
2229
  }
2191
2230
  async function runInit(options) {
2192
2231
  const cwd = process.cwd();
2193
- const defaultName = path12.basename(cwd);
2232
+ const defaultName = path13.basename(cwd);
2194
2233
  let projectName = options.name || defaultName;
2195
2234
  let projectType = options.type;
2196
2235
  let components = parseComponentsOption(options.components);
@@ -2201,7 +2240,7 @@ async function runInit(options) {
2201
2240
  let docsRemote = options.docsRemote;
2202
2241
  let projectRoot;
2203
2242
  const componentProjectRoots = options.componentProjectRoots ? parseComponentProjectRootsOption(options.componentProjectRoots) : {};
2204
- const targetDir = path12.resolve(cwd, options.dir || "./docs");
2243
+ const targetDir = path13.resolve(cwd, options.dir || "./docs");
2205
2244
  const skipPrompts = !!options.yes || !!options.nonInteractive;
2206
2245
  if (options.docsRepo && !["embedded", "standalone"].includes(options.docsRepo)) {
2207
2246
  throw createCliError(
@@ -2241,18 +2280,18 @@ async function runInit(options) {
2241
2280
  }
2242
2281
  console.log();
2243
2282
  console.log(
2244
- chalk8.blue(`${tr(lang, "cli", "init.currentDirectoryLabel")}: ${cwd}`)
2283
+ chalk9.blue(`${tr(lang, "cli", "init.currentDirectoryLabel")}: ${cwd}`)
2245
2284
  );
2246
2285
  if (isInsideGitRepo) {
2247
- console.log(chalk8.green(tr(lang, "cli", "init.gitDetected")));
2286
+ console.log(chalk9.green(tr(lang, "cli", "init.gitDetected")));
2248
2287
  console.log();
2249
- console.log(chalk8.gray(tr(lang, "cli", "init.insideProjectRoot")));
2250
- console.log(chalk8.gray(tr(lang, "cli", "init.modeEmbeddedDesc")));
2251
- console.log(chalk8.gray(tr(lang, "cli", "init.modeStandaloneDesc")));
2252
- console.log(chalk8.gray(tr(lang, "cli", "init.modeStandaloneMove")));
2288
+ console.log(chalk9.gray(tr(lang, "cli", "init.insideProjectRoot")));
2289
+ console.log(chalk9.gray(tr(lang, "cli", "init.modeEmbeddedDesc")));
2290
+ console.log(chalk9.gray(tr(lang, "cli", "init.modeStandaloneDesc")));
2291
+ console.log(chalk9.gray(tr(lang, "cli", "init.modeStandaloneMove")));
2253
2292
  } else {
2254
- console.log(chalk8.yellow(tr(lang, "cli", "init.gitNotDetected")));
2255
- console.log(chalk8.gray(tr(lang, "cli", "init.gitNotDetectedDetail")));
2293
+ console.log(chalk9.yellow(tr(lang, "cli", "init.gitNotDetected")));
2294
+ console.log(chalk9.gray(tr(lang, "cli", "init.gitNotDetectedDetail")));
2256
2295
  }
2257
2296
  console.log();
2258
2297
  const response = await prompts(
@@ -2574,31 +2613,31 @@ async function runInit(options) {
2574
2613
  initial: false
2575
2614
  });
2576
2615
  if (!overwrite) {
2577
- console.log(chalk8.yellow(tr(lang, "cli", "common.canceled")));
2616
+ console.log(chalk9.yellow(tr(lang, "cli", "common.canceled")));
2578
2617
  return;
2579
2618
  }
2580
2619
  }
2581
2620
  }
2582
2621
  }
2583
2622
  console.log();
2584
- console.log(chalk8.blue(tr(lang, "cli", "init.log.creatingDocs")));
2623
+ console.log(chalk9.blue(tr(lang, "cli", "init.log.creatingDocs")));
2585
2624
  console.log(
2586
- chalk8.gray(
2625
+ chalk9.gray(
2587
2626
  ` ${tr(lang, "cli", "init.log.projectLabel")}: ${projectName}`
2588
2627
  )
2589
2628
  );
2590
2629
  console.log(
2591
- chalk8.gray(` ${tr(lang, "cli", "init.log.typeLabel")}: ${projectType}`)
2630
+ chalk9.gray(` ${tr(lang, "cli", "init.log.typeLabel")}: ${projectType}`)
2592
2631
  );
2593
2632
  console.log(
2594
- chalk8.gray(` ${tr(lang, "cli", "init.log.langLabel")}: ${lang}`)
2633
+ chalk9.gray(` ${tr(lang, "cli", "init.log.langLabel")}: ${lang}`)
2595
2634
  );
2596
2635
  console.log(
2597
- chalk8.gray(` ${tr(lang, "cli", "init.log.pathLabel")}: ${targetDir}`)
2636
+ chalk9.gray(` ${tr(lang, "cli", "init.log.pathLabel")}: ${targetDir}`)
2598
2637
  );
2599
2638
  console.log();
2600
2639
  const templatesDir = getTemplatesDir();
2601
- const commonPath = path12.join(templatesDir, lang, "common");
2640
+ const commonPath = path13.join(templatesDir, lang, "common");
2602
2641
  if (!await fs.pathExists(commonPath)) {
2603
2642
  throw new Error(
2604
2643
  tr(lang, "cli", "init.error.templateNotFound", { path: commonPath })
@@ -2607,11 +2646,11 @@ async function runInit(options) {
2607
2646
  const fsAdapter = new DefaultFileSystemAdapter();
2608
2647
  await copyTemplates(fsAdapter, commonPath, targetDir);
2609
2648
  if (projectType === "multi") {
2610
- const featuresRoot = path12.join(targetDir, "features");
2649
+ const featuresRoot = path13.join(targetDir, "features");
2611
2650
  for (const component of components) {
2612
- const componentDir = path12.join(featuresRoot, component);
2651
+ const componentDir = path13.join(featuresRoot, component);
2613
2652
  await fs.ensureDir(componentDir);
2614
- const readmePath = path12.join(componentDir, "README.md");
2653
+ const readmePath = path13.join(componentDir, "README.md");
2615
2654
  if (!await fs.pathExists(readmePath)) {
2616
2655
  await fs.writeFile(
2617
2656
  readmePath,
@@ -2672,20 +2711,20 @@ async function runInit(options) {
2672
2711
  config.projectRoot = projectRoot;
2673
2712
  }
2674
2713
  }
2675
- const configPath = path12.join(targetDir, ".lee-spec-kit.json");
2714
+ const configPath = path13.join(targetDir, ".lee-spec-kit.json");
2676
2715
  await fs.writeJson(configPath, config, { spaces: 2 });
2677
2716
  const extraCommitPathsAbs = [];
2678
2717
  try {
2679
2718
  if (docsRepo === "embedded") {
2680
2719
  const repoRoot = getGitTopLevelOrNull(cwd) || cwd;
2681
- const agentsMdPath = path12.join(repoRoot, "AGENTS.md");
2720
+ const agentsMdPath = path13.join(repoRoot, "AGENTS.md");
2682
2721
  const result = await upsertLeeSpecKitAgentsMd(agentsMdPath, {
2683
2722
  lang,
2684
2723
  docsRepo
2685
2724
  });
2686
2725
  if (result.changed) extraCommitPathsAbs.push(agentsMdPath);
2687
2726
  } else {
2688
- await upsertLeeSpecKitAgentsMd(path12.join(targetDir, "AGENTS.md"), {
2727
+ await upsertLeeSpecKitAgentsMd(path13.join(targetDir, "AGENTS.md"), {
2689
2728
  lang,
2690
2729
  docsRepo
2691
2730
  });
@@ -2695,16 +2734,16 @@ async function runInit(options) {
2695
2734
  } else if (projectRoot && typeof projectRoot === "object") {
2696
2735
  roots.push(...Object.values(projectRoot));
2697
2736
  }
2698
- const resolvedCwd = path12.resolve(cwd);
2737
+ const resolvedCwd = path13.resolve(cwd);
2699
2738
  for (const raw of roots) {
2700
2739
  const value = String(raw || "").trim();
2701
2740
  if (!value) continue;
2702
- const abs = path12.resolve(cwd, value);
2703
- if (abs === resolvedCwd || abs.startsWith(`${resolvedCwd}${path12.sep}`)) {
2741
+ const abs = path13.resolve(cwd, value);
2742
+ if (abs === resolvedCwd || abs.startsWith(`${resolvedCwd}${path13.sep}`)) {
2704
2743
  if (await fs.pathExists(abs)) {
2705
2744
  const stat = await fs.stat(abs);
2706
2745
  if (stat.isDirectory()) {
2707
- await upsertLeeSpecKitAgentsMd(path12.join(abs, "AGENTS.md"), {
2746
+ await upsertLeeSpecKitAgentsMd(path13.join(abs, "AGENTS.md"), {
2708
2747
  lang,
2709
2748
  docsRepo
2710
2749
  });
@@ -2715,7 +2754,7 @@ async function runInit(options) {
2715
2754
  }
2716
2755
  } catch {
2717
2756
  }
2718
- console.log(chalk8.green(tr(lang, "cli", "init.log.docsCreated")));
2757
+ console.log(chalk9.green(tr(lang, "cli", "init.log.docsCreated")));
2719
2758
  console.log();
2720
2759
  await initGit(
2721
2760
  cwd,
@@ -2726,14 +2765,14 @@ async function runInit(options) {
2726
2765
  docsRemote,
2727
2766
  extraCommitPathsAbs
2728
2767
  );
2729
- console.log(chalk8.blue(tr(lang, "cli", "init.log.nextStepsTitle")));
2768
+ console.log(chalk9.blue(tr(lang, "cli", "init.log.nextStepsTitle")));
2730
2769
  console.log(
2731
- chalk8.gray(
2770
+ chalk9.gray(
2732
2771
  tr(lang, "cli", "init.log.nextSteps1", { docsDir: targetDir })
2733
2772
  )
2734
2773
  );
2735
- console.log(chalk8.gray(tr(lang, "cli", "init.log.nextSteps2")));
2736
- console.log(chalk8.gray(tr(lang, "cli", "init.log.nextSteps3")));
2774
+ console.log(chalk9.gray(tr(lang, "cli", "init.log.nextSteps2")));
2775
+ console.log(chalk9.gray(tr(lang, "cli", "init.log.nextSteps3")));
2737
2776
  console.log();
2738
2777
  },
2739
2778
  { owner: "init" }
@@ -2788,31 +2827,31 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2788
2827
  try {
2789
2828
  runGitOrThrow(["rev-parse", "--is-inside-work-tree"], gitWorkdir);
2790
2829
  console.log(
2791
- chalk8.blue(tr(lang, "cli", "init.log.gitRepoDetectedCommit"))
2830
+ chalk9.blue(tr(lang, "cli", "init.log.gitRepoDetectedCommit"))
2792
2831
  );
2793
2832
  } catch {
2794
- console.log(chalk8.blue(tr(lang, "cli", "init.log.gitInit")));
2833
+ console.log(chalk9.blue(tr(lang, "cli", "init.log.gitInit")));
2795
2834
  runGitOrThrow(["init"], gitWorkdir);
2796
2835
  }
2797
- const relativePath = docsRepo === "standalone" ? "." : path12.relative(gitWorkdir, targetDir);
2836
+ const relativePath = docsRepo === "standalone" ? "." : path13.relative(gitWorkdir, targetDir);
2798
2837
  const stagedBeforeAdd = getCachedStagedFiles(gitWorkdir);
2799
2838
  if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
2800
- console.log(chalk8.yellow(tr(lang, "cli", "init.warn.stagedChangesSkip")));
2801
- console.log(chalk8.gray(tr(lang, "cli", "init.warn.commitManually")));
2839
+ console.log(chalk9.yellow(tr(lang, "cli", "init.warn.stagedChangesSkip")));
2840
+ console.log(chalk9.gray(tr(lang, "cli", "init.warn.commitManually")));
2802
2841
  console.log();
2803
2842
  return;
2804
2843
  }
2805
2844
  if (relativePath !== "." && isPathIgnored(gitWorkdir, relativePath)) {
2806
2845
  const repoRelativePath = toRepoRelativePath(gitWorkdir, relativePath);
2807
2846
  console.log(
2808
- chalk8.yellow(
2847
+ chalk9.yellow(
2809
2848
  tr(lang, "cli", "init.warn.docsPathIgnoredSkipCommit", {
2810
2849
  path: repoRelativePath
2811
2850
  })
2812
2851
  )
2813
2852
  );
2814
2853
  console.log(
2815
- chalk8.gray(
2854
+ chalk9.gray(
2816
2855
  tr(lang, "cli", "init.warn.docsPathIgnoredHint", {
2817
2856
  path: repoRelativePath
2818
2857
  })
@@ -2821,7 +2860,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2821
2860
  console.log();
2822
2861
  return;
2823
2862
  }
2824
- const extraRelativePaths = extraCommitPathsAbs.map((absPath) => path12.relative(gitWorkdir, absPath)).map((p) => p.replace(/\\/g, "/").trim()).filter((p) => !!p && p !== "." && !p.startsWith("../"));
2863
+ const extraRelativePaths = extraCommitPathsAbs.map((absPath) => path13.relative(gitWorkdir, absPath)).map((p) => p.replace(/\\/g, "/").trim()).filter((p) => !!p && p !== "." && !p.startsWith("../"));
2825
2864
  const pathsToStage = [relativePath, ...extraRelativePaths];
2826
2865
  for (const p of pathsToStage) {
2827
2866
  runGitOrThrow(["add", p], gitWorkdir);
@@ -2840,34 +2879,34 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote, ext
2840
2879
  try {
2841
2880
  runGitOrThrow(["remote", "add", "origin", docsRemote], gitWorkdir);
2842
2881
  console.log(
2843
- chalk8.green(
2882
+ chalk9.green(
2844
2883
  tr(lang, "cli", "init.log.gitRemoteSet", { remote: docsRemote })
2845
2884
  )
2846
2885
  );
2847
2886
  } catch {
2848
- console.log(chalk8.yellow(tr(lang, "cli", "init.warn.gitRemoteExists")));
2887
+ console.log(chalk9.yellow(tr(lang, "cli", "init.warn.gitRemoteExists")));
2849
2888
  }
2850
2889
  }
2851
- console.log(chalk8.green(tr(lang, "cli", "init.log.gitInitialCommitDone")));
2890
+ console.log(chalk9.green(tr(lang, "cli", "init.log.gitInitialCommitDone")));
2852
2891
  console.log();
2853
2892
  } catch {
2854
- console.log(chalk8.yellow(tr(lang, "cli", "init.warn.skipGitInit")));
2893
+ console.log(chalk9.yellow(tr(lang, "cli", "init.warn.skipGitInit")));
2855
2894
  console.log();
2856
2895
  }
2857
2896
  }
2858
2897
  function getAncestorDirs(startDir) {
2859
2898
  const dirs = [];
2860
- let current = path12.resolve(startDir);
2899
+ let current = path13.resolve(startDir);
2861
2900
  while (true) {
2862
2901
  dirs.push(current);
2863
- const parent = path12.dirname(current);
2902
+ const parent = path13.dirname(current);
2864
2903
  if (parent === current) break;
2865
2904
  current = parent;
2866
2905
  }
2867
2906
  return dirs;
2868
2907
  }
2869
2908
  function hasWorkspaceBoundary(dir) {
2870
- return fs.existsSync(path12.join(dir, "package.json")) || fs.existsSync(path12.join(dir, ".git"));
2909
+ return fs.existsSync(path13.join(dir, "package.json")) || fs.existsSync(path13.join(dir, ".git"));
2871
2910
  }
2872
2911
  function getSearchBaseDirs(cwd) {
2873
2912
  const ancestors = getAncestorDirs(cwd);
@@ -2883,7 +2922,7 @@ function normalizeComponentKeys(value) {
2883
2922
  return Object.keys(value).map((key) => key.trim().toLowerCase()).filter(Boolean);
2884
2923
  }
2885
2924
  async function inferComponentsFromFeaturesDir(docsDir) {
2886
- const featuresPath = path12.join(docsDir, "features");
2925
+ const featuresPath = path13.join(docsDir, "features");
2887
2926
  if (!await fs.pathExists(featuresPath)) return [];
2888
2927
  const entries = await fs.readdir(featuresPath, { withFileTypes: true });
2889
2928
  const inferred = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name.trim().toLowerCase()).filter(
@@ -2894,21 +2933,21 @@ async function inferComponentsFromFeaturesDir(docsDir) {
2894
2933
  async function getConfig(cwd) {
2895
2934
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2896
2935
  const baseDirs = [
2897
- ...explicitDocsDir ? [path12.resolve(explicitDocsDir)] : [],
2936
+ ...explicitDocsDir ? [path13.resolve(explicitDocsDir)] : [],
2898
2937
  ...getSearchBaseDirs(cwd)
2899
2938
  ];
2900
2939
  const visitedBaseDirs = /* @__PURE__ */ new Set();
2901
2940
  const visitedDocsDirs = /* @__PURE__ */ new Set();
2902
2941
  for (const baseDir of baseDirs) {
2903
- const resolvedBaseDir = path12.resolve(baseDir);
2942
+ const resolvedBaseDir = path13.resolve(baseDir);
2904
2943
  if (visitedBaseDirs.has(resolvedBaseDir)) continue;
2905
2944
  visitedBaseDirs.add(resolvedBaseDir);
2906
- const possibleDocsDirs = [path12.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2945
+ const possibleDocsDirs = [path13.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2907
2946
  for (const docsDir of possibleDocsDirs) {
2908
- const resolvedDocsDir = path12.resolve(docsDir);
2947
+ const resolvedDocsDir = path13.resolve(docsDir);
2909
2948
  if (visitedDocsDirs.has(resolvedDocsDir)) continue;
2910
2949
  visitedDocsDirs.add(resolvedDocsDir);
2911
- const configPath = path12.join(resolvedDocsDir, ".lee-spec-kit.json");
2950
+ const configPath = path13.join(resolvedDocsDir, ".lee-spec-kit.json");
2912
2951
  if (await fs.pathExists(configPath)) {
2913
2952
  try {
2914
2953
  const configFile = await fs.readJson(configPath);
@@ -2938,16 +2977,16 @@ async function getConfig(cwd) {
2938
2977
  } catch {
2939
2978
  }
2940
2979
  }
2941
- const agentsPath = path12.join(resolvedDocsDir, "agents");
2942
- const featuresPath = path12.join(resolvedDocsDir, "features");
2980
+ const agentsPath = path13.join(resolvedDocsDir, "agents");
2981
+ const featuresPath = path13.join(resolvedDocsDir, "features");
2943
2982
  if (await fs.pathExists(agentsPath) && await fs.pathExists(featuresPath)) {
2944
2983
  const inferredComponents = await inferComponentsFromFeaturesDir(resolvedDocsDir);
2945
2984
  const projectType = inferredComponents.length > 0 ? "multi" : "single";
2946
2985
  const components = projectType === "multi" ? resolveProjectComponents("multi", inferredComponents) : void 0;
2947
2986
  const langProbeCandidates = [
2948
- path12.join(agentsPath, "custom.md"),
2949
- path12.join(agentsPath, "constitution.md"),
2950
- path12.join(agentsPath, "agents.md")
2987
+ path13.join(agentsPath, "custom.md"),
2988
+ path13.join(agentsPath, "constitution.md"),
2989
+ path13.join(agentsPath, "agents.md")
2951
2990
  ];
2952
2991
  let lang = "en";
2953
2992
  for (const candidate of langProbeCandidates) {
@@ -3018,18 +3057,18 @@ async function patchMarkdownIfExists(filePath, transform) {
3018
3057
  await fs.writeFile(filePath, transform(content), "utf-8");
3019
3058
  }
3020
3059
  async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
3021
- await patchMarkdownIfExists(path12.join(featureDir, "spec.md"), sanitizeSpecForLocal);
3060
+ await patchMarkdownIfExists(path13.join(featureDir, "spec.md"), sanitizeSpecForLocal);
3022
3061
  await patchMarkdownIfExists(
3023
- path12.join(featureDir, "tasks.md"),
3062
+ path13.join(featureDir, "tasks.md"),
3024
3063
  (content) => sanitizeTasksForLocal(content, lang)
3025
3064
  );
3026
- await fs.remove(path12.join(featureDir, "issue.md"));
3027
- await fs.remove(path12.join(featureDir, "pr.md"));
3065
+ await fs.remove(path13.join(featureDir, "issue.md"));
3066
+ await fs.remove(path13.join(featureDir, "pr.md"));
3028
3067
  }
3029
3068
 
3030
3069
  // src/commands/feature.ts
3031
3070
  function featureCommand(program2) {
3032
- program2.command("feature <name>").description("Create a new feature folder").option("--component <component>", "Component name (multi only)").option("--id <id>", "Feature ID (default: auto)").option("-d, --desc <description>", "Feature description for spec.md").option("--non-interactive", "Fail instead of prompting for input").option("--json", "Output in JSON format for agents").action(async (name, options) => {
3071
+ program2.command("feature <name>").description("Create a new feature folder").option("--component <component>", "Component name (multi only)").option("--id <id>", "Feature ID (default: auto)").option("-d, --desc <description>", "Feature description for spec.md").option("--idea <ref>", "Idea reference to promote (I001 | I001-slug | docs/ideas/...)").option("--non-interactive", "Fail instead of prompting for input").option("--json", "Output in JSON format for agents").action(async (name, options) => {
3033
3072
  try {
3034
3073
  const result = await runFeature(name, options);
3035
3074
  if (options.json) {
@@ -3062,7 +3101,7 @@ function featureCommand(program2) {
3062
3101
  );
3063
3102
  return;
3064
3103
  }
3065
- console.log(chalk8.yellow(`
3104
+ console.log(chalk9.yellow(`
3066
3105
  ${tr(lang2, "cli", "common.canceled")}`));
3067
3106
  return;
3068
3107
  }
@@ -3083,8 +3122,8 @@ ${tr(lang2, "cli", "common.canceled")}`));
3083
3122
  return;
3084
3123
  }
3085
3124
  console.error(
3086
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
3087
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
3125
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
3126
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
3088
3127
  );
3089
3128
  printCliErrorSuggestions(suggestions, lang);
3090
3129
  process.exitCode = 1;
@@ -3110,6 +3149,7 @@ async function runFeature(name, options) {
3110
3149
  projectType,
3111
3150
  config.components
3112
3151
  );
3152
+ const linkedIdea = options.idea ? await resolveIdeaReference(docsDir, options.idea, lang) : null;
3113
3153
  assertValid(
3114
3154
  validateSafeNameWithLang(name, lang),
3115
3155
  tr(lang, "cli", "validation.context.featureName"),
@@ -3175,19 +3215,19 @@ async function runFeature(name, options) {
3175
3215
  }
3176
3216
  let featuresDir;
3177
3217
  if (projectType === "multi") {
3178
- featuresDir = path12.join(docsDir, "features", component);
3218
+ featuresDir = path13.join(docsDir, "features", component);
3179
3219
  } else {
3180
- featuresDir = path12.join(docsDir, "features");
3220
+ featuresDir = path13.join(docsDir, "features");
3181
3221
  }
3182
3222
  const featureFolderName = `${featureId}-${name}`;
3183
- const featureDir = path12.join(featuresDir, featureFolderName);
3223
+ const featureDir = path13.join(featuresDir, featureFolderName);
3184
3224
  if (await fs.pathExists(featureDir)) {
3185
3225
  throw createCliError(
3186
3226
  "INVALID_ARGUMENT",
3187
3227
  tr(lang, "cli", "feature.folderExists", { path: featureDir })
3188
3228
  );
3189
3229
  }
3190
- const featureBasePath = path12.join(
3230
+ const featureBasePath = path13.join(
3191
3231
  getTemplatesDir(),
3192
3232
  lang,
3193
3233
  "common",
@@ -3232,23 +3272,30 @@ async function runFeature(name, options) {
3232
3272
  }
3233
3273
  const fsAdapter = new DefaultFileSystemAdapter();
3234
3274
  await replaceInFiles(fsAdapter, featureDir, replacements);
3275
+ if (linkedIdea) {
3276
+ await stampIdeaReferenceInSpec(
3277
+ path13.join(featureDir, "spec.md"),
3278
+ path13.relative(featureDir, linkedIdea.path)
3279
+ );
3280
+ await markIdeaAsFeatureized(linkedIdea.path, featureFolderName);
3281
+ }
3235
3282
  if (config.workflow?.mode === "local") {
3236
3283
  await applyLocalWorkflowTemplateToFeatureDir(featureDir, lang);
3237
3284
  }
3238
3285
  if (!options.json) {
3239
3286
  console.log();
3240
3287
  console.log(
3241
- chalk8.green(tr(lang, "cli", "feature.created", { path: featureDir }))
3288
+ chalk9.green(tr(lang, "cli", "feature.created", { path: featureDir }))
3242
3289
  );
3243
3290
  console.log();
3244
- console.log(chalk8.blue(tr(lang, "cli", "feature.nextStepsTitle")));
3291
+ console.log(chalk9.blue(tr(lang, "cli", "feature.nextStepsTitle")));
3245
3292
  console.log(
3246
- chalk8.gray(
3293
+ chalk9.gray(
3247
3294
  tr(lang, "cli", "feature.nextSteps1", { path: featureDir })
3248
3295
  )
3249
3296
  );
3250
- console.log(chalk8.gray(tr(lang, "cli", "feature.nextSteps2")));
3251
- console.log(chalk8.gray(tr(lang, "cli", "feature.nextSteps3")));
3297
+ console.log(chalk9.gray(tr(lang, "cli", "feature.nextSteps2")));
3298
+ console.log(chalk9.gray(tr(lang, "cli", "feature.nextSteps3")));
3252
3299
  console.log();
3253
3300
  }
3254
3301
  return {
@@ -3256,18 +3303,115 @@ async function runFeature(name, options) {
3256
3303
  featureName: name,
3257
3304
  component: projectType === "multi" ? component : void 0,
3258
3305
  featurePath: featureDir,
3259
- featurePathFromDocs: path12.relative(docsDir, featureDir)
3306
+ featurePathFromDocs: path13.relative(docsDir, featureDir)
3260
3307
  };
3261
3308
  },
3262
3309
  { owner: "feature" }
3263
3310
  );
3264
3311
  }
3312
+ async function resolveIdeaReference(docsDir, ref, lang) {
3313
+ const ideasDir = path13.join(docsDir, "ideas");
3314
+ const trimmedRef = ref.trim();
3315
+ if (!trimmedRef) {
3316
+ throw createCliError(
3317
+ "INVALID_ARGUMENT",
3318
+ tr(lang, "cli", "feature.ideaNotFound", { ref })
3319
+ );
3320
+ }
3321
+ if (trimmedRef.includes("/") || trimmedRef.endsWith(".md")) {
3322
+ const candidate = path13.resolve(process.cwd(), trimmedRef);
3323
+ if (await fs.pathExists(candidate)) {
3324
+ return { path: candidate };
3325
+ }
3326
+ throw createCliError(
3327
+ "INVALID_ARGUMENT",
3328
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3329
+ );
3330
+ }
3331
+ if (!await fs.pathExists(ideasDir)) {
3332
+ throw createCliError(
3333
+ "INVALID_ARGUMENT",
3334
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3335
+ );
3336
+ }
3337
+ const entries = await fs.readdir(ideasDir, { withFileTypes: true });
3338
+ const files = entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md")).map((entry) => entry.name);
3339
+ const exactName = `${trimmedRef}.md`;
3340
+ if (files.includes(exactName)) {
3341
+ return { path: path13.join(ideasDir, exactName) };
3342
+ }
3343
+ const byId = /^I\d{3,}$/.test(trimmedRef) ? files.filter((name) => name.startsWith(`${trimmedRef}-`)) : [];
3344
+ if (byId.length === 1) {
3345
+ return { path: path13.join(ideasDir, byId[0]) };
3346
+ }
3347
+ if (byId.length > 1) {
3348
+ throw createCliError(
3349
+ "INVALID_ARGUMENT",
3350
+ tr(lang, "cli", "feature.ideaAmbiguous", { ref: trimmedRef })
3351
+ );
3352
+ }
3353
+ throw createCliError(
3354
+ "INVALID_ARGUMENT",
3355
+ tr(lang, "cli", "feature.ideaNotFound", { ref: trimmedRef })
3356
+ );
3357
+ }
3358
+ async function stampIdeaReferenceInSpec(specPath, relativeIdeaPath) {
3359
+ const normalizedPath = relativeIdeaPath.replace(/\\/g, "/");
3360
+ const ideaLine = `- Idea: \`${normalizedPath}\``;
3361
+ let content = await fs.readFile(specPath, "utf-8");
3362
+ if (content.includes(ideaLine)) {
3363
+ return;
3364
+ }
3365
+ if (content.includes("## Related Documents")) {
3366
+ content = content.replace(
3367
+ "## Related Documents\n\n",
3368
+ `## Related Documents
3369
+
3370
+ ${ideaLine}
3371
+ `
3372
+ );
3373
+ } else {
3374
+ content = `${content.trimEnd()}
3375
+
3376
+ ${ideaLine}
3377
+ `;
3378
+ }
3379
+ await fs.writeFile(specPath, content, "utf-8");
3380
+ }
3381
+ async function markIdeaAsFeatureized(ideaPath, featureFolderName) {
3382
+ let content = await fs.readFile(ideaPath, "utf-8");
3383
+ content = replaceOrAppendIdeaMetadata(content, "Status", "Featureized");
3384
+ content = replaceOrAppendIdeaMetadata(content, "Feature", featureFolderName);
3385
+ await fs.writeFile(ideaPath, content, "utf-8");
3386
+ }
3387
+ function replaceOrAppendIdeaMetadata(content, label, value) {
3388
+ const pattern = new RegExp(`^- \\*\\*${escapeRegExp(label)}\\*\\*:.*$`, "m");
3389
+ const line = `- **${label}**: ${value}`;
3390
+ if (pattern.test(content)) {
3391
+ return content.replace(pattern, line);
3392
+ }
3393
+ const heading = "## Promotion Tracking";
3394
+ if (content.includes(heading)) {
3395
+ return content.replace(heading, `${heading}
3396
+
3397
+ ${line}`);
3398
+ }
3399
+ return `${content.trimEnd()}
3400
+
3401
+ ${heading}
3402
+
3403
+ ${line}
3404
+ `;
3405
+ }
3406
+ function escapeRegExp(value) {
3407
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3408
+ }
3265
3409
  async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
3266
3410
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
3267
3411
  const candidates = [
3268
- ...explicitDocsDir ? [path12.resolve(explicitDocsDir)] : [],
3269
- path12.resolve(cwd, "docs"),
3270
- path12.resolve(cwd)
3412
+ ...explicitDocsDir ? [path13.resolve(explicitDocsDir)] : [],
3413
+ path13.resolve(cwd, "docs"),
3414
+ path13.resolve(cwd)
3271
3415
  ];
3272
3416
  const endAt = Date.now() + timeoutMs;
3273
3417
  while (Date.now() < endAt) {
@@ -3294,12 +3438,12 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
3294
3438
  return getConfig(cwd);
3295
3439
  }
3296
3440
  async function getNextFeatureId(docsDir, projectType, components) {
3297
- const featuresDir = path12.join(docsDir, "features");
3441
+ const featuresDir = path13.join(docsDir, "features");
3298
3442
  let max = 0;
3299
3443
  const scanDirs = [];
3300
3444
  if (projectType === "multi") {
3301
3445
  scanDirs.push(
3302
- ...components.map((component) => path12.join(featuresDir, component))
3446
+ ...components.map((component) => path13.join(featuresDir, component))
3303
3447
  );
3304
3448
  } else {
3305
3449
  scanDirs.push(featuresDir);
@@ -3320,6 +3464,167 @@ async function getNextFeatureId(docsDir, projectType, components) {
3320
3464
  const width = Math.max(3, String(next).length);
3321
3465
  return `F${String(next).padStart(width, "0")}`;
3322
3466
  }
3467
+ function ideaCommand(program2) {
3468
+ program2.command("idea <name>").description("Create a new indexed idea document").option("--component <component>", "Component name (optional)").option("--id <id>", "Idea ID (default: auto)").option("-d, --desc <description>", "Idea description for the document").option("--non-interactive", "Reserved for parity with other generators").option("--json", "Output in JSON format for agents").action(async (name, options) => {
3469
+ try {
3470
+ const result = await runIdea(name, options);
3471
+ if (options.json) {
3472
+ console.log(
3473
+ JSON.stringify(
3474
+ {
3475
+ status: "ok",
3476
+ reasonCode: "IDEA_CREATED",
3477
+ ideaId: result.ideaId,
3478
+ ideaName: result.ideaName,
3479
+ component: result.component,
3480
+ ideaPath: result.ideaPath,
3481
+ ideaPathFromDocs: result.ideaPathFromDocs
3482
+ },
3483
+ null,
3484
+ 2
3485
+ )
3486
+ );
3487
+ }
3488
+ } catch (error) {
3489
+ const config = await getConfig(process.cwd());
3490
+ const lang = config?.lang ?? DEFAULT_LANG;
3491
+ const cliError = toCliError(error);
3492
+ const suggestions = getCliErrorSuggestions(cliError.code, lang);
3493
+ if (options.json) {
3494
+ console.log(
3495
+ JSON.stringify({
3496
+ status: "error",
3497
+ reasonCode: cliError.code,
3498
+ error: cliError.message,
3499
+ suggestions
3500
+ })
3501
+ );
3502
+ process.exitCode = 1;
3503
+ return;
3504
+ }
3505
+ console.error(
3506
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
3507
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
3508
+ );
3509
+ printCliErrorSuggestions(suggestions, lang);
3510
+ process.exitCode = 1;
3511
+ }
3512
+ });
3513
+ }
3514
+ async function runIdea(name, options) {
3515
+ const cwd = process.cwd();
3516
+ const config = await getConfig(cwd);
3517
+ if (!config) {
3518
+ throw createCliError(
3519
+ "DOCS_NOT_FOUND",
3520
+ tr(DEFAULT_LANG, "cli", "common.docsNotFound")
3521
+ );
3522
+ }
3523
+ const { docsDir, projectType, lang } = config;
3524
+ const configuredComponents = resolveProjectComponents(
3525
+ projectType,
3526
+ config.components
3527
+ );
3528
+ assertValid(
3529
+ validateSafeNameWithLang(name, lang),
3530
+ tr(lang, "cli", "validation.context.ideaName"),
3531
+ lang
3532
+ );
3533
+ let component = (options.component || "").trim().toLowerCase();
3534
+ if (component && projectType === "single") {
3535
+ throw createCliError(
3536
+ "INVALID_ARGUMENT",
3537
+ "`--component` can only be used in multi mode."
3538
+ );
3539
+ }
3540
+ if (projectType === "multi" && component) {
3541
+ assertAllowedComponent(component, configuredComponents);
3542
+ }
3543
+ return withFileLock(
3544
+ getDocsLockPath(docsDir),
3545
+ async () => {
3546
+ const ideaId = options.id ? validateProvidedIdeaId(options.id, lang) : await getNextIdeaId(docsDir);
3547
+ const ideasDir = path13.join(docsDir, "ideas");
3548
+ const ideaFileName = `${ideaId}-${name}.md`;
3549
+ const ideaPath = path13.join(ideasDir, ideaFileName);
3550
+ if (await fs.pathExists(ideaPath)) {
3551
+ throw createCliError(
3552
+ "INVALID_ARGUMENT",
3553
+ tr(lang, "cli", "idea.fileExists", { path: ideaPath })
3554
+ );
3555
+ }
3556
+ const templatePath = path13.join(
3557
+ getTemplatesDir(),
3558
+ lang,
3559
+ "common",
3560
+ "ideas",
3561
+ "idea.md"
3562
+ );
3563
+ if (!await fs.pathExists(templatePath)) {
3564
+ throw createCliError(
3565
+ "DOCS_NOT_FOUND",
3566
+ tr(lang, "cli", "idea.templateNotFound")
3567
+ );
3568
+ }
3569
+ await fs.mkdir(ideasDir, { recursive: true });
3570
+ const template = await fs.readFile(templatePath, "utf-8");
3571
+ const content = applyIdeaTemplate(template, {
3572
+ ideaId,
3573
+ name,
3574
+ description: options.desc || "",
3575
+ component: component || "-",
3576
+ created: getLocalDateString()
3577
+ });
3578
+ await fs.writeFile(ideaPath, content, "utf-8");
3579
+ if (!options.json) {
3580
+ console.log();
3581
+ console.log(chalk9.green(tr(lang, "cli", "idea.created", { path: ideaPath })));
3582
+ console.log();
3583
+ console.log(chalk9.blue(tr(lang, "cli", "idea.nextStepsTitle")));
3584
+ console.log(chalk9.gray(tr(lang, "cli", "idea.nextSteps1")));
3585
+ console.log(chalk9.gray(tr(lang, "cli", "idea.nextSteps2", { ideaId })));
3586
+ console.log(chalk9.gray(tr(lang, "cli", "idea.nextSteps3")));
3587
+ console.log();
3588
+ }
3589
+ return {
3590
+ ideaId,
3591
+ ideaName: name,
3592
+ component: component || void 0,
3593
+ ideaPath,
3594
+ ideaPathFromDocs: path13.relative(docsDir, ideaPath)
3595
+ };
3596
+ },
3597
+ { owner: "idea" }
3598
+ );
3599
+ }
3600
+ function validateProvidedIdeaId(id, lang) {
3601
+ assertValid(
3602
+ validateIdeaIdWithLang(id, lang),
3603
+ tr(lang, "cli", "validation.context.ideaId"),
3604
+ lang
3605
+ );
3606
+ return id;
3607
+ }
3608
+ function applyIdeaTemplate(template, values) {
3609
+ return template.replaceAll("{idea-id}", values.ideaId).replaceAll("{idea-name}", values.name).replaceAll("{YYYY-MM-DD}", values.created).replaceAll("{{description}}", values.description).replaceAll("{component}", values.component);
3610
+ }
3611
+ async function getNextIdeaId(docsDir) {
3612
+ const ideasDir = path13.join(docsDir, "ideas");
3613
+ let max = 0;
3614
+ if (await fs.pathExists(ideasDir)) {
3615
+ const entries = await fs.readdir(ideasDir, { withFileTypes: true });
3616
+ for (const entry of entries) {
3617
+ if (!entry.isFile()) continue;
3618
+ const match = entry.name.match(/^I(\d+)-/);
3619
+ if (!match) continue;
3620
+ const num = parseInt(match[1], 10);
3621
+ if (num > max) max = num;
3622
+ }
3623
+ }
3624
+ const next = max + 1;
3625
+ const width = Math.max(3, String(next).length);
3626
+ return `I${String(next).padStart(width, "0")}`;
3627
+ }
3323
3628
  var DefaultCommandAdapter = class {
3324
3629
  execSync(command, options) {
3325
3630
  return execSync(command, options);
@@ -3579,15 +3884,15 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
3579
3884
  2. \uB9AC\uBDF0 \uBC94\uC704\uB97C \uBD84\uB9AC\uD574 \uD655\uC778\uD558\uC138\uC694.
3580
3885
  - main \uAE30\uC900: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
3581
3886
  - worktree \uAE30\uC900: 'git diff --name-only', 'git diff --name-only --cached', 'git ls-files --others --exclude-standard'
3582
- 3. \uAD6C\uD604\uC774 feature \uC758\uB3C4\uC5D0 \uB9DE\uB294\uC9C0 \uD3C9\uAC00\uD558\uC138\uC694. \uD2B9\uD788 \`featureIntentSummary\`, \`implementationFit\`, \`missingCases\`, \`residualRisks\`\uB97C \uAD6C\uCCB4\uC801\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694.
3583
- 4. \uD655\uC778\uB41C \uAC01 \uD30C\uC77C\uC5D0 \uB300\uD574 risk, security, perf, maintainability \uD3C9\uAC00\uC640 \uAD6C\uCCB4\uC801\uC778 fileLine \uC704\uCE58\uAC00 \uD3EC\uD568\uB41C 'review-trace.json' \uC99D\uAC70 \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC138\uC694.
3887
+ 3. \uAD6C\uD604\uC774 feature \uC758\uB3C4\uC5D0 \uB9DE\uB294\uC9C0 \uD3C9\uAC00\uD558\uC138\uC694. \uD2B9\uD788 \`featureIntentSummary\`, \`implementationFit\`, \`missingCases\`, \`residualRisks\`, \`approvalRationale\`\uB97C \uAD6C\uCCB4\uC801\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694.
3888
+ 4. \uD655\uC778\uB41C \uAC01 \uD30C\uC77C\uC5D0 \uB300\uD574 risk, security, perf, maintainability \uD3C9\uAC00\uC640 \uAD6C\uCCB4\uC801\uC778 fileLine \uC704\uCE58\uAC00 \uD3EC\uD568\uB41C 'review-trace.json' \uC99D\uAC70 \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC138\uC694. \uC99D\uAC70\uC5D0\uB294 \uBC18\uB4DC\uC2DC \`baseSha\`, \`headSha\`, \`changedFiles\`, \`reviewedFiles\`, \`riskSummaries\`(blocking/important/minor)\uAC00 \uD3EC\uD568\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4.
3584
3889
  5. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 '${fallbackText}'\uC774\uBA70, 'create-pr' \uBB38\uC11C\uC758 'Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8' \uC139\uC158\uC744 \uC218\uD589\uD558\uC138\uC694.
3585
3890
  6. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: ${skills.length > 0 ? skills.join(", ") : "\uC5C6\uC74C"} \uB85C \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694.
3586
3891
  7. \uCD94\uAC00 \uAC80\uC99D\uC774 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC audit/\uD0C0\uAE43 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694. \uBCC4\uB3C4 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uCD94\uAC00 \uC0DD\uC131\uB3C4 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC \uD558\uC138\uC694.
3587
3892
  8. \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uACE0, \uC774\uBBF8 \uC218\uC9D1\uD55C \uACB0\uACFC\uB9CC \uC815\uB9AC\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3588
3893
  9. \uC2E4\uD589\uD55C \uBA85\uB839\uC774 \uC788\uC73C\uBA74 \`commandsExecuted\`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.
3589
- 10. \uC9C0\uC801\uC0AC\uD56D\uC774 \uB0A8\uC544 \uC788\uC73C\uBA74 \uBA3C\uC800 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested' \uB85C \uAE30\uB85D\uD558\uC138\uC694. \uB2E8, \`workflow.prePrReview.evidenceMode=any\` \uC774\uACE0 \uC2E4\uD589 \uC99D\uAC70 \uAC15\uC81C\uAC00 \uC5C6\uC73C\uBA74 \`--evidence\` \uC5C6\uC774 \uC9C1\uC811 \uAE30\uB85D\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3590
- 11. \uC218\uC815/\uC7AC\uAC80\uC99D \uD6C4 \uCD5C\uC885 \uC2B9\uC778 \uC2DC\uC810\uC5D0 'npx lee-spec-kit pre-pr-review <feature> --decision approve' \uB97C \uC2E4\uD589\uD558\uC138\uC694. \`path_required\` \uC815\uCC45\uC77C \uB54C\uB9CC \`--evidence review-trace.json\` \uC744 \uD568\uAED8 \uBD99\uC774\uC138\uC694.`;
3894
+ 10. \uC9C0\uC801\uC0AC\uD56D\uC774 \uB0A8\uC544 \uC788\uC73C\uBA74 \uBA3C\uC800 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested' \uB85C \uAE30\uB85D\uD558\uC138\uC694. \uB2E8, \`workflow.prePrReview.evidenceMode=any\` \uC774\uACE0 \uC2E4\uD589 \uC99D\uAC70 \uAC15\uC81C\uAC00 \uC5C6\uC73C\uBA74 \`--evidence\` \uC5C6\uC774 \uC9C1\uC811 \uAE30\uB85D\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3895
+ 11. \uC218\uC815/\uC7AC\uAC80\uC99D \uD6C4 \uCD5C\uC885 \uC2B9\uC778 \uC2DC\uC810\uC5D0\uB294 \uBC18\uB4DC\uC2DC \uAD6C\uC870\uD654\uB41C evidence\uC640 \uD568\uAED8 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision approve' \uB97C \uC2E4\uD589\uD558\uC138\uC694. approve\uB294 evidence \uC5C6\uC774 \uAE30\uB85D\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`;
3591
3896
  }
3592
3897
  return `Conduct a pre-PR code review.
3593
3898
  0. Reuse the existing helper/sub-agent for this feature review if one already exists. Default to a single helper agent.
@@ -3595,15 +3900,15 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
3595
3900
  2. Split and check the review scope.
3596
3901
  - Main scope: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
3597
3902
  - Worktree scope: 'git diff --name-only', 'git diff --name-only --cached', 'git ls-files --others --exclude-standard'
3598
- 3. Evaluate whether the implementation actually fits the feature intent. Capture concrete \`featureIntentSummary\`, \`implementationFit\`, \`missingCases\`, and \`residualRisks\`, and explicitly set \`specAlignmentChecked\`.
3599
- 4. Generate a 'review-trace.json' file for all changed files, including \`findingCount\`, \`blockingFindings\`, evaluations for risk, security, perf, maintainability, and specific fileLine locators.
3903
+ 3. Evaluate whether the implementation actually fits the feature intent. Capture concrete \`featureIntentSummary\`, \`implementationFit\`, \`missingCases\`, \`residualRisks\`, and \`approvalRationale\`, and explicitly set \`specAlignmentChecked\`.
3904
+ 4. Generate a 'review-trace.json' file for all changed files, including \`baseSha\`, \`headSha\`, \`changedFiles\`, \`reviewedFiles\`, \`riskSummaries\` (blocking/important/minor), \`findingCount\`, \`blockingFindings\`, per-file risk/security/perf/maintainability evaluations, and specific \`fileLine\` locators.
3600
3905
  5. The baseline is '${fallbackText}'. Always perform the 'Pre-PR Core Checklist' section of the 'create-pr' document.
3601
3906
  6. Priority skills: ${skills.length > 0 ? skills.join(", ") : "None"} for deeper technical review.
3602
3907
  7. Run extra audit/targeted verification only when the review truly needs more evidence. Spawn additional helper agents only when necessary.
3603
3908
  8. If helper-agent quota is exhausted, continue the review in the main agent and just keep the evidence consistent.
3604
3909
  9. Record commands in \`commandsExecuted\` only when you actually ran them.
3605
- 10. If unresolved findings remain, first record them with 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested'. When \`workflow.prePrReview.evidenceMode=any\` and execution evidence is not enforced, direct record mode without \`--evidence\` is also valid.
3606
- 11. After fixes and re-validation, run 'npx lee-spec-kit pre-pr-review <feature> --decision approve' for final pre-PR approval. Add \`--evidence review-trace.json\` only when the active evidence policy requires a path.`;
3910
+ 10. If unresolved findings remain, first record them with 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested'. When \`workflow.prePrReview.evidenceMode=any\` and execution evidence is not enforced, direct record mode without \`--evidence\` is also valid.
3911
+ 11. After fixes and re-validation, run 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision approve' for final pre-PR approval. Approve never records without structured evidence.`;
3607
3912
  }
3608
3913
  function getCodeReviewPrompt(lang) {
3609
3914
  if (lang === "ko") {
@@ -3743,7 +4048,7 @@ function isNonNegativeIntegerValue(value) {
3743
4048
  }
3744
4049
  function isLikelyCurrentPrePrReviewEvidence(evidencePath, feature) {
3745
4050
  try {
3746
- const raw = fs9.readFileSync(evidencePath, "utf-8");
4051
+ const raw = fs10.readFileSync(evidencePath, "utf-8");
3747
4052
  const parsed = JSON.parse(raw);
3748
4053
  const evidenceFeature = (parsed.feature || "").toString().trim();
3749
4054
  if (evidenceFeature && evidenceFeature !== feature.folderName) {
@@ -3759,31 +4064,31 @@ function resolvePrePrReviewEvidencePath(feature) {
3759
4064
  const candidates = [];
3760
4065
  const explicit = (feature.prePrReview.evidence || "").trim();
3761
4066
  if (explicit && explicit !== "-") {
3762
- if (path12.isAbsolute(explicit)) {
4067
+ if (path13.isAbsolute(explicit)) {
3763
4068
  candidates.push(explicit);
3764
4069
  } else {
3765
- candidates.push(path12.resolve(feature.path, explicit));
3766
- candidates.push(path12.resolve(docsRoot, explicit));
4070
+ candidates.push(path13.resolve(feature.path, explicit));
4071
+ candidates.push(path13.resolve(docsRoot, explicit));
3767
4072
  const normalizedExplicit = explicit.replace(/\\/g, "/");
3768
4073
  if (normalizedExplicit.startsWith("docs/")) {
3769
4074
  const withoutDocsPrefix = normalizedExplicit.slice("docs/".length);
3770
4075
  if (withoutDocsPrefix) {
3771
- candidates.push(path12.resolve(docsRoot, withoutDocsPrefix));
4076
+ candidates.push(path13.resolve(docsRoot, withoutDocsPrefix));
3772
4077
  }
3773
4078
  }
3774
4079
  }
3775
4080
  }
3776
- candidates.push(path12.join(feature.path, "review-trace.json"));
3777
- candidates.push(path12.join(docsRoot, "review-trace.json"));
4081
+ candidates.push(path13.join(feature.path, "review-trace.json"));
4082
+ candidates.push(path13.join(docsRoot, "review-trace.json"));
3778
4083
  const seen = /* @__PURE__ */ new Set();
3779
4084
  for (const candidate of candidates) {
3780
- const abs = path12.resolve(candidate);
4085
+ const abs = path13.resolve(candidate);
3781
4086
  if (seen.has(abs)) continue;
3782
4087
  seen.add(abs);
3783
- if (!fs9.existsSync(abs)) continue;
4088
+ if (!fs10.existsSync(abs)) continue;
3784
4089
  if (!abs.toLowerCase().endsWith(".json")) continue;
3785
4090
  if (!isLikelyCurrentPrePrReviewEvidence(abs, feature)) continue;
3786
- const rel = path12.relative(docsRoot, abs).replace(/\\/g, "/");
4091
+ const rel = path13.relative(docsRoot, abs).replace(/\\/g, "/");
3787
4092
  if (rel && !rel.startsWith("../")) {
3788
4093
  return rel;
3789
4094
  }
@@ -3824,8 +4129,8 @@ function getReviewFixCommitGuidance(feature, lang, options) {
3824
4129
  }
3825
4130
  function resolveManagedWorktreeCleanupPaths(projectGitCwd) {
3826
4131
  if (!projectGitCwd) return null;
3827
- const normalized = path12.resolve(projectGitCwd);
3828
- const marker = `${path12.sep}.worktrees${path12.sep}`;
4132
+ const normalized = path13.resolve(projectGitCwd);
4133
+ const marker = `${path13.sep}.worktrees${path13.sep}`;
3829
4134
  const markerIndex = normalized.lastIndexOf(marker);
3830
4135
  if (markerIndex <= 0) return null;
3831
4136
  const projectRoot = normalized.slice(0, markerIndex);
@@ -3868,7 +4173,7 @@ function toTaskKey(rawTitle) {
3868
4173
  function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
3869
4174
  const docsGitCwd = feature.git.docsGitCwd;
3870
4175
  const tasksRelativePath = normalizeGitRelativePath(
3871
- path12.join(feature.docs.featurePathFromDocs, "tasks.md")
4176
+ path13.join(feature.docs.featurePathFromDocs, "tasks.md")
3872
4177
  );
3873
4178
  const diff = readGitText(ctx, docsGitCwd, [
3874
4179
  "diff",
@@ -3943,7 +4248,7 @@ function checkTaskCommitGate(ctx, feature) {
3943
4248
  return { pass: true };
3944
4249
  }
3945
4250
  const args = ["log", "-n", "1", "--pretty=%s", "--", "."];
3946
- const relativeDocsDir = path12.relative(projectGitCwd, feature.git.docsGitCwd);
4251
+ const relativeDocsDir = path13.relative(projectGitCwd, feature.git.docsGitCwd);
3947
4252
  const normalizedDocsDir = normalizeGitRelativePath(relativeDocsDir);
3948
4253
  if (normalizedDocsDir && normalizedDocsDir !== "." && normalizedDocsDir !== ".." && !normalizedDocsDir.startsWith("../")) {
3949
4254
  args.push(`:(exclude)${normalizedDocsDir}/**`);
@@ -4325,9 +4630,9 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4325
4630
  const isPrePrReviewCurrent = (f) => prePrReviewPolicy.enabled && workflowPolicy.requirePr && f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f) && !f.git.docsHasCommitRequiredChanges && !f.git.projectHasUncommittedChanges && (!isPrMetadataConfigured(f) || !f.pr.link) && !isPrePrReviewSatisfied(f, prePrReviewPolicy);
4326
4631
  const isPrePrReviewMetadataMissing = (f) => isPrePrReviewCurrent(f) && !f.docs.prePrReviewFieldExists;
4327
4632
  const isPrePrReviewFixRequired = (f) => isPrePrReviewCurrent(f) && !!f.prePrReview.decisionOutcome && f.prePrReview.decisionOutcome !== "approve";
4328
- const isPrePrReviewRun = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && f.prePrReview.status !== "Running" && !resolvePrePrReviewEvidencePath(f) && (prePrReviewPolicy.evidenceMode === "path_required" || prePrReviewPolicy.enforceExecutionEvidence);
4329
- const isPrePrReviewRunning = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && f.prePrReview.status === "Running" && !resolvePrePrReviewEvidencePath(f) && (prePrReviewPolicy.evidenceMode === "path_required" || prePrReviewPolicy.enforceExecutionEvidence);
4330
- const isPrePrReviewRecord = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && (!!resolvePrePrReviewEvidencePath(f) || prePrReviewPolicy.evidenceMode === "any" && !prePrReviewPolicy.enforceExecutionEvidence);
4633
+ const isPrePrReviewRun = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && f.prePrReview.status !== "Running" && !resolvePrePrReviewEvidencePath(f);
4634
+ const isPrePrReviewRunning = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && f.prePrReview.status === "Running" && !resolvePrePrReviewEvidencePath(f);
4635
+ const isPrePrReviewRecord = (f) => isPrePrReviewCurrent(f) && f.docs.prePrReviewFieldExists && !isPrePrReviewFixRequired(f) && !!resolvePrePrReviewEvidencePath(f);
4331
4636
  const getPrePrReviewMetadataActions = () => [
4332
4637
  {
4333
4638
  type: "instruction",
@@ -4371,7 +4676,7 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
4371
4676
  cmd: buildSelfCliCommand(buildPrePrReviewRunCommandArgs(f))
4372
4677
  }
4373
4678
  ];
4374
- const getPrePrReviewRunningActions = () => [
4679
+ const getPrePrReviewInProgressActions = () => [
4375
4680
  {
4376
4681
  type: "instruction",
4377
4682
  category: "pre_pr_review_run",
@@ -4909,15 +5214,15 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
4909
5214
  actions: (f) => getPrePrReviewRunActions(f)
4910
5215
  },
4911
5216
  {
4912
- id: "pre_pr_review_running",
5217
+ id: "pre_pr_review_in_progress",
4913
5218
  phase: "running",
4914
5219
  owner: "subagent",
4915
5220
  category: "pre_pr_review_run",
4916
5221
  when: (f) => isPrePrReviewRunning(f),
4917
- actions: () => getPrePrReviewRunningActions()
5222
+ actions: () => getPrePrReviewInProgressActions()
4918
5223
  },
4919
5224
  {
4920
- id: "pre_pr_review_record",
5225
+ id: "pre_pr_review_record_pending",
4921
5226
  phase: "record",
4922
5227
  owner: "main",
4923
5228
  category: "pre_pr_review_record",
@@ -5559,17 +5864,17 @@ function isGitPathIgnored(ctx, cwd, relativePath) {
5559
5864
  }
5560
5865
  }
5561
5866
  var GIT_WORKTREE_CACHE = /* @__PURE__ */ new Map();
5562
- var WORKTREE_MARKER = `${path12.sep}.worktrees${path12.sep}`;
5867
+ var WORKTREE_MARKER = `${path13.sep}.worktrees${path13.sep}`;
5563
5868
  function resetContextGitCaches() {
5564
5869
  GIT_WORKTREE_CACHE.clear();
5565
5870
  }
5566
5871
  function isManagedWorktreePath(cwd) {
5567
5872
  if (!cwd) return false;
5568
- const normalized = path12.resolve(cwd);
5873
+ const normalized = path13.resolve(cwd);
5569
5874
  return normalized.includes(WORKTREE_MARKER);
5570
5875
  }
5571
5876
  function resolveProjectRootFromGitCwd(cwd) {
5572
- const normalized = path12.resolve(cwd);
5877
+ const normalized = path13.resolve(cwd);
5573
5878
  const markerIndex = normalized.lastIndexOf(WORKTREE_MARKER);
5574
5879
  if (markerIndex <= 0) return normalized;
5575
5880
  const projectRoot = normalized.slice(0, markerIndex);
@@ -5588,7 +5893,7 @@ function getGitTopLevel(ctx, cwd) {
5588
5893
  }
5589
5894
  function listGitWorktrees(ctx, cwd) {
5590
5895
  const topLevel = getGitTopLevel(ctx, cwd) || cwd;
5591
- const cacheKey = path12.resolve(topLevel);
5896
+ const cacheKey = path13.resolve(topLevel);
5592
5897
  const cached = GIT_WORKTREE_CACHE.get(cacheKey);
5593
5898
  if (cached) return cached;
5594
5899
  try {
@@ -5689,12 +5994,12 @@ function countDocumentLines(content) {
5689
5994
  if (lines[lines.length - 1] === "") return lines.length - 1;
5690
5995
  return lines.length;
5691
5996
  }
5692
- function escapeRegExp(value) {
5997
+ function escapeRegExp2(value) {
5693
5998
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5694
5999
  }
5695
6000
  function extractSpecValue(content, key) {
5696
6001
  const regex = new RegExp(
5697
- `^\\s*-\\s*\\*\\*${escapeRegExp(key)}\\*\\*\\s*:\\s*(.*)$`,
6002
+ `^\\s*-\\s*\\*\\*${escapeRegExp2(key)}\\*\\*\\s*:\\s*(.*)$`,
5698
6003
  "m"
5699
6004
  );
5700
6005
  const match = content.match(regex);
@@ -5702,7 +6007,7 @@ function extractSpecValue(content, key) {
5702
6007
  }
5703
6008
  function hasSpecKey(content, key) {
5704
6009
  const regex = new RegExp(
5705
- `^\\s*-\\s*\\*\\*${escapeRegExp(key)}\\*\\*\\s*:`,
6010
+ `^\\s*-\\s*\\*\\*${escapeRegExp2(key)}\\*\\*\\s*:`,
5706
6011
  "m"
5707
6012
  );
5708
6013
  return regex.test(content);
@@ -5894,7 +6199,7 @@ function splitReviewLogSections(content, headerRegex) {
5894
6199
  }
5895
6200
  function collectStructuredReviewEntries(section, keys) {
5896
6201
  const lines = section.split("\n");
5897
- const escaped = keys.map((key) => escapeRegExp(key));
6202
+ const escaped = keys.map((key) => escapeRegExp2(key));
5898
6203
  const fieldRegex = new RegExp(
5899
6204
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*(.*)$`,
5900
6205
  "i"
@@ -6076,17 +6381,17 @@ function resolveLocalEvidencePathCandidates(rawValue, context) {
6076
6381
  if (!evidencePath) return [];
6077
6382
  if (/^https?:\/\//i.test(evidencePath)) return [];
6078
6383
  const candidates = /* @__PURE__ */ new Set();
6079
- if (path12.isAbsolute(evidencePath)) {
6080
- candidates.add(path12.resolve(evidencePath));
6384
+ if (path13.isAbsolute(evidencePath)) {
6385
+ candidates.add(path13.resolve(evidencePath));
6081
6386
  } else {
6082
- candidates.add(path12.resolve(context.featurePath, evidencePath));
6083
- candidates.add(path12.resolve(context.docsDir, evidencePath));
6084
- candidates.add(path12.resolve(path12.dirname(context.docsDir), evidencePath));
6387
+ candidates.add(path13.resolve(context.featurePath, evidencePath));
6388
+ candidates.add(path13.resolve(context.docsDir, evidencePath));
6389
+ candidates.add(path13.resolve(path13.dirname(context.docsDir), evidencePath));
6085
6390
  const normalizedEvidencePath = evidencePath.replace(/\\/g, "/");
6086
6391
  if (normalizedEvidencePath.startsWith("docs/")) {
6087
6392
  const withoutDocsPrefix = normalizedEvidencePath.slice("docs/".length);
6088
6393
  if (withoutDocsPrefix) {
6089
- candidates.add(path12.resolve(context.docsDir, withoutDocsPrefix));
6394
+ candidates.add(path13.resolve(context.docsDir, withoutDocsPrefix));
6090
6395
  }
6091
6396
  }
6092
6397
  }
@@ -6148,13 +6453,13 @@ function parsePrLink(value) {
6148
6453
  return trimmed;
6149
6454
  }
6150
6455
  function normalizeGitPath(value) {
6151
- return value.split(path12.sep).join("/");
6456
+ return value.split(path13.sep).join("/");
6152
6457
  }
6153
6458
  function resolveProjectStatusPaths(projectGitCwd, docsDir) {
6154
- const relativeDocsDir = path12.relative(projectGitCwd, docsDir);
6459
+ const relativeDocsDir = path13.relative(projectGitCwd, docsDir);
6155
6460
  if (!relativeDocsDir) return [];
6156
- if (path12.isAbsolute(relativeDocsDir)) return [];
6157
- if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path12.sep}`)) {
6461
+ if (path13.isAbsolute(relativeDocsDir)) return [];
6462
+ if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path13.sep}`)) {
6158
6463
  return [];
6159
6464
  }
6160
6465
  const normalizedDocsDir = normalizeGitPath(relativeDocsDir).replace(
@@ -6192,7 +6497,7 @@ function getExpectedWorktreeCandidates(projectGitCwd, issueNumber, slug, folderN
6192
6497
  const seen = /* @__PURE__ */ new Set();
6193
6498
  const out = [];
6194
6499
  for (const name of names) {
6195
- const candidate = path12.resolve(projectRoot, ".worktrees", name);
6500
+ const candidate = path13.resolve(projectRoot, ".worktrees", name);
6196
6501
  if (seen.has(candidate)) continue;
6197
6502
  seen.add(candidate);
6198
6503
  out.push(candidate);
@@ -6206,7 +6511,7 @@ function resolveExistingExpectedWorktreePath(projectGitCwd, issueNumber, slug, f
6206
6511
  slug,
6207
6512
  folderName
6208
6513
  )) {
6209
- if (!fs9.existsSync(candidate)) continue;
6514
+ if (!fs10.existsSync(candidate)) continue;
6210
6515
  return candidate;
6211
6516
  }
6212
6517
  return void 0;
@@ -6236,7 +6541,7 @@ function resolveFeatureWorktreePath(ctx, projectGitCwd, issueNumber, slug, folde
6236
6541
  slug,
6237
6542
  folderName
6238
6543
  )) {
6239
- if (!fs9.existsSync(candidate)) continue;
6544
+ if (!fs10.existsSync(candidate)) continue;
6240
6545
  const branchName = getCurrentBranch(ctx, candidate);
6241
6546
  if (!expectedBranchesSet.has(branchName)) continue;
6242
6547
  return {
@@ -6377,10 +6682,10 @@ async function resolveComponentStatusPaths(ctx, projectGitCwd, component, workfl
6377
6682
  const normalizedCandidates = uniqueNormalizedPaths(
6378
6683
  candidates.map((candidate) => {
6379
6684
  if (!candidate) return "";
6380
- if (!path12.isAbsolute(candidate)) return candidate;
6381
- const relative = path12.relative(projectGitCwd, candidate);
6685
+ if (!path13.isAbsolute(candidate)) return candidate;
6686
+ const relative = path13.relative(projectGitCwd, candidate);
6382
6687
  if (!relative) return "";
6383
- if (relative === ".." || relative.startsWith(`..${path12.sep}`))
6688
+ if (relative === ".." || relative.startsWith(`..${path13.sep}`))
6384
6689
  return "";
6385
6690
  return relative;
6386
6691
  }).filter(Boolean)
@@ -6394,7 +6699,7 @@ async function resolveComponentStatusPaths(ctx, projectGitCwd, component, workfl
6394
6699
  if (cached) return [...cached];
6395
6700
  const existing = [];
6396
6701
  for (const candidate of normalizedCandidates) {
6397
- if (await ctx.fs.pathExists(path12.join(projectGitCwd, candidate))) {
6702
+ if (await ctx.fs.pathExists(path13.join(projectGitCwd, candidate))) {
6398
6703
  existing.push(candidate);
6399
6704
  }
6400
6705
  }
@@ -6482,16 +6787,16 @@ async function parseFeature(ctx, featurePath, type, context, options) {
6482
6787
  const lang = options.lang;
6483
6788
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
6484
6789
  const prePrReviewPolicy = resolvePrePrReviewPolicy(options.workflow);
6485
- const folderName = path12.basename(featurePath);
6790
+ const folderName = path13.basename(featurePath);
6486
6791
  const match = folderName.match(/^(F\d+)-(.+)$/);
6487
6792
  const id = match?.[1];
6488
6793
  const slug = match?.[2] || folderName;
6489
- const specPath = path12.join(featurePath, "spec.md");
6490
- const planPath = path12.join(featurePath, "plan.md");
6491
- const tasksPath = path12.join(featurePath, "tasks.md");
6492
- const decisionsPath = path12.join(featurePath, "decisions.md");
6493
- const issueDocPath = path12.join(featurePath, "issue.md");
6494
- const prDocPath = path12.join(featurePath, "pr.md");
6794
+ const specPath = path13.join(featurePath, "spec.md");
6795
+ const planPath = path13.join(featurePath, "plan.md");
6796
+ const tasksPath = path13.join(featurePath, "tasks.md");
6797
+ const decisionsPath = path13.join(featurePath, "decisions.md");
6798
+ const issueDocPath = path13.join(featurePath, "issue.md");
6799
+ const prDocPath = path13.join(featurePath, "pr.md");
6495
6800
  let specStatus;
6496
6801
  let issueNumber;
6497
6802
  const specExists = await ctx.fs.pathExists(specPath);
@@ -6753,7 +7058,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
6753
7058
  } else if (workflowPolicy.requireWorktree && tasksSummary.total > tasksSummary.done && !projectInManagedWorktree) {
6754
7059
  warnings.push(tr(lang, "warnings", "workflowWorktreeRequired"));
6755
7060
  }
6756
- const relativeFeaturePathFromDocs = path12.relative(
7061
+ const relativeFeaturePathFromDocs = path13.relative(
6757
7062
  context.docsDir,
6758
7063
  featurePath
6759
7064
  );
@@ -7116,7 +7421,7 @@ async function parseFeature(ctx, featurePath, type, context, options) {
7116
7421
  async function listFeatureDirs(ctx, rootDir) {
7117
7422
  const dirs = await listSubdirectories(ctx.fs, rootDir);
7118
7423
  return dirs.filter(
7119
- (value) => path12.basename(value).trim().toLowerCase() !== "feature-base"
7424
+ (value) => path13.basename(value).trim().toLowerCase() !== "feature-base"
7120
7425
  );
7121
7426
  }
7122
7427
  function normalizeRelPath(value) {
@@ -7257,7 +7562,7 @@ async function scanFeatures(ctx) {
7257
7562
  if (config.projectType === "single") {
7258
7563
  const featureDirs = await listFeatureDirs(
7259
7564
  ctx,
7260
- path12.join(config.docsDir, "features")
7565
+ path13.join(config.docsDir, "features")
7261
7566
  );
7262
7567
  componentFeatureDirs.set("single", featureDirs);
7263
7568
  allFeatureDirs.push(...featureDirs);
@@ -7269,14 +7574,14 @@ async function scanFeatures(ctx) {
7269
7574
  for (const component of components) {
7270
7575
  const componentDirs = await listFeatureDirs(
7271
7576
  ctx,
7272
- path12.join(config.docsDir, "features", component)
7577
+ path13.join(config.docsDir, "features", component)
7273
7578
  );
7274
7579
  componentFeatureDirs.set(component, componentDirs);
7275
7580
  allFeatureDirs.push(...componentDirs);
7276
7581
  }
7277
7582
  }
7278
7583
  const relativeFeaturePaths = allFeatureDirs.map(
7279
- (dir) => normalizeRelPath(path12.relative(config.docsDir, dir))
7584
+ (dir) => normalizeRelPath(path13.relative(config.docsDir, dir))
7280
7585
  );
7281
7586
  const docsGitMeta = buildDocsFeatureGitMeta(
7282
7587
  ctx,
@@ -7293,7 +7598,7 @@ async function scanFeatures(ctx) {
7293
7598
  const parsed = await Promise.all(
7294
7599
  target.dirs.map(async (dir) => {
7295
7600
  const relativeFeaturePathFromDocs = normalizeRelPath(
7296
- path12.relative(config.docsDir, dir)
7601
+ path13.relative(config.docsDir, dir)
7297
7602
  );
7298
7603
  const docsMeta = docsGitMeta.get(relativeFeaturePathFromDocs);
7299
7604
  return parseFeature(
@@ -7345,8 +7650,8 @@ function statusCommand(program2) {
7345
7650
  const cliError = toCliError(error);
7346
7651
  const suggestions = getCliErrorSuggestions(cliError.code, lang);
7347
7652
  console.error(
7348
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
7349
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
7653
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
7654
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
7350
7655
  );
7351
7656
  printCliErrorSuggestions(suggestions, lang);
7352
7657
  process.exitCode = 1;
@@ -7363,13 +7668,13 @@ async function runStatus(options) {
7363
7668
  );
7364
7669
  }
7365
7670
  const { docsDir, projectType, projectName, lang } = ctx.config;
7366
- const featuresDir = path12.join(docsDir, "features");
7671
+ const featuresDir = path13.join(docsDir, "features");
7367
7672
  const scan = await scanFeatures(ctx);
7368
7673
  const features = [];
7369
7674
  const idMap = /* @__PURE__ */ new Map();
7370
7675
  for (const f of scan.features) {
7371
7676
  const id = f.id || "UNKNOWN";
7372
- const relPath = path12.relative(docsDir, f.path);
7677
+ const relPath = path13.relative(docsDir, f.path);
7373
7678
  if (!idMap.has(id)) idMap.set(id, []);
7374
7679
  idMap.get(id).push(relPath);
7375
7680
  if (!f.docs.specExists || !f.docs.tasksExists) continue;
@@ -7443,7 +7748,7 @@ async function runStatus(options) {
7443
7748
  return;
7444
7749
  }
7445
7750
  if (features.length === 0) {
7446
- console.log(chalk8.yellow(tr(lang, "cli", "status.noFeatures")));
7751
+ console.log(chalk9.yellow(tr(lang, "cli", "status.noFeatures")));
7447
7752
  return;
7448
7753
  }
7449
7754
  features.sort((a, b) => a.id.localeCompare(b.id));
@@ -7453,14 +7758,14 @@ async function runStatus(options) {
7453
7758
  console.log(header);
7454
7759
  console.log(separator);
7455
7760
  for (const f of features) {
7456
- const statusColor = f.status === "WORKFLOW_DONE" ? chalk8.green : f.status === "DONE" ? chalk8.cyan : f.status === "DOING" ? chalk8.yellow : chalk8.gray;
7761
+ const statusColor = f.status === "WORKFLOW_DONE" ? chalk9.green : f.status === "DONE" ? chalk9.cyan : f.status === "DOING" ? chalk9.yellow : chalk9.gray;
7457
7762
  console.log(
7458
7763
  `| ${f.id} | ${f.name} | ${f.repo} | ${f.issue} | ${statusColor(f.status)} | ${f.progress} | ${f.step} | ${f.substate} | ${f.path} |`
7459
7764
  );
7460
7765
  }
7461
7766
  console.log();
7462
7767
  if (options.write) {
7463
- const outputPath = path12.join(featuresDir, "status.md");
7768
+ const outputPath = path13.join(featuresDir, "status.md");
7464
7769
  const date = getLocalDateString();
7465
7770
  const content = [
7466
7771
  "# Feature Status",
@@ -7477,22 +7782,22 @@ async function runStatus(options) {
7477
7782
  ].join("\n");
7478
7783
  await ctx.fs.writeFile(outputPath, content, "utf-8");
7479
7784
  console.log(
7480
- chalk8.green(tr(lang, "cli", "status.wrote", { path: outputPath }))
7785
+ chalk9.green(tr(lang, "cli", "status.wrote", { path: outputPath }))
7481
7786
  );
7482
7787
  }
7483
7788
  }
7484
- function escapeRegExp2(value) {
7789
+ function escapeRegExp3(value) {
7485
7790
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7486
7791
  }
7487
7792
  async function getFeatureNameFromSpec(fsAdapter, featureDir, fallbackSlug, fallbackFolderName) {
7488
7793
  try {
7489
- const specPath = path12.join(featureDir, "spec.md");
7794
+ const specPath = path13.join(featureDir, "spec.md");
7490
7795
  if (!await fsAdapter.pathExists(specPath)) return fallbackSlug;
7491
7796
  const content = await fsAdapter.readFile(specPath, "utf-8");
7492
7797
  const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
7493
7798
  for (const key of keys) {
7494
7799
  const regex = new RegExp(
7495
- `^\\s*-\\s*\\*\\*${escapeRegExp2(key)}\\*\\*\\s*:\\s*(.*)$`,
7800
+ `^\\s*-\\s*\\*\\*${escapeRegExp3(key)}\\*\\*\\s*:\\s*(.*)$`,
7496
7801
  "m"
7497
7802
  );
7498
7803
  const match = content.match(regex);
@@ -7514,15 +7819,15 @@ function updateCommand(program2) {
7514
7819
  const config = await getConfig(process.cwd());
7515
7820
  const lang = config?.lang ?? DEFAULT_LANG;
7516
7821
  if (error instanceof Error && error.message === "canceled") {
7517
- console.log(chalk8.yellow(`
7822
+ console.log(chalk9.yellow(`
7518
7823
  ${tr(lang, "cli", "common.canceled")}`));
7519
7824
  return;
7520
7825
  }
7521
7826
  const cliError = toCliError(error);
7522
7827
  const suggestions = getCliErrorSuggestions(cliError.code, lang);
7523
7828
  console.error(
7524
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
7525
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
7829
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
7830
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
7526
7831
  );
7527
7832
  printCliErrorSuggestions(suggestions, lang);
7528
7833
  process.exitCode = 1;
@@ -7552,26 +7857,26 @@ async function runUpdate(options) {
7552
7857
  const updateAgentsMd = options.agentsMd || !hasExplicitSelection;
7553
7858
  const updateTemplates = options.templates || !hasExplicitSelection;
7554
7859
  const agentsMode = options.skills && !options.agents ? "skills" : "all";
7555
- console.log(chalk8.blue(tr(lang, "cli", "update.start")));
7556
- console.log(chalk8.gray(` - ${tr(lang, "cli", "update.langLabel")}: ${lang}`));
7860
+ console.log(chalk9.blue(tr(lang, "cli", "update.start")));
7861
+ console.log(chalk9.gray(` - ${tr(lang, "cli", "update.langLabel")}: ${lang}`));
7557
7862
  console.log(
7558
- chalk8.gray(` - ${tr(lang, "cli", "update.typeLabel")}: ${projectType}`)
7863
+ chalk9.gray(` - ${tr(lang, "cli", "update.typeLabel")}: ${projectType}`)
7559
7864
  );
7560
7865
  console.log();
7561
7866
  let updatedCount = 0;
7562
7867
  if (updateAgents) {
7563
7868
  if (agentsMode === "skills") {
7564
- console.log(chalk8.blue(tr(lang, "cli", "update.updatingSkills")));
7869
+ console.log(chalk9.blue(tr(lang, "cli", "update.updatingSkills")));
7565
7870
  console.log(
7566
- chalk8.gray(tr(lang, "cli", "update.engineManagedSkillsBuiltin"))
7871
+ chalk9.gray(tr(lang, "cli", "update.engineManagedSkillsBuiltin"))
7567
7872
  );
7568
- console.log(chalk8.green(` \u2705 ${tr(lang, "cli", "update.skillsUpdated")}`));
7873
+ console.log(chalk9.green(` \u2705 ${tr(lang, "cli", "update.skillsUpdated")}`));
7569
7874
  } else {
7570
- console.log(chalk8.blue(tr(lang, "cli", "update.updatingAgents")));
7875
+ console.log(chalk9.blue(tr(lang, "cli", "update.updatingAgents")));
7571
7876
  }
7572
7877
  if (agentsMode === "all") {
7573
- const commonAgentsBase = path12.join(templatesDir, lang, "common", "agents");
7574
- const targetAgentsBase = path12.join(docsDir, "agents");
7878
+ const commonAgentsBase = path13.join(templatesDir, lang, "common", "agents");
7879
+ const targetAgentsBase = path13.join(docsDir, "agents");
7575
7880
  const commonAgents = commonAgentsBase;
7576
7881
  const targetAgents = targetAgentsBase;
7577
7882
  const featurePath = projectType === "multi" ? "docs/features/{component}" : "docs/features";
@@ -7599,7 +7904,7 @@ async function runUpdate(options) {
7599
7904
  updatedCount += count;
7600
7905
  }
7601
7906
  console.log(
7602
- chalk8.green(
7907
+ chalk9.green(
7603
7908
  ` \u2705 ${tr(lang, "cli", "update.agentsUpdated")}`
7604
7909
  )
7605
7910
  );
@@ -7618,13 +7923,13 @@ async function runUpdate(options) {
7618
7923
  }
7619
7924
  }
7620
7925
  if (updateTemplates) {
7621
- console.log(chalk8.blue(tr(lang, "cli", "update.updatingFeatureBase")));
7622
- console.log(chalk8.gray(tr(lang, "cli", "update.engineManagedFeatureBaseBuiltin")));
7926
+ console.log(chalk9.blue(tr(lang, "cli", "update.updatingFeatureBase")));
7927
+ console.log(chalk9.gray(tr(lang, "cli", "update.engineManagedFeatureBaseBuiltin")));
7623
7928
  }
7624
7929
  const pruned = await pruneEngineManagedDocs(docsDir);
7625
7930
  if (pruned.length > 0) {
7626
7931
  console.log(
7627
- chalk8.gray(
7932
+ chalk9.gray(
7628
7933
  ` - ${tr(lang, "cli", "update.engineManagedPruned", {
7629
7934
  count: pruned.length
7630
7935
  })}`
@@ -7634,18 +7939,18 @@ async function runUpdate(options) {
7634
7939
  console.log();
7635
7940
  if (configBackfill.changed) {
7636
7941
  console.log(
7637
- chalk8.gray(
7942
+ chalk9.gray(
7638
7943
  ` - ${tr(lang, "cli", "update.fileUpdated", { file: ".lee-spec-kit.json" })}`
7639
7944
  )
7640
7945
  );
7641
7946
  console.log(
7642
- chalk8.gray(
7947
+ chalk9.gray(
7643
7948
  ` (${configBackfill.changedPaths.join(", ")})`
7644
7949
  )
7645
7950
  );
7646
7951
  }
7647
7952
  console.log(
7648
- chalk8.green(`\u2705 ${tr(lang, "cli", "update.updatedTotal", { count: updatedCount })}`)
7953
+ chalk9.green(`\u2705 ${tr(lang, "cli", "update.updatedTotal", { count: updatedCount })}`)
7649
7954
  );
7650
7955
  },
7651
7956
  { owner: "update" }
@@ -7669,21 +7974,21 @@ async function collectAgentsMdTargets(cwd, config) {
7669
7974
  const targets = /* @__PURE__ */ new Set();
7670
7975
  const docsRepo = config.docsRepo ?? "embedded";
7671
7976
  if (docsRepo === "embedded") {
7672
- const repoRoot = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || path12.resolve(config.docsDir, "..");
7673
- targets.add(path12.join(repoRoot, "AGENTS.md"));
7977
+ const repoRoot = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || path13.resolve(config.docsDir, "..");
7978
+ targets.add(path13.join(repoRoot, "AGENTS.md"));
7674
7979
  return [...targets];
7675
7980
  }
7676
- targets.add(path12.join(config.docsDir, "AGENTS.md"));
7981
+ targets.add(path13.join(config.docsDir, "AGENTS.md"));
7677
7982
  const baseDir = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || process.cwd();
7678
7983
  const rawRoots = typeof config.projectRoot === "string" ? [config.projectRoot] : config.projectRoot && typeof config.projectRoot === "object" ? Object.values(config.projectRoot) : [];
7679
7984
  for (const rawRoot of rawRoots) {
7680
7985
  const value = String(rawRoot || "").trim();
7681
7986
  if (!value) continue;
7682
- const resolved = path12.resolve(baseDir, value);
7987
+ const resolved = path13.resolve(baseDir, value);
7683
7988
  if (!await fs.pathExists(resolved)) continue;
7684
7989
  const stat = await fs.stat(resolved);
7685
7990
  if (!stat.isDirectory()) continue;
7686
- targets.add(path12.join(resolved, "AGENTS.md"));
7991
+ targets.add(path13.join(resolved, "AGENTS.md"));
7687
7992
  }
7688
7993
  return [...targets];
7689
7994
  }
@@ -7723,7 +8028,7 @@ function normalizeDecisionEnumList2(raw) {
7723
8028
  return [...deduped];
7724
8029
  }
7725
8030
  async function backfillMissingConfigDefaults(docsDir) {
7726
- const configPath = path12.join(docsDir, ".lee-spec-kit.json");
8031
+ const configPath = path13.join(docsDir, ".lee-spec-kit.json");
7727
8032
  if (!await fs.pathExists(configPath)) {
7728
8033
  return { changed: false, changedPaths: [] };
7729
8034
  }
@@ -7846,8 +8151,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
7846
8151
  const files = await fs.readdir(sourceDir);
7847
8152
  let updatedCount = 0;
7848
8153
  for (const file of files) {
7849
- const sourcePath = path12.join(sourceDir, file);
7850
- const targetPath = path12.join(targetDir, file);
8154
+ const sourcePath = path13.join(sourceDir, file);
8155
+ const targetPath = path13.join(targetDir, file);
7851
8156
  const stat = await fs.stat(sourcePath);
7852
8157
  if (stat.isFile()) {
7853
8158
  if (protectedFiles.has(file)) {
@@ -7865,7 +8170,7 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
7865
8170
  }
7866
8171
  if (!force) {
7867
8172
  console.log(
7868
- chalk8.yellow(
8173
+ chalk9.yellow(
7869
8174
  ` \u26A0\uFE0F ${file} - ${tr(lang, "cli", "update.changeDetected")}`
7870
8175
  )
7871
8176
  );
@@ -7875,7 +8180,7 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
7875
8180
  if (shouldUpdate) {
7876
8181
  await fs.writeFile(targetPath, sourceContent);
7877
8182
  console.log(
7878
- chalk8.gray(` \u{1F4C4} ${tr(lang, "cli", "update.fileUpdated", { file })}`)
8183
+ chalk9.gray(` \u{1F4C4} ${tr(lang, "cli", "update.fileUpdated", { file })}`)
7879
8184
  );
7880
8185
  updatedCount++;
7881
8186
  }
@@ -7930,7 +8235,7 @@ function extractPorcelainPaths(line) {
7930
8235
  function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
7931
8236
  const top = getGitTopLevel2(docsDir);
7932
8237
  if (!top) return null;
7933
- const rel = path12.relative(top, docsDir) || ".";
8238
+ const rel = path13.relative(top, docsDir) || ".";
7934
8239
  try {
7935
8240
  const output = execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
7936
8241
  cwd: top,
@@ -7942,7 +8247,7 @@ function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
7942
8247
  }
7943
8248
  const ignoredRelPaths = new Set(
7944
8249
  ignoredAbsPaths.map(
7945
- (absPath) => normalizeGitPath2(path12.relative(top, absPath) || ".")
8250
+ (absPath) => normalizeGitPath2(path13.relative(top, absPath) || ".")
7946
8251
  )
7947
8252
  );
7948
8253
  const filtered = output.split("\n").filter((line) => {
@@ -7980,7 +8285,7 @@ function configCommand(program2) {
7980
8285
  if (error instanceof Error && error.message === "canceled") {
7981
8286
  const config2 = await getConfig(process.cwd());
7982
8287
  const lang2 = config2?.lang ?? DEFAULT_LANG;
7983
- console.log(chalk8.yellow(`
8288
+ console.log(chalk9.yellow(`
7984
8289
  ${tr(lang2, "cli", "common.canceled")}`));
7985
8290
  return;
7986
8291
  }
@@ -7989,8 +8294,8 @@ ${tr(lang2, "cli", "common.canceled")}`));
7989
8294
  const cliError = toCliError(error);
7990
8295
  const suggestions = getCliErrorSuggestions(cliError.code, lang);
7991
8296
  console.error(
7992
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
7993
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
8297
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
8298
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
7994
8299
  );
7995
8300
  printCliErrorSuggestions(suggestions, lang);
7996
8301
  process.exitCode = 1;
@@ -8000,7 +8305,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
8000
8305
  }
8001
8306
  async function runConfig(options) {
8002
8307
  const cwd = process.cwd();
8003
- const targetCwd = options.dir ? path12.resolve(cwd, options.dir) : cwd;
8308
+ const targetCwd = options.dir ? path13.resolve(cwd, options.dir) : cwd;
8004
8309
  const config = await getConfig(targetCwd);
8005
8310
  if (!config) {
8006
8311
  throw createCliError(
@@ -8008,13 +8313,13 @@ async function runConfig(options) {
8008
8313
  tr(DEFAULT_LANG, "cli", "common.configNotFound")
8009
8314
  );
8010
8315
  }
8011
- const configPath = path12.join(config.docsDir, ".lee-spec-kit.json");
8316
+ const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
8012
8317
  if (!options.projectRoot) {
8013
8318
  console.log();
8014
- console.log(chalk8.blue(tr(config.lang, "cli", "config.currentTitle")));
8319
+ console.log(chalk9.blue(tr(config.lang, "cli", "config.currentTitle")));
8015
8320
  console.log();
8016
8321
  console.log(
8017
- chalk8.gray(
8322
+ chalk9.gray(
8018
8323
  ` ${tr(config.lang, "cli", "config.pathLabel")}: ${configPath}`
8019
8324
  )
8020
8325
  );
@@ -8031,7 +8336,7 @@ async function runConfig(options) {
8031
8336
  const configFile = await fs.readJson(configPath);
8032
8337
  if (configFile.docsRepo !== "standalone") {
8033
8338
  console.log(
8034
- chalk8.yellow(tr(config.lang, "cli", "config.projectRootStandaloneOnly"))
8339
+ chalk9.yellow(tr(config.lang, "cli", "config.projectRootStandaloneOnly"))
8035
8340
  );
8036
8341
  return;
8037
8342
  }
@@ -8081,7 +8386,7 @@ async function runConfig(options) {
8081
8386
  currentRoot[targetComponent] = projectRoot;
8082
8387
  configFile.projectRoot = currentRoot;
8083
8388
  console.log(
8084
- chalk8.green(
8389
+ chalk9.green(
8085
8390
  tr(config.lang, "cli", "config.projectRootSet", {
8086
8391
  repo: targetComponent.toUpperCase(),
8087
8392
  path: projectRoot
@@ -8097,7 +8402,7 @@ async function runConfig(options) {
8097
8402
  }
8098
8403
  configFile.projectRoot = projectRoot;
8099
8404
  console.log(
8100
- chalk8.green(
8405
+ chalk9.green(
8101
8406
  tr(config.lang, "cli", "config.projectRootSetSingle", {
8102
8407
  path: projectRoot
8103
8408
  })
@@ -8114,47 +8419,47 @@ var BUILTIN_DOC_DEFINITIONS = [
8114
8419
  {
8115
8420
  id: "agents",
8116
8421
  title: { ko: "\uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uADDC\uCE59", en: "Agent Operating Rules" },
8117
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "agents.md")
8422
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "agents.md")
8118
8423
  },
8119
8424
  {
8120
8425
  id: "git-workflow",
8121
8426
  title: { ko: "Git \uC6CC\uD06C\uD50C\uB85C\uC6B0", en: "Git Workflow" },
8122
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "git-workflow.md")
8427
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "git-workflow.md")
8123
8428
  },
8124
8429
  {
8125
8430
  id: "issue-doc",
8126
8431
  title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
8127
- relativePath: (_, lang) => path12.join(lang, "common", "features", "feature-base", "issue.md")
8432
+ relativePath: (_, lang) => path13.join(lang, "common", "features", "feature-base", "issue.md")
8128
8433
  },
8129
8434
  {
8130
8435
  id: "pr-doc",
8131
8436
  title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
8132
- relativePath: (_, lang) => path12.join(lang, "common", "features", "feature-base", "pr.md")
8437
+ relativePath: (_, lang) => path13.join(lang, "common", "features", "feature-base", "pr.md")
8133
8438
  },
8134
8439
  {
8135
8440
  id: "create-feature",
8136
8441
  title: { ko: "create-feature \uC2A4\uD0AC", en: "create-feature skill" },
8137
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "skills", "create-feature.md")
8442
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-feature.md")
8138
8443
  },
8139
8444
  {
8140
8445
  id: "execute-task",
8141
8446
  title: { ko: "execute-task \uC2A4\uD0AC", en: "execute-task skill" },
8142
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "skills", "execute-task.md")
8447
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "execute-task.md")
8143
8448
  },
8144
8449
  {
8145
8450
  id: "create-issue",
8146
8451
  title: { ko: "create-issue \uC2A4\uD0AC", en: "create-issue skill" },
8147
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "skills", "create-issue.md")
8452
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-issue.md")
8148
8453
  },
8149
8454
  {
8150
8455
  id: "create-pr",
8151
8456
  title: { ko: "create-pr \uC2A4\uD0AC", en: "create-pr skill" },
8152
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "skills", "create-pr.md")
8457
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "create-pr.md")
8153
8458
  },
8154
8459
  {
8155
8460
  id: "split-feature",
8156
8461
  title: { ko: "feature \uBD84\uD560 \uAC00\uC774\uB4DC", en: "feature split guide" },
8157
- relativePath: (_, lang) => path12.join(lang, "common", "agents", "skills", "split-feature.md")
8462
+ relativePath: (_, lang) => path13.join(lang, "common", "agents", "skills", "split-feature.md")
8158
8463
  }
8159
8464
  ];
8160
8465
  var DOC_FOLLOWUPS = {
@@ -8251,7 +8556,7 @@ function listBuiltinDocs(projectType, lang) {
8251
8556
  id: doc.id,
8252
8557
  title: doc.title[lang],
8253
8558
  relativePath,
8254
- absolutePath: path12.join(templatesDir, relativePath)
8559
+ absolutePath: path13.join(templatesDir, relativePath)
8255
8560
  };
8256
8561
  });
8257
8562
  }
@@ -8672,7 +8977,7 @@ function getActionExecutionMetadata(action) {
8672
8977
  return {
8673
8978
  handoffOnly: true,
8674
8979
  advancesWorkflow: false,
8675
- nextMainState: "pre_pr_review_running"
8980
+ nextMainState: "pre_pr_review_in_progress"
8676
8981
  };
8677
8982
  }
8678
8983
  return null;
@@ -8830,7 +9135,7 @@ function buildDelegatedActionContract(state) {
8830
9135
  const feature = state.matchedFeature;
8831
9136
  const substateId = feature?.currentSubstateId;
8832
9137
  if (!feature || !substateId) return null;
8833
- if (substateId === "pre_pr_review_run" || substateId === "pre_pr_review_running") {
9138
+ if (substateId === "pre_pr_review_run" || substateId === "pre_pr_review_in_progress") {
8834
9139
  return {
8835
9140
  required: true,
8836
9141
  mode: "command",
@@ -8839,8 +9144,8 @@ function buildDelegatedActionContract(state) {
8839
9144
  delegatedWorkRequired: true,
8840
9145
  handoffOnly: true,
8841
9146
  advancesWorkflow: false,
8842
- doNotReapproveSameLabel: substateId === "pre_pr_review_running",
8843
- nextMainState: "pre_pr_review_running",
9147
+ doNotReapproveSameLabel: substateId === "pre_pr_review_in_progress",
9148
+ nextMainState: "pre_pr_review_in_progress",
8844
9149
  reuseKey: `pre-pr:${feature.folderName}`,
8845
9150
  evidenceFile: "review-trace.json",
8846
9151
  nextStepRequirement: "generate_review_trace_then_record",
@@ -8851,7 +9156,7 @@ function buildDelegatedActionContract(state) {
8851
9156
  ),
8852
9157
  approve: buildPrePrRecordCommand(feature, "approve")
8853
9158
  },
8854
- guidance: substateId === "pre_pr_review_running" ? "A pre-PR review handoff is already prepared. Reuse or resume the delegated review, generate review-trace.json, then record the result with pre-pr-review. Do not re-approve the same label." : "After approval, spawn_agent first and hand off the delegated pre-PR review. Handoff-only execution only prepares the review session; continue the delegated review immediately after approval."
9159
+ guidance: substateId === "pre_pr_review_in_progress" ? "A pre-PR review is already in progress. Reuse or resume the delegated review, generate structured review evidence, then record the result with pre-pr-review. Do not re-approve the same label." : "After approval, spawn_agent first and hand off the delegated pre-PR review. Handoff-only execution only prepares the review session; continue the delegated review immediately after approval."
8855
9160
  };
8856
9161
  }
8857
9162
  if (substateId === "code_review_run" || substateId === "code_review_running") {
@@ -9083,12 +9388,12 @@ function printSuggestionOptions(lang, suggestionOptions) {
9083
9388
  if (suggestionOptions.length === 0) return;
9084
9389
  const finalPrompt = buildSuggestionFinalPrompt(lang, suggestionOptions);
9085
9390
  console.log(
9086
- chalk8.green(chalk8.bold(`\u{1F449} ${tr(lang, "cli", "context.suggestionHeader")}`))
9391
+ chalk9.green(chalk9.bold(`\u{1F449} ${tr(lang, "cli", "context.suggestionHeader")}`))
9087
9392
  );
9088
9393
  suggestionOptions.forEach((option) => {
9089
9394
  console.log(` ${option.label}: ${option.summary}`);
9090
9395
  console.log(
9091
- chalk8.gray(
9396
+ chalk9.gray(
9092
9397
  ` \u21B3 ${tr(lang, "cli", "context.suggestionCommandHint", {
9093
9398
  command: option.command
9094
9399
  })}`
@@ -9096,7 +9401,7 @@ function printSuggestionOptions(lang, suggestionOptions) {
9096
9401
  );
9097
9402
  });
9098
9403
  if (finalPrompt) {
9099
- console.log(chalk8.cyan(` \u21B3 ${finalPrompt}`));
9404
+ console.log(chalk9.cyan(` \u21B3 ${finalPrompt}`));
9100
9405
  }
9101
9406
  }
9102
9407
  function buildRequiredDocHints(actionOptions) {
@@ -9288,7 +9593,7 @@ function getApprovalSessionId() {
9288
9593
  function getApprovalTicketPaths(config) {
9289
9594
  return {
9290
9595
  runtimePath: getApprovalTicketStorePath(config.docsDir),
9291
- legacyPath: path12.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
9596
+ legacyPath: path13.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
9292
9597
  };
9293
9598
  }
9294
9599
  async function loadApprovalTicketStore(storePath) {
@@ -9302,7 +9607,7 @@ async function loadApprovalTicketStore(storePath) {
9302
9607
  }
9303
9608
  }
9304
9609
  async function saveApprovalTicketStore(storePath, payload) {
9305
- await fs.ensureDir(path12.dirname(storePath));
9610
+ await fs.ensureDir(path13.dirname(storePath));
9306
9611
  await fs.writeJson(storePath, payload, { spaces: 2 });
9307
9612
  }
9308
9613
  function pruneApprovalTickets(tickets, nowMs) {
@@ -9633,10 +9938,10 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9633
9938
  return;
9634
9939
  }
9635
9940
  console.log();
9636
- console.log(chalk8.green(`\u2705 Approved option: ${parsedLabel}`));
9637
- console.log(chalk8.gray(` - Action: ${freshSelected.detail}`));
9941
+ console.log(chalk9.green(`\u2705 Approved option: ${parsedLabel}`));
9942
+ console.log(chalk9.gray(` - Action: ${freshSelected.detail}`));
9638
9943
  if (userRequest) {
9639
- console.log(chalk8.gray(` - User request: ${userRequest}`));
9944
+ console.log(chalk9.gray(` - User request: ${userRequest}`));
9640
9945
  }
9641
9946
  if (selectedAction.type === "command") {
9642
9947
  const selectedComponent = selectionOptions.component || "";
@@ -9647,24 +9952,24 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9647
9952
  `--ticket ${ticket.token}`
9648
9953
  );
9649
9954
  console.log(
9650
- chalk8.gray(
9955
+ chalk9.gray(
9651
9956
  ` - Ticket: ${ticket.token} (expires: ${ticket.expiresAt})`
9652
9957
  )
9653
9958
  );
9654
9959
  } else {
9655
9960
  executeCommand = executeCommand.replace(" [--ticket <TICKET>]", "");
9656
9961
  }
9657
- console.log(chalk8.gray(` - Run with: ${executeCommand}`));
9962
+ console.log(chalk9.gray(` - Run with: ${executeCommand}`));
9658
9963
  if (executionMetadata?.handoffOnly && !executionMetadata.advancesWorkflow) {
9659
9964
  console.log(
9660
- chalk8.gray(
9965
+ chalk9.gray(
9661
9966
  " - This command prepares a handoff only; complete the delegated work and update workflow evidence before re-running context."
9662
9967
  )
9663
9968
  );
9664
9969
  }
9665
9970
  } else {
9666
9971
  console.log(
9667
- chalk8.gray(" - Instruction-only action (no command execution).")
9972
+ chalk9.gray(" - Instruction-only action (no command execution).")
9668
9973
  );
9669
9974
  }
9670
9975
  console.log();
@@ -9715,19 +10020,19 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9715
10020
  }
9716
10021
  console.log();
9717
10022
  console.log(
9718
- chalk8.yellow(`\u26A0\uFE0F Approved label ${parsedLabel} is instruction-only.`)
10023
+ chalk9.yellow(`\u26A0\uFE0F Approved label ${parsedLabel} is instruction-only.`)
9719
10024
  );
9720
10025
  if (userRequest) {
9721
- console.log(chalk8.gray(` User request: ${userRequest}`));
10026
+ console.log(chalk9.gray(` User request: ${userRequest}`));
9722
10027
  }
9723
- console.log(chalk8.gray(` ${selectedAction.message}`));
10028
+ console.log(chalk9.gray(` ${selectedAction.message}`));
9724
10029
  console.log();
9725
10030
  return;
9726
10031
  }
9727
10032
  if (!jsonMode) {
9728
10033
  console.log();
9729
- console.log(chalk8.blue(`\u25B6 Executing option ${parsedLabel}...`));
9730
- console.log(chalk8.gray(` ${selectedAction.cmd}`));
10034
+ console.log(chalk9.blue(`\u25B6 Executing option ${parsedLabel}...`));
10035
+ console.log(chalk9.gray(` ${selectedAction.cmd}`));
9731
10036
  console.log();
9732
10037
  }
9733
10038
  try {
@@ -9789,14 +10094,14 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9789
10094
  }
9790
10095
  if (executionMetadata?.handoffOnly && !executionMetadata.advancesWorkflow) {
9791
10096
  console.log(
9792
- chalk8.yellow(
10097
+ chalk9.yellow(
9793
10098
  "Prepared handoff only. Complete the delegated work and update workflow evidence before re-running context."
9794
10099
  )
9795
10100
  );
9796
10101
  console.log();
9797
10102
  return;
9798
10103
  }
9799
- console.log(chalk8.green(`\u2705 Executed option ${parsedLabel}.`));
10104
+ console.log(chalk9.green(`\u2705 Executed option ${parsedLabel}.`));
9800
10105
  console.log();
9801
10106
  } catch (error) {
9802
10107
  const message = error instanceof Error ? error.message : String(error);
@@ -9844,8 +10149,8 @@ function contextCommand(program2) {
9844
10149
  );
9845
10150
  } else {
9846
10151
  console.error(
9847
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
9848
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
10152
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
10153
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
9849
10154
  );
9850
10155
  printCliErrorSuggestions(suggestions, lang);
9851
10156
  }
@@ -10214,11 +10519,11 @@ async function runContext(featureName, options) {
10214
10519
  return;
10215
10520
  }
10216
10521
  console.log();
10217
- console.log(chalk8.bold(tr(lang, "cli", "context.header")));
10522
+ console.log(chalk9.bold(tr(lang, "cli", "context.header")));
10218
10523
  if (config.projectType === "single") {
10219
10524
  if (state.branches.project.single) {
10220
10525
  console.log(
10221
- chalk8.gray(
10526
+ chalk9.gray(
10222
10527
  ` (Detected from Project Branch: ${state.branches.project.single})`
10223
10528
  )
10224
10529
  );
@@ -10227,7 +10532,7 @@ async function runContext(featureName, options) {
10227
10532
  const branchName = state.branches.project[selectedComponent] || "";
10228
10533
  if (branchName) {
10229
10534
  console.log(
10230
- chalk8.gray(
10535
+ chalk9.gray(
10231
10536
  ` (Detected from Project Branch: ${selectedComponent.toUpperCase()} ${branchName})`
10232
10537
  )
10233
10538
  );
@@ -10236,37 +10541,37 @@ async function runContext(featureName, options) {
10236
10541
  const parts = Object.entries(state.branches.project).filter(([key, value]) => key !== "single" && !!value).map(([key, value]) => `${key.toUpperCase()} ${value}`);
10237
10542
  if (parts.length > 0) {
10238
10543
  console.log(
10239
- chalk8.gray(` (Detected from Project Branch: ${parts.join(" / ")})`)
10544
+ chalk9.gray(` (Detected from Project Branch: ${parts.join(" / ")})`)
10240
10545
  );
10241
10546
  }
10242
10547
  }
10243
10548
  if (config.docsRepo === "standalone" && state.branches.docs) {
10244
- console.log(chalk8.gray(` (Docs Branch: ${state.branches.docs})`));
10549
+ console.log(chalk9.gray(` (Docs Branch: ${state.branches.docs})`));
10245
10550
  }
10246
- console.log(chalk8.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
10551
+ console.log(chalk9.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
10247
10552
  console.log();
10248
10553
  if (state.features.length === 0) {
10249
- console.log(chalk8.yellow(tr(lang, "cli", "context.noActiveFeatures")));
10554
+ console.log(chalk9.yellow(tr(lang, "cli", "context.noActiveFeatures")));
10250
10555
  console.log();
10251
10556
  printSuggestionOptions(lang, suggestionOptions);
10252
10557
  console.log();
10253
10558
  return;
10254
10559
  }
10255
10560
  if (state.warnings.length > 0) {
10256
- console.log(chalk8.yellow(tr(lang, "cli", "context.envWarnings")));
10257
- state.warnings.forEach((w) => console.log(chalk8.yellow(` - ${w}`)));
10561
+ console.log(chalk9.yellow(tr(lang, "cli", "context.envWarnings")));
10562
+ state.warnings.forEach((w) => console.log(chalk9.yellow(` - ${w}`)));
10258
10563
  console.log();
10259
10564
  }
10260
10565
  if (state.targetFeatures.length === 0) {
10261
- console.log(chalk8.yellow(tr(lang, "cli", "context.noActiveFeatures")));
10566
+ console.log(chalk9.yellow(tr(lang, "cli", "context.noActiveFeatures")));
10262
10567
  if (state.status === "no_open") {
10263
10568
  console.log(
10264
- chalk8.gray(
10569
+ chalk9.gray(
10265
10570
  ` $ npx lee-spec-kit context --done # ${tr(lang, "cli", "context.tipShowDone")}`
10266
10571
  )
10267
10572
  );
10268
10573
  console.log(
10269
- chalk8.gray(
10574
+ chalk9.gray(
10270
10575
  ` $ npx lee-spec-kit context --all # ${tr(lang, "cli", "context.tipShowAll")}`
10271
10576
  )
10272
10577
  );
@@ -10279,7 +10584,7 @@ async function runContext(featureName, options) {
10279
10584
  if (state.targetFeatures.length > 1) {
10280
10585
  if (state.selectionMode === "open") {
10281
10586
  console.log(
10282
- chalk8.gray(
10587
+ chalk9.gray(
10283
10588
  ` ${tr(lang, "cli", "context.openFallbackSummary", {
10284
10589
  inProgress: state.inProgressFeatures.length,
10285
10590
  readyToClose: state.readyToCloseFeatures.length,
@@ -10291,7 +10596,7 @@ async function runContext(featureName, options) {
10291
10596
  }
10292
10597
  if (state.selectionMode === "open") {
10293
10598
  console.log(
10294
- chalk8.blue(
10599
+ chalk9.blue(
10295
10600
  `\u{1F539} ${tr(lang, "cli", "context.sectionInProgress")} (${state.inProgressFeatures.length})`
10296
10601
  )
10297
10602
  );
@@ -10303,14 +10608,14 @@ async function runContext(featureName, options) {
10303
10608
  workflowPolicy,
10304
10609
  prePrReviewPolicy
10305
10610
  );
10306
- const typeStr = config.projectType === "multi" ? chalk8.cyan(`(${f2.type})`) : "";
10611
+ const typeStr = config.projectType === "multi" ? chalk9.cyan(`(${f2.type})`) : "";
10307
10612
  console.log(
10308
- ` \u2022 ${chalk8.bold(f2.folderName)} ${typeStr} - ${chalk8.yellow(stepName2)}`
10613
+ ` \u2022 ${chalk9.bold(f2.folderName)} ${typeStr} - ${chalk9.yellow(stepName2)}`
10309
10614
  );
10310
10615
  });
10311
10616
  console.log();
10312
10617
  console.log(
10313
- chalk8.blue(
10618
+ chalk9.blue(
10314
10619
  `\u{1F538} ${tr(lang, "cli", "context.sectionReadyToClose")} (${state.readyToCloseFeatures.length})`
10315
10620
  )
10316
10621
  );
@@ -10322,14 +10627,14 @@ async function runContext(featureName, options) {
10322
10627
  workflowPolicy,
10323
10628
  prePrReviewPolicy
10324
10629
  );
10325
- const typeStr = config.projectType === "multi" ? chalk8.cyan(`(${f2.type})`) : "";
10630
+ const typeStr = config.projectType === "multi" ? chalk9.cyan(`(${f2.type})`) : "";
10326
10631
  console.log(
10327
- ` \u2022 ${chalk8.bold(f2.folderName)} ${typeStr} - ${chalk8.yellow(stepName2)}`
10632
+ ` \u2022 ${chalk9.bold(f2.folderName)} ${typeStr} - ${chalk9.yellow(stepName2)}`
10328
10633
  );
10329
10634
  });
10330
10635
  } else {
10331
10636
  const title = state.selectionMode === "all" ? `\u{1F539} ${state.targetFeatures.length} Features:` : state.selectionMode === "done" ? `\u{1F539} ${state.targetFeatures.length} Done Features:` : `\u{1F539} ${state.targetFeatures.length} Features Detected:`;
10332
- console.log(chalk8.blue(title));
10637
+ console.log(chalk9.blue(title));
10333
10638
  console.log();
10334
10639
  state.targetFeatures.forEach((f2) => {
10335
10640
  const stepName2 = getListLabel(
@@ -10339,24 +10644,24 @@ async function runContext(featureName, options) {
10339
10644
  workflowPolicy,
10340
10645
  prePrReviewPolicy
10341
10646
  );
10342
- const typeStr = config.projectType === "multi" ? chalk8.cyan(`(${f2.type})`) : "";
10647
+ const typeStr = config.projectType === "multi" ? chalk9.cyan(`(${f2.type})`) : "";
10343
10648
  console.log(
10344
- ` \u2022 ${chalk8.bold(f2.folderName)} ${typeStr} - ${chalk8.yellow(stepName2)}`
10649
+ ` \u2022 ${chalk9.bold(f2.folderName)} ${typeStr} - ${chalk9.yellow(stepName2)}`
10345
10650
  );
10346
10651
  });
10347
10652
  }
10348
10653
  console.log();
10349
- console.log(chalk8.gray(tr(lang, "cli", "context.tipDetails")));
10654
+ console.log(chalk9.gray(tr(lang, "cli", "context.tipDetails")));
10350
10655
  const selectorTip = config.projectType === "multi" ? selectedComponent ? ` $ npx lee-spec-kit context <slug|F001|F001-slug> --component ${selectedComponent}` : " $ npx lee-spec-kit context <slug|F001|F001-slug> [--component <component>]" : " $ npx lee-spec-kit context <slug|F001|F001-slug>";
10351
- console.log(chalk8.gray(selectorTip));
10656
+ console.log(chalk9.gray(selectorTip));
10352
10657
  if (state.selectionMode === "open") {
10353
10658
  console.log(
10354
- chalk8.gray(
10659
+ chalk9.gray(
10355
10660
  ` $ npx lee-spec-kit context --all # ${tr(lang, "cli", "context.tipShowAll")}`
10356
10661
  )
10357
10662
  );
10358
10663
  console.log(
10359
- chalk8.gray(
10664
+ chalk9.gray(
10360
10665
  ` $ npx lee-spec-kit context --done # ${tr(lang, "cli", "context.tipShowDone")}`
10361
10666
  )
10362
10667
  );
@@ -10368,47 +10673,47 @@ async function runContext(featureName, options) {
10368
10673
  }
10369
10674
  const f = state.targetFeatures[0];
10370
10675
  const stepName = stepsMap[f.currentStep] || "Unknown";
10371
- const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk8.yellow(tr(lang, "cli", "context.checkRequired")) : "";
10676
+ const checkTag = (requiresUserCheck) => requiresUserCheck ? chalk9.yellow(tr(lang, "cli", "context.checkRequired")) : "";
10372
10677
  const hasCheckAction = approvalRequired;
10373
10678
  console.log(
10374
- `\u{1F539} Feature: ${chalk8.bold(f.folderName)} ${config.projectType === "multi" ? chalk8.cyan(`(${f.type})`) : ""}`
10679
+ `\u{1F539} Feature: ${chalk9.bold(f.folderName)} ${config.projectType === "multi" ? chalk9.cyan(`(${f.type})`) : ""}`
10375
10680
  );
10376
10681
  console.log(
10377
- ` \u2022 Completion: ${f.completion.implementationDone ? chalk8.green("Implementation \u2705") : chalk8.gray("Implementation \u25EF")} / ${f.completion.workflowDone ? chalk8.green("Workflow \u2705") : chalk8.yellow("Workflow \u25EF")}`
10682
+ ` \u2022 Completion: ${f.completion.implementationDone ? chalk9.green("Implementation \u2705") : chalk9.gray("Implementation \u25EF")} / ${f.completion.workflowDone ? chalk9.green("Workflow \u2705") : chalk9.yellow("Workflow \u25EF")}`
10378
10683
  );
10379
10684
  if (f.issueNumber) {
10380
10685
  console.log(` \u2022 Issue: #${f.issueNumber}`);
10381
10686
  }
10382
- console.log(` \u2022 Path: ${path12.relative(cwd, f.path)}`);
10687
+ console.log(` \u2022 Path: ${path13.relative(cwd, f.path)}`);
10383
10688
  if (f.git.projectBranch) {
10384
10689
  console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
10385
10690
  }
10386
10691
  console.log();
10387
10692
  console.log(
10388
- `\u{1F539} Progress: ${chalk8.yellow(`Step ${f.currentStep}. ${stepName}`)}`
10693
+ `\u{1F539} Progress: ${chalk9.yellow(`Step ${f.currentStep}. ${stepName}`)}`
10389
10694
  );
10390
10695
  if (f.activeTask) {
10391
10696
  console.log(
10392
- ` \u2022 Active Task: ${chalk8.yellow(`[${f.activeTask.status}]`)} ${f.activeTask.title}`
10697
+ ` \u2022 Active Task: ${chalk9.yellow(`[${f.activeTask.status}]`)} ${f.activeTask.title}`
10393
10698
  );
10394
10699
  } else if (f.nextTodoTask && f.currentStep === 10) {
10395
10700
  console.log(
10396
- ` \u2022 Next TODO: ${chalk8.gray(`[${f.nextTodoTask.status}]`)} ${f.nextTodoTask.title}`
10701
+ ` \u2022 Next TODO: ${chalk9.gray(`[${f.nextTodoTask.status}]`)} ${f.nextTodoTask.title}`
10397
10702
  );
10398
10703
  }
10399
10704
  printChecklist(f, stepDefinitions);
10400
10705
  if (f.warnings.length > 0) {
10401
10706
  console.log();
10402
- console.log(chalk8.yellow("\u26A0\uFE0F Feature Warnings:"));
10403
- f.warnings.forEach((w) => console.log(chalk8.yellow(` - ${w}`)));
10707
+ console.log(chalk9.yellow("\u26A0\uFE0F Feature Warnings:"));
10708
+ f.warnings.forEach((w) => console.log(chalk9.yellow(` - ${w}`)));
10404
10709
  }
10405
10710
  console.log();
10406
- console.log(chalk8.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
10711
+ console.log(chalk9.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
10407
10712
  if (hasCheckAction) {
10408
- console.log(chalk8.gray(tr(lang, "cli", "context.checkPolicyHint")));
10713
+ console.log(chalk9.gray(tr(lang, "cli", "context.checkPolicyHint")));
10409
10714
  }
10410
10715
  if (!f.actions || f.actions.length === 0) {
10411
- console.log(`\u{1F449} Next Action: ${chalk8.green(chalk8.bold(f.nextAction))}`);
10716
+ console.log(`\u{1F449} Next Action: ${chalk9.green(chalk9.bold(f.nextAction))}`);
10412
10717
  console.log();
10413
10718
  return;
10414
10719
  }
@@ -10421,7 +10726,7 @@ async function runContext(featureName, options) {
10421
10726
  f.currentSubstateOwner
10422
10727
  );
10423
10728
  const showOptionLabels = hasCheckAction;
10424
- console.log(chalk8.green(chalk8.bold("\u{1F449} Next Options (Atomic):")));
10729
+ console.log(chalk9.green(chalk9.bold("\u{1F449} Next Options (Atomic):")));
10425
10730
  let hasDocsCommand = false;
10426
10731
  actionOptions.forEach((option) => {
10427
10732
  const requiresCheck = option.action.requiresUserCheck;
@@ -10434,26 +10739,26 @@ async function runContext(featureName, options) {
10434
10739
  });
10435
10740
  if (hasDocsCommand) {
10436
10741
  console.log(
10437
- chalk8.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`)
10742
+ chalk9.gray(` \u21B3 ${tr(lang, "cli", "context.tipDocsCommitRules")}`)
10438
10743
  );
10439
10744
  }
10440
10745
  if (hasCommandOption && longRunningDelegation.shouldDelegate) {
10441
10746
  console.log(
10442
- chalk8.gray(` \u21B3 ${tr(lang, "cli", "context.subAgentOrchestrationHint")}`)
10747
+ chalk9.gray(` \u21B3 ${tr(lang, "cli", "context.subAgentOrchestrationHint")}`)
10443
10748
  );
10444
10749
  }
10445
10750
  if (hasCheckAction) {
10446
10751
  console.log(
10447
- chalk8.gray(` \u21B3 ${tr(lang, "cli", "context.actionOptionHint")}`)
10752
+ chalk9.gray(` \u21B3 ${tr(lang, "cli", "context.actionOptionHint")}`)
10448
10753
  );
10449
10754
  console.log(
10450
- chalk8.gray(` \u21B3 ${tr(lang, "cli", "context.actionExplainHint")}`)
10755
+ chalk9.gray(` \u21B3 ${tr(lang, "cli", "context.actionExplainHint")}`)
10451
10756
  );
10452
10757
  }
10453
10758
  if (requiredDocs.length > 0) {
10454
10759
  for (const requiredDoc of requiredDocs) {
10455
10760
  console.log(
10456
- chalk8.gray(
10761
+ chalk9.gray(
10457
10762
  ` \u21B3 ${tr(lang, "cli", "context.readBuiltinDocFirst", {
10458
10763
  command: requiredDoc.command
10459
10764
  })}`
@@ -10462,9 +10767,9 @@ async function runContext(featureName, options) {
10462
10767
  }
10463
10768
  }
10464
10769
  if (autoRunPlan.available) {
10465
- console.log(chalk8.gray(` \u21B3 ${autoRunPlan.summary}`));
10770
+ console.log(chalk9.gray(` \u21B3 ${autoRunPlan.summary}`));
10466
10771
  console.log(
10467
- chalk8.gray(
10772
+ chalk9.gray(
10468
10773
  ` \u21B3 ${tr(lang, "cli", "context.autoRunCommandHint", {
10469
10774
  command: autoRunPlan.command
10470
10775
  })}`
@@ -10484,16 +10789,16 @@ async function runContext(featureName, options) {
10484
10789
  selectedComponent,
10485
10790
  true
10486
10791
  );
10487
- console.log(chalk8.cyan(` \u21B3 ${finalApprovalPrompt}`));
10792
+ console.log(chalk9.cyan(` \u21B3 ${finalApprovalPrompt}`));
10488
10793
  console.log(
10489
- chalk8.gray(
10794
+ chalk9.gray(
10490
10795
  ` \u21B3 ${tr(lang, "cli", "context.finalLabelCommandHint", {
10491
10796
  command: approveCommand
10492
10797
  })}`
10493
10798
  )
10494
10799
  );
10495
10800
  console.log(
10496
- chalk8.gray(
10801
+ chalk9.gray(
10497
10802
  ` \u21B3 ${tr(lang, "cli", "context.finalTicketCommandHint", {
10498
10803
  command: executeCommand
10499
10804
  })}`
@@ -10507,8 +10812,8 @@ function printChecklist(f, stepDefinitions) {
10507
10812
  checklistSteps.forEach((definition) => {
10508
10813
  const done = definition.checklist.done(f);
10509
10814
  const detail = definition.checklist.detail?.(f) ?? "";
10510
- const mark = done ? chalk8.green("\u2705") : chalk8.gray("\u25EF");
10511
- const label = definition.step === f.currentStep ? chalk8.bold(definition.name) : definition.name;
10815
+ const mark = done ? chalk9.green("\u2705") : chalk9.gray("\u25EF");
10816
+ const label = definition.step === f.currentStep ? chalk9.bold(definition.name) : definition.name;
10512
10817
  console.log(` ${mark} ${definition.step}. ${label} ${detail}`);
10513
10818
  });
10514
10819
  }
@@ -10531,7 +10836,7 @@ function extractTitleAfterId(line, id) {
10531
10836
  return cleaned ? cleaned : void 0;
10532
10837
  }
10533
10838
  async function scanPrdRequirements(fsAdapter, docsDir) {
10534
- const prdDir = path12.join(docsDir, "prd");
10839
+ const prdDir = path13.join(docsDir, "prd");
10535
10840
  const files = await walkFiles(fsAdapter, prdDir, {
10536
10841
  extensions: [".md"],
10537
10842
  ignoreDirs: [".git", "node_modules", "dist", "tmp"]
@@ -10539,7 +10844,7 @@ async function scanPrdRequirements(fsAdapter, docsDir) {
10539
10844
  const definitions = /* @__PURE__ */ new Map();
10540
10845
  const duplicates = [];
10541
10846
  for (const filePath of files) {
10542
- if (path12.basename(filePath).toLowerCase() === "readme.md") {
10847
+ if (path13.basename(filePath).toLowerCase() === "readme.md") {
10543
10848
  continue;
10544
10849
  }
10545
10850
  let content = "";
@@ -10548,7 +10853,7 @@ async function scanPrdRequirements(fsAdapter, docsDir) {
10548
10853
  } catch {
10549
10854
  continue;
10550
10855
  }
10551
- const relFile = normalizeRelPath2(path12.relative(docsDir, filePath));
10856
+ const relFile = normalizeRelPath2(path13.relative(docsDir, filePath));
10552
10857
  const lines = content.split(/\r?\n/);
10553
10858
  let inCodeBlock = false;
10554
10859
  for (let i = 0; i < lines.length; i += 1) {
@@ -10623,7 +10928,7 @@ var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
10623
10928
  ]);
10624
10929
  function formatPath(cwd, p) {
10625
10930
  if (!p) return "";
10626
- return path12.isAbsolute(p) ? path12.relative(cwd, p) : p;
10931
+ return path13.isAbsolute(p) ? path13.relative(cwd, p) : p;
10627
10932
  }
10628
10933
  function detectPlaceholders(content) {
10629
10934
  const patterns = [
@@ -10782,7 +11087,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
10782
11087
  const placeholderContext = {
10783
11088
  projectName: config.projectName,
10784
11089
  featureName: f.slug,
10785
- featurePath: f.docs.featurePathFromDocs || path12.relative(config.docsDir, f.path),
11090
+ featurePath: f.docs.featurePathFromDocs || path13.relative(config.docsDir, f.path),
10786
11091
  repoType: f.type,
10787
11092
  featureNumber
10788
11093
  };
@@ -10792,7 +11097,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
10792
11097
  "tasks.md"
10793
11098
  ];
10794
11099
  for (const file of files) {
10795
- const fullPath = path12.join(f.path, file);
11100
+ const fullPath = path13.join(f.path, file);
10796
11101
  if (!await fs.pathExists(fullPath)) continue;
10797
11102
  const original = await fs.readFile(fullPath, "utf-8");
10798
11103
  let next = original;
@@ -10845,7 +11150,7 @@ async function checkDocsStructure(config, cwd) {
10845
11150
  const issues = [];
10846
11151
  const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
10847
11152
  for (const dir of requiredDirs) {
10848
- const p = path12.join(config.docsDir, dir);
11153
+ const p = path13.join(config.docsDir, dir);
10849
11154
  if (!await fs.pathExists(p)) {
10850
11155
  issues.push({
10851
11156
  level: "error",
@@ -10857,7 +11162,7 @@ async function checkDocsStructure(config, cwd) {
10857
11162
  });
10858
11163
  }
10859
11164
  }
10860
- const configPath = path12.join(config.docsDir, ".lee-spec-kit.json");
11165
+ const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
10861
11166
  if (!await fs.pathExists(configPath)) {
10862
11167
  issues.push({
10863
11168
  level: "warn",
@@ -10885,7 +11190,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10885
11190
  }
10886
11191
  const idMap = /* @__PURE__ */ new Map();
10887
11192
  for (const f of features) {
10888
- const rel = f.docs.featurePathFromDocs || path12.relative(config.docsDir, f.path);
11193
+ const rel = f.docs.featurePathFromDocs || path13.relative(config.docsDir, f.path);
10889
11194
  const id = f.id || "UNKNOWN";
10890
11195
  if (!idMap.has(id)) idMap.set(id, []);
10891
11196
  idMap.get(id).push(rel);
@@ -10893,7 +11198,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10893
11198
  if (!isInitialTemplateState) {
10894
11199
  const featureDocs = ["spec.md", "plan.md", "tasks.md"];
10895
11200
  for (const file of featureDocs) {
10896
- const p = path12.join(f.path, file);
11201
+ const p = path13.join(f.path, file);
10897
11202
  if (!await fs.pathExists(p)) continue;
10898
11203
  const content = await fs.readFile(p, "utf-8");
10899
11204
  const placeholders = detectPlaceholders(content);
@@ -10908,7 +11213,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10908
11213
  });
10909
11214
  }
10910
11215
  if (decisionsPlaceholderMode !== "off") {
10911
- const decisionsPath = path12.join(f.path, "decisions.md");
11216
+ const decisionsPath = path13.join(f.path, "decisions.md");
10912
11217
  if (await fs.pathExists(decisionsPath)) {
10913
11218
  const content = await fs.readFile(decisionsPath, "utf-8");
10914
11219
  const placeholders = detectPlaceholders(content);
@@ -10937,7 +11242,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10937
11242
  level: "warn",
10938
11243
  code: "spec_status_unset",
10939
11244
  message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
10940
- path: formatPath(cwd, path12.join(f.path, "spec.md"))
11245
+ path: formatPath(cwd, path13.join(f.path, "spec.md"))
10941
11246
  });
10942
11247
  }
10943
11248
  if (f.docs.planExists && !f.planStatus && !isInitialTemplateState) {
@@ -10945,7 +11250,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10945
11250
  level: "warn",
10946
11251
  code: "plan_status_unset",
10947
11252
  message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
10948
- path: formatPath(cwd, path12.join(f.path, "plan.md"))
11253
+ path: formatPath(cwd, path13.join(f.path, "plan.md"))
10949
11254
  });
10950
11255
  }
10951
11256
  if (f.docs.tasksExists && f.tasks.total === 0 && !isInitialTemplateState) {
@@ -10953,11 +11258,11 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10953
11258
  level: "warn",
10954
11259
  code: "tasks_empty",
10955
11260
  message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
10956
- path: formatPath(cwd, path12.join(f.path, "tasks.md"))
11261
+ path: formatPath(cwd, path13.join(f.path, "tasks.md"))
10957
11262
  });
10958
11263
  }
10959
11264
  if (f.docs.tasksExists) {
10960
- const tasksPath = path12.join(f.path, "tasks.md");
11265
+ const tasksPath = path13.join(f.path, "tasks.md");
10961
11266
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
10962
11267
  const unknownPrdTags = [...new Set(
10963
11268
  parseTaskLines(tasksContent).flatMap((task) => task.tags).filter((tag) => isPrdRequirementId(tag)).map((tag) => tag.trim().toUpperCase()).filter((tag) => !prdDefinitions.has(tag))
@@ -10979,7 +11284,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10979
11284
  level: "warn",
10980
11285
  code: "tasks_doc_status_missing",
10981
11286
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
10982
- path: formatPath(cwd, path12.join(f.path, "tasks.md"))
11287
+ path: formatPath(cwd, path13.join(f.path, "tasks.md"))
10983
11288
  });
10984
11289
  }
10985
11290
  if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus && !isInitialTemplateState) {
@@ -10987,7 +11292,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
10987
11292
  level: "warn",
10988
11293
  code: "tasks_doc_status_unset",
10989
11294
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
10990
- path: formatPath(cwd, path12.join(f.path, "tasks.md"))
11295
+ path: formatPath(cwd, path13.join(f.path, "tasks.md"))
10991
11296
  });
10992
11297
  }
10993
11298
  }
@@ -11011,7 +11316,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
11011
11316
  level: "warn",
11012
11317
  code: "missing_feature_id",
11013
11318
  message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
11014
- path: formatPath(cwd, path12.join(config.docsDir, p))
11319
+ path: formatPath(cwd, path13.join(config.docsDir, p))
11015
11320
  });
11016
11321
  }
11017
11322
  return issues;
@@ -11141,25 +11446,25 @@ function doctorCommand(program2) {
11141
11446
  return;
11142
11447
  }
11143
11448
  console.log();
11144
- console.log(chalk8.bold(tr(lang, "cli", "doctor.title")));
11145
- console.log(chalk8.gray(`- Docs: ${path12.relative(cwd, docsDir)}`));
11146
- console.log(chalk8.gray(`- Type: ${projectType}`));
11147
- console.log(chalk8.gray(`- Lang: ${lang}`));
11449
+ console.log(chalk9.bold(tr(lang, "cli", "doctor.title")));
11450
+ console.log(chalk9.gray(`- Docs: ${path13.relative(cwd, docsDir)}`));
11451
+ console.log(chalk9.gray(`- Type: ${projectType}`));
11452
+ console.log(chalk9.gray(`- Lang: ${lang}`));
11148
11453
  console.log();
11149
11454
  if (warnings.length > 0) {
11150
- console.log(chalk8.yellow(tr(lang, "cli", "doctor.envWarnings")));
11151
- warnings.forEach((w) => console.log(chalk8.yellow(` - ${w}`)));
11455
+ console.log(chalk9.yellow(tr(lang, "cli", "doctor.envWarnings")));
11456
+ warnings.forEach((w) => console.log(chalk9.yellow(` - ${w}`)));
11152
11457
  console.log();
11153
11458
  }
11154
11459
  if (fixResult) {
11155
11460
  const label = fixResult.dryRun ? "\u{1F9EA} Doctor Fix (dry-run)" : "\u{1F6E0}\uFE0F Doctor Fix";
11156
11461
  console.log(
11157
- chalk8.blue(`${label}: ${fixResult.changedFiles} file(s)`)
11462
+ chalk9.blue(`${label}: ${fixResult.changedFiles} file(s)`)
11158
11463
  );
11159
11464
  if (fixResult.changedFiles > 0) {
11160
11465
  fixResult.entries.forEach(
11161
11466
  (entry) => console.log(
11162
- chalk8.gray(` - ${entry.path}: ${entry.changes.join(", ")}`)
11467
+ chalk9.gray(` - ${entry.path}: ${entry.changes.join(", ")}`)
11163
11468
  )
11164
11469
  );
11165
11470
  }
@@ -11169,51 +11474,51 @@ function doctorCommand(program2) {
11169
11474
  const warns = issues.filter((i) => i.level === "warn");
11170
11475
  const infos = issues.filter((i) => i.level === "info");
11171
11476
  if (!hasIssues && infos.length === 0) {
11172
- console.log(chalk8.green(tr(lang, "cli", "doctor.noIssues")));
11477
+ console.log(chalk9.green(tr(lang, "cli", "doctor.noIssues")));
11173
11478
  console.log();
11174
11479
  return;
11175
11480
  }
11176
11481
  if (!hasIssues && infos.length > 0) {
11177
- console.log(chalk8.green(tr(lang, "cli", "doctor.noIssues")));
11482
+ console.log(chalk9.green(tr(lang, "cli", "doctor.noIssues")));
11178
11483
  console.log();
11179
11484
  }
11180
11485
  if (errors.length > 0) {
11181
11486
  console.log(
11182
- chalk8.red(
11487
+ chalk9.red(
11183
11488
  `\u274C ${tr(lang, "cli", "doctor.errorsTitle")} (${errors.length})`
11184
11489
  )
11185
11490
  );
11186
11491
  errors.forEach(
11187
11492
  (i) => console.log(
11188
- chalk8.red(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11493
+ chalk9.red(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11189
11494
  )
11190
11495
  );
11191
11496
  console.log();
11192
11497
  }
11193
11498
  if (warns.length > 0) {
11194
11499
  console.log(
11195
- chalk8.yellow(
11500
+ chalk9.yellow(
11196
11501
  `\u26A0\uFE0F ${tr(lang, "cli", "doctor.warningsTitle")} (${warns.length})`
11197
11502
  )
11198
11503
  );
11199
11504
  warns.forEach(
11200
11505
  (i) => console.log(
11201
- chalk8.yellow(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11506
+ chalk9.yellow(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11202
11507
  )
11203
11508
  );
11204
11509
  console.log();
11205
11510
  }
11206
11511
  if (infos.length > 0) {
11207
- console.log(chalk8.blue(`\u2139\uFE0F Info (${infos.length})`));
11512
+ console.log(chalk9.blue(`\u2139\uFE0F Info (${infos.length})`));
11208
11513
  infos.forEach(
11209
11514
  (i) => console.log(
11210
- chalk8.blue(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11515
+ chalk9.blue(` - ${i.message}${i.path ? ` (${i.path})` : ""}`)
11211
11516
  )
11212
11517
  );
11213
11518
  console.log();
11214
11519
  }
11215
11520
  console.log(
11216
- chalk8.gray(
11521
+ chalk9.gray(
11217
11522
  tr(lang, "cli", "doctor.tipJson", {
11218
11523
  strictFlag: options.strict ? " --strict" : ""
11219
11524
  })
@@ -11242,8 +11547,8 @@ function doctorCommand(program2) {
11242
11547
  );
11243
11548
  } else {
11244
11549
  console.error(
11245
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
11246
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
11550
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
11551
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
11247
11552
  );
11248
11553
  printCliErrorSuggestions(suggestions, lang);
11249
11554
  }
@@ -11272,8 +11577,8 @@ function viewCommand(program2) {
11272
11577
  );
11273
11578
  } else {
11274
11579
  console.error(
11275
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
11276
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
11580
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
11581
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
11277
11582
  );
11278
11583
  printCliErrorSuggestions(suggestions, lang);
11279
11584
  }
@@ -11322,49 +11627,49 @@ async function runView(featureName, options) {
11322
11627
  return;
11323
11628
  }
11324
11629
  console.log();
11325
- console.log(chalk8.bold("\u{1F4CA} Workflow View"));
11326
- console.log(chalk8.gray(`- Docs: ${path12.relative(cwd, config.docsDir)}`));
11630
+ console.log(chalk9.bold("\u{1F4CA} Workflow View"));
11631
+ console.log(chalk9.gray(`- Docs: ${path13.relative(cwd, config.docsDir)}`));
11327
11632
  console.log(
11328
- chalk8.gray(
11633
+ chalk9.gray(
11329
11634
  `- Features: ${state.features.length} (open ${state.openFeatures.length} / done ${state.doneFeatures.length})`
11330
11635
  )
11331
11636
  );
11332
11637
  console.log(
11333
- chalk8.gray(
11638
+ chalk9.gray(
11334
11639
  `- In Progress: ${state.inProgressFeatures.length}, Ready To Close: ${state.readyToCloseFeatures.length}`
11335
11640
  )
11336
11641
  );
11337
11642
  if (state.warnings.length > 0) {
11338
11643
  console.log();
11339
- console.log(chalk8.yellow("\u26A0\uFE0F Environment warnings:"));
11644
+ console.log(chalk9.yellow("\u26A0\uFE0F Environment warnings:"));
11340
11645
  for (const warning of state.warnings) {
11341
- console.log(chalk8.yellow(` - ${warning}`));
11646
+ console.log(chalk9.yellow(` - ${warning}`));
11342
11647
  }
11343
11648
  }
11344
11649
  if (state.features.length === 0) {
11345
11650
  console.log();
11346
- console.log(chalk8.yellow("No features found."));
11347
- console.log(chalk8.gray("Try: npx lee-spec-kit feature <name>"));
11651
+ console.log(chalk9.yellow("No features found."));
11652
+ console.log(chalk9.gray("Try: npx lee-spec-kit feature <name>"));
11348
11653
  console.log();
11349
11654
  return;
11350
11655
  }
11351
11656
  if (!state.matchedFeature) {
11352
11657
  console.log();
11353
11658
  console.log(
11354
- chalk8.blue(`Selection: ${state.status} (${toReasonCode(state.status)})`)
11659
+ chalk9.blue(`Selection: ${state.status} (${toReasonCode(state.status)})`)
11355
11660
  );
11356
11661
  const rows = state.targetFeatures.length > 0 ? state.targetFeatures : state.features;
11357
11662
  for (const f2 of rows) {
11358
- const statusText = f2.completion.workflowDone ? chalk8.green("WORKFLOW_DONE") : f2.completion.implementationDone ? chalk8.cyan("DONE") : chalk8.yellow("IN_PROGRESS");
11663
+ const statusText = f2.completion.workflowDone ? chalk9.green("WORKFLOW_DONE") : f2.completion.implementationDone ? chalk9.cyan("DONE") : chalk9.yellow("IN_PROGRESS");
11359
11664
  const substateText = f2.currentSubstateId ? `${f2.currentSubstateId} (${f2.currentSubstateOwner ?? "-"} / ${f2.currentSubstatePhase ?? "-"})` : "-";
11360
11665
  console.log(
11361
11666
  `- ${f2.folderName} (${f2.tasks.done}/${f2.tasks.total}) ${statusText} step:${f2.currentStep} substate:${substateText}`
11362
11667
  );
11363
- console.log(chalk8.gray(` next: ${f2.nextAction}`));
11668
+ console.log(chalk9.gray(` next: ${f2.nextAction}`));
11364
11669
  }
11365
11670
  console.log();
11366
11671
  const selectorTip = config.projectType === "multi" ? selectedComponent ? `Tip: npx lee-spec-kit view <slug|F001|F001-slug> --component ${selectedComponent}` : "Tip: npx lee-spec-kit view <slug|F001|F001-slug> [--component <component>]" : "Tip: npx lee-spec-kit view <slug|F001|F001-slug>";
11367
- console.log(chalk8.gray(selectorTip));
11672
+ console.log(chalk9.gray(selectorTip));
11368
11673
  console.log();
11369
11674
  return;
11370
11675
  }
@@ -11372,7 +11677,7 @@ async function runView(featureName, options) {
11372
11677
  const completion = `${f.tasks.done}/${f.tasks.total}`;
11373
11678
  const stateLabel = f.completion.workflowDone ? "WORKFLOW_DONE" : f.completion.implementationDone ? "DONE" : "IN_PROGRESS";
11374
11679
  console.log();
11375
- console.log(chalk8.blue(`Feature: ${chalk8.bold(f.folderName)}`));
11680
+ console.log(chalk9.blue(`Feature: ${chalk9.bold(f.folderName)}`));
11376
11681
  console.log(`- State: ${stateLabel}`);
11377
11682
  console.log(`- Progress: ${completion}`);
11378
11683
  console.log(`- Step: ${f.currentStep}`);
@@ -11383,14 +11688,14 @@ async function runView(featureName, options) {
11383
11688
  console.log(`- Next: ${nextSummary}`);
11384
11689
  if (state.actionOptions.length > 0) {
11385
11690
  console.log();
11386
- console.log(chalk8.green("Atomic options:"));
11691
+ console.log(chalk9.green("Atomic options:"));
11387
11692
  for (const option of state.actionOptions) {
11388
11693
  const lang = config.lang ?? DEFAULT_LANG;
11389
11694
  const requiresCheck = option.action.requiresUserCheck ? tr(lang, "cli", "context.checkRequired") : "";
11390
11695
  console.log(` ${option.label}. ${requiresCheck}${option.detail}`);
11391
11696
  }
11392
11697
  console.log(
11393
- chalk8.gray(
11698
+ chalk9.gray(
11394
11699
  `Approve with: npx lee-spec-kit context ${f.folderName} --approve <LABEL>`
11395
11700
  )
11396
11701
  );
@@ -11408,13 +11713,13 @@ function normalizeRunId(raw) {
11408
11713
  return value;
11409
11714
  }
11410
11715
  function getFlowRunBaseDir(cwd) {
11411
- return path12.join(getRuntimeStateDir(cwd), "flow-runs");
11716
+ return path13.join(getRuntimeStateDir(cwd), "flow-runs");
11412
11717
  }
11413
11718
  function getFlowRunPath(cwd, runId) {
11414
- return path12.join(getFlowRunBaseDir(cwd), `${runId}.json`);
11719
+ return path13.join(getFlowRunBaseDir(cwd), `${runId}.json`);
11415
11720
  }
11416
11721
  function getFlowRunLockPath(cwd, runId) {
11417
- return path12.join(getRuntimeStateDir(cwd), "locks", `flow-run-${runId}.lock`);
11722
+ return path13.join(getRuntimeStateDir(cwd), "locks", `flow-run-${runId}.lock`);
11418
11723
  }
11419
11724
  async function readFlowRunRecordUnsafe(cwd, runId) {
11420
11725
  const normalized = normalizeRunId(runId);
@@ -11440,7 +11745,7 @@ async function readFlowRunRecordUnsafe(cwd, runId) {
11440
11745
  }
11441
11746
  async function writeFlowRunRecord(cwd, record) {
11442
11747
  const filePath = getFlowRunPath(cwd, record.runId);
11443
- await fs.ensureDir(path12.dirname(filePath));
11748
+ await fs.ensureDir(path13.dirname(filePath));
11444
11749
  await fs.writeJson(filePath, record, { spaces: 2 });
11445
11750
  }
11446
11751
  async function createFlowRunRecord(cwd, input) {
@@ -12235,8 +12540,8 @@ function flowCommand(program2) {
12235
12540
  );
12236
12541
  } else {
12237
12542
  console.error(
12238
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
12239
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
12543
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
12544
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
12240
12545
  );
12241
12546
  printCliErrorSuggestions(suggestions, lang);
12242
12547
  }
@@ -12555,16 +12860,16 @@ async function runFlow(featureName, options) {
12555
12860
  return;
12556
12861
  }
12557
12862
  console.log();
12558
- console.log(chalk8.bold("\u{1F501} Flow Summary"));
12863
+ console.log(chalk9.bold("\u{1F501} Flow Summary"));
12559
12864
  console.log(
12560
- chalk8.gray(
12865
+ chalk9.gray(
12561
12866
  `- Before: ${before.status} (${toReasonCode(before.status)}) / After: ${after.status} (${toReasonCode(after.status)})`
12562
12867
  )
12563
12868
  );
12564
12869
  if (approvalResult && typeof approvalResult === "object") {
12565
12870
  const result = approvalResult;
12566
12871
  console.log(
12567
- chalk8.gray(
12872
+ chalk9.gray(
12568
12873
  `- Approval: ${result.status ?? "unknown"} (${result.reasonCode ?? "-"})`
12569
12874
  )
12570
12875
  );
@@ -12572,18 +12877,18 @@ async function runFlow(featureName, options) {
12572
12877
  if (autoRun) {
12573
12878
  const presetSuffix = autoRun.preset ? `, preset ${autoRun.preset}` : "";
12574
12879
  console.log(
12575
- chalk8.gray(
12880
+ chalk9.gray(
12576
12881
  `- Auto: ${autoRun.status} (${autoRun.reasonCode}), iterations ${autoRun.iterations}, executions ${autoRun.executions.length}${presetSuffix}`
12577
12882
  )
12578
12883
  );
12579
- console.log(chalk8.gray(`- Auto resume: ${autoRun.resume.flowCommand}`));
12884
+ console.log(chalk9.gray(`- Auto resume: ${autoRun.resume.flowCommand}`));
12580
12885
  if (autoRun.run) {
12581
12886
  console.log(
12582
- chalk8.gray(
12887
+ chalk9.gray(
12583
12888
  `- Auto run: ${autoRun.run.mode} ${autoRun.run.runId} (${autoRun.run.status})`
12584
12889
  )
12585
12890
  );
12586
- console.log(chalk8.gray(`- Resume with: ${autoRun.run.resumeCommand}`));
12891
+ console.log(chalk9.gray(`- Resume with: ${autoRun.run.resumeCommand}`));
12587
12892
  }
12588
12893
  }
12589
12894
  const agentOrchestration = buildAgentOrchestrationPolicy2(
@@ -12591,21 +12896,21 @@ async function runFlow(featureName, options) {
12591
12896
  resolvedFeatureName || null
12592
12897
  );
12593
12898
  console.log(
12594
- chalk8.gray(
12899
+ chalk9.gray(
12595
12900
  `- Orchestration: ${agentOrchestration.mode}, prefer substate-owner delegation and fall back to legacy long-running categories`
12596
12901
  )
12597
12902
  );
12598
12903
  const statusCounts = statusReport.counts;
12599
12904
  const doctorCounts = doctorReport.counts;
12600
- console.log(chalk8.gray(`- Status features: ${statusCounts?.features ?? 0}`));
12905
+ console.log(chalk9.gray(`- Status features: ${statusCounts?.features ?? 0}`));
12601
12906
  console.log(
12602
- chalk8.gray(
12907
+ chalk9.gray(
12603
12908
  `- Doctor issues: ${doctorCounts?.issues ?? 0} (errors ${doctorCounts?.errors ?? 0}, warnings ${doctorCounts?.warnings ?? 0})`
12604
12909
  )
12605
12910
  );
12606
12911
  if (strictChecks) {
12607
- const strictLabel = strictChecks.statusStrictOk && strictChecks.doctorStrictOk ? chalk8.green("PASS") : chalk8.red("FAIL");
12608
- console.log(chalk8.gray(`- Strict checks: ${strictLabel}`));
12912
+ const strictLabel = strictChecks.statusStrictOk && strictChecks.doctorStrictOk ? chalk9.green("PASS") : chalk9.red("FAIL");
12913
+ console.log(chalk9.gray(`- Strict checks: ${strictLabel}`));
12609
12914
  }
12610
12915
  console.log();
12611
12916
  if (autoRun?.status === "gate_reached" && autoRun.gate?.userFacingLines?.length) {
@@ -12613,7 +12918,7 @@ async function runFlow(featureName, options) {
12613
12918
  console.log(line);
12614
12919
  }
12615
12920
  console.log(
12616
- chalk8.gray(
12921
+ chalk9.gray(
12617
12922
  "Auto gate reached. Reply with one of the labels shown above (example: A OK)."
12618
12923
  )
12619
12924
  );
@@ -12624,15 +12929,15 @@ async function runFlow(featureName, options) {
12624
12929
  }
12625
12930
  if (after.matchedFeature) {
12626
12931
  console.log(
12627
- chalk8.blue(
12932
+ chalk9.blue(
12628
12933
  `Next: npx lee-spec-kit context ${after.matchedFeature.folderName}${componentHint}`
12629
12934
  )
12630
12935
  );
12631
12936
  } else {
12632
- console.log(chalk8.blue(`Next: npx lee-spec-kit context${componentHint}`));
12937
+ console.log(chalk9.blue(`Next: npx lee-spec-kit context${componentHint}`));
12633
12938
  }
12634
12939
  console.log(
12635
- chalk8.gray(
12940
+ chalk9.gray(
12636
12941
  "Tip: add --approve <LABEL> [--execute] to run the selected atomic action."
12637
12942
  )
12638
12943
  );
@@ -12751,27 +13056,27 @@ function tg(lang, key, vars = {}) {
12751
13056
  function detectGithubCliLangSync(cwd) {
12752
13057
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
12753
13058
  const startDirs = [
12754
- explicitDocsDir ? path12.resolve(explicitDocsDir) : "",
12755
- path12.resolve(cwd)
13059
+ explicitDocsDir ? path13.resolve(explicitDocsDir) : "",
13060
+ path13.resolve(cwd)
12756
13061
  ].filter(Boolean);
12757
13062
  const scanOrder = [];
12758
13063
  const seen = /* @__PURE__ */ new Set();
12759
13064
  for (const start of startDirs) {
12760
13065
  let current = start;
12761
13066
  while (true) {
12762
- const abs = path12.resolve(current);
13067
+ const abs = path13.resolve(current);
12763
13068
  if (!seen.has(abs)) {
12764
13069
  scanOrder.push(abs);
12765
13070
  seen.add(abs);
12766
13071
  }
12767
- const parent = path12.dirname(abs);
13072
+ const parent = path13.dirname(abs);
12768
13073
  if (parent === abs) break;
12769
13074
  current = parent;
12770
13075
  }
12771
13076
  }
12772
13077
  for (const base of scanOrder) {
12773
- for (const docsDir of [path12.join(base, "docs"), base]) {
12774
- const configPath = path12.join(docsDir, ".lee-spec-kit.json");
13078
+ for (const docsDir of [path13.join(base, "docs"), base]) {
13079
+ const configPath = path13.join(docsDir, ".lee-spec-kit.json");
12775
13080
  if (fs.existsSync(configPath)) {
12776
13081
  try {
12777
13082
  const parsed = fs.readJsonSync(configPath);
@@ -12780,11 +13085,11 @@ function detectGithubCliLangSync(cwd) {
12780
13085
  } catch {
12781
13086
  }
12782
13087
  }
12783
- const agentsPath = path12.join(docsDir, "agents");
12784
- const featuresPath = path12.join(docsDir, "features");
13088
+ const agentsPath = path13.join(docsDir, "agents");
13089
+ const featuresPath = path13.join(docsDir, "features");
12785
13090
  if (!fs.existsSync(agentsPath) || !fs.existsSync(featuresPath)) continue;
12786
13091
  for (const probe of ["custom.md", "constitution.md", "agents.md"]) {
12787
- const file = path12.join(agentsPath, probe);
13092
+ const file = path13.join(agentsPath, probe);
12788
13093
  if (!fs.existsSync(file)) continue;
12789
13094
  try {
12790
13095
  const content = fs.readFileSync(file, "utf-8");
@@ -12804,13 +13109,13 @@ function parseLabels(raw, lang) {
12804
13109
  }
12805
13110
  return [...new Set(labels)];
12806
13111
  }
12807
- function escapeRegExp3(value) {
13112
+ function escapeRegExp4(value) {
12808
13113
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12809
13114
  }
12810
13115
  function extractDraftMetadataValue(content, keys) {
12811
13116
  for (const key of keys) {
12812
13117
  const re = new RegExp(
12813
- `^\\s*-\\s*\\*\\*${escapeRegExp3(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
13118
+ `^\\s*-\\s*\\*\\*${escapeRegExp4(key)}\\*\\*\\s*:\\s*(.*?)\\s*$`,
12814
13119
  "mi"
12815
13120
  );
12816
13121
  const match = content.match(re);
@@ -12889,7 +13194,7 @@ async function prepareGithubBody(params) {
12889
13194
  };
12890
13195
  }
12891
13196
  }
12892
- await fs.ensureDir(path12.dirname(defaultBodyFile));
13197
+ await fs.ensureDir(path13.dirname(defaultBodyFile));
12893
13198
  await fs.writeFile(defaultBodyFile, generatedBody, "utf-8");
12894
13199
  return {
12895
13200
  body: generatedBody,
@@ -12929,7 +13234,7 @@ function ensureSections(body, sections, kind, lang) {
12929
13234
  };
12930
13235
  const hasMetadataField = (field) => {
12931
13236
  const re = new RegExp(
12932
- `^\\s*-\\s*\\*\\*${escapeRegExp3(field)}\\*\\*\\s*:`,
13237
+ `^\\s*-\\s*\\*\\*${escapeRegExp4(field)}\\*\\*\\s*:`,
12933
13238
  "m"
12934
13239
  );
12935
13240
  return re.test(body);
@@ -12959,7 +13264,7 @@ function ensureSections(body, sections, kind, lang) {
12959
13264
  }
12960
13265
  function ensureDocsExist(docsDir, relativePaths, lang) {
12961
13266
  const missing = relativePaths.filter(
12962
- (relativePath) => !fs.existsSync(path12.join(docsDir, relativePath))
13267
+ (relativePath) => !fs.existsSync(path13.join(docsDir, relativePath))
12963
13268
  );
12964
13269
  if (missing.length > 0) {
12965
13270
  throw createCliError(
@@ -12969,18 +13274,18 @@ function ensureDocsExist(docsDir, relativePaths, lang) {
12969
13274
  }
12970
13275
  }
12971
13276
  function buildDefaultBodyFileName(kind, docsDir, component) {
12972
- const key = `${path12.resolve(docsDir)}::${component.trim().toLowerCase()}`;
13277
+ const key = `${path13.resolve(docsDir)}::${component.trim().toLowerCase()}`;
12973
13278
  const digest = createHash("sha1").update(key).digest("hex").slice(0, 12);
12974
13279
  return `lee-spec-kit.${digest}.${kind}.md`;
12975
13280
  }
12976
13281
  function toBodyFilePath(raw, kind, docsDir, component, lang) {
12977
- const selected = raw?.trim() || path12.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
13282
+ const selected = raw?.trim() || path13.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
12978
13283
  assertValid(
12979
13284
  validatePathWithLang(selected, lang),
12980
13285
  `github.${kind}.bodyFile`,
12981
13286
  lang
12982
13287
  );
12983
- return path12.resolve(selected);
13288
+ return path13.resolve(selected);
12984
13289
  }
12985
13290
  function toProjectRootDocsPath(relativePathFromDocs) {
12986
13291
  const normalized = relativePathFromDocs.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -13817,7 +14122,7 @@ function stripMarkdownCodeContexts(body) {
13817
14122
  function hasIssueClosingKeyword(body, issueNumber) {
13818
14123
  if (!issueNumber) return false;
13819
14124
  const cleaned = stripMarkdownCodeContexts(body);
13820
- const issue = escapeRegExp3(issueNumber);
14125
+ const issue = escapeRegExp4(issueNumber);
13821
14126
  const closeKeywordRegex = new RegExp(
13822
14127
  `\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\b\\s*(?:[a-zA-Z0-9_.-]+\\/)?#\\s*${issue}\\b`,
13823
14128
  "i"
@@ -14035,7 +14340,7 @@ function ensureCleanWorktree(cwd, lang) {
14035
14340
  function commitAndPushPaths(cwd, absPaths, message, lang, options) {
14036
14341
  const uniqueRelativePaths = [
14037
14342
  ...new Set(
14038
- absPaths.filter((absPath) => !!absPath && fs.existsSync(absPath)).map((absPath) => path12.relative(cwd, absPath) || absPath)
14343
+ absPaths.filter((absPath) => !!absPath && fs.existsSync(absPath)).map((absPath) => path13.relative(cwd, absPath) || absPath)
14039
14344
  )
14040
14345
  ];
14041
14346
  if (uniqueRelativePaths.length === 0) return;
@@ -14231,15 +14536,15 @@ function githubCommand(program2) {
14231
14536
  config.lang
14232
14537
  );
14233
14538
  const specContent = await fs.readFile(
14234
- path12.join(config.docsDir, paths.specPath),
14539
+ path13.join(config.docsDir, paths.specPath),
14235
14540
  "utf-8"
14236
14541
  );
14237
14542
  const planContent = await fs.readFile(
14238
- path12.join(config.docsDir, paths.planPath),
14543
+ path13.join(config.docsDir, paths.planPath),
14239
14544
  "utf-8"
14240
14545
  );
14241
14546
  const tasksContent = await fs.readFile(
14242
- path12.join(config.docsDir, paths.tasksPath),
14547
+ path13.join(config.docsDir, paths.tasksPath),
14243
14548
  "utf-8"
14244
14549
  );
14245
14550
  const overview = resolveOverviewFromSpec(
@@ -14282,7 +14587,7 @@ function githubCommand(program2) {
14282
14587
  create: options.create,
14283
14588
  explicitBodyFile,
14284
14589
  defaultBodyFile,
14285
- workflowDraftPath: path12.join(config.docsDir, paths.issuePath),
14590
+ workflowDraftPath: path13.join(config.docsDir, paths.issuePath),
14286
14591
  generatedBody,
14287
14592
  requiredSections: getRequiredIssueSections(config.lang),
14288
14593
  kindLabel: tg(config.lang, "kindIssue"),
@@ -14298,7 +14603,7 @@ function githubCommand(program2) {
14298
14603
  `${feature.type}-issue-sanitized`,
14299
14604
  config.lang
14300
14605
  );
14301
- await fs.ensureDir(path12.dirname(sanitizedBodyFile));
14606
+ await fs.ensureDir(path13.dirname(sanitizedBodyFile));
14302
14607
  await fs.writeFile(sanitizedBodyFile, body, "utf-8");
14303
14608
  bodyFile = sanitizedBodyFile;
14304
14609
  }
@@ -14347,12 +14652,12 @@ function githubCommand(program2) {
14347
14652
  const syncedIssueNumber = extractIssueNumberFromUrl(issueUrl);
14348
14653
  if (syncedIssueNumber) {
14349
14654
  const synced = syncTasksIssueMetadata(
14350
- path12.join(config.docsDir, paths.tasksPath),
14655
+ path13.join(config.docsDir, paths.tasksPath),
14351
14656
  syncedIssueNumber,
14352
14657
  config.lang
14353
14658
  );
14354
14659
  const draftSynced = syncIssueDraftMetadata(
14355
- path12.join(config.docsDir, paths.issuePath),
14660
+ path13.join(config.docsDir, paths.issuePath),
14356
14661
  syncedIssueNumber
14357
14662
  );
14358
14663
  syncChanged = synced.changed || draftSynced.changed;
@@ -14380,31 +14685,31 @@ function githubCommand(program2) {
14380
14685
  return;
14381
14686
  }
14382
14687
  console.log();
14383
- console.log(chalk8.bold(tg(config.lang, "issueHeader")));
14688
+ console.log(chalk9.bold(tg(config.lang, "issueHeader")));
14384
14689
  console.log(
14385
- chalk8.gray(
14690
+ chalk9.gray(
14386
14691
  `- ${tg(config.lang, "labelFeature")}: ${feature.folderName}`
14387
14692
  )
14388
14693
  );
14389
14694
  console.log(
14390
- chalk8.gray(
14695
+ chalk9.gray(
14391
14696
  `- ${tg(config.lang, "labelBodyFile")}: ${bodyFile}`
14392
14697
  )
14393
14698
  );
14394
14699
  console.log(
14395
- chalk8.gray(
14700
+ chalk9.gray(
14396
14701
  `- ${tg(config.lang, "labelLabels")}: ${labels.join(", ")}`
14397
14702
  )
14398
14703
  );
14399
14704
  if (issueUrl) {
14400
14705
  console.log(
14401
- chalk8.green(
14706
+ chalk9.green(
14402
14707
  tg(config.lang, "issueCreated", { url: issueUrl })
14403
14708
  )
14404
14709
  );
14405
14710
  } else {
14406
14711
  console.log(
14407
- chalk8.blue(tg(config.lang, "issueTemplateGenerated"))
14712
+ chalk9.blue(tg(config.lang, "issueTemplateGenerated"))
14408
14713
  );
14409
14714
  }
14410
14715
  console.log();
@@ -14423,8 +14728,8 @@ function githubCommand(program2) {
14423
14728
  );
14424
14729
  } else {
14425
14730
  console.error(
14426
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
14427
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
14731
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
14732
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
14428
14733
  );
14429
14734
  printCliErrorSuggestions(suggestions, lang);
14430
14735
  }
@@ -14463,13 +14768,13 @@ function githubCommand(program2) {
14463
14768
  config.lang
14464
14769
  );
14465
14770
  const specContent = await fs.readFile(
14466
- path12.join(config.docsDir, paths.specPath),
14771
+ path13.join(config.docsDir, paths.specPath),
14467
14772
  "utf-8"
14468
14773
  );
14469
- const planPath = path12.join(config.docsDir, paths.planPath);
14774
+ const planPath = path13.join(config.docsDir, paths.planPath);
14470
14775
  const planContent = await fs.pathExists(planPath) ? await fs.readFile(planPath, "utf-8") : "";
14471
14776
  const tasksContent = await fs.readFile(
14472
- path12.join(config.docsDir, paths.tasksPath),
14777
+ path13.join(config.docsDir, paths.tasksPath),
14473
14778
  "utf-8"
14474
14779
  );
14475
14780
  const overview = resolveOverviewFromSpec(
@@ -14517,7 +14822,7 @@ function githubCommand(program2) {
14517
14822
  create: options.create,
14518
14823
  explicitBodyFile,
14519
14824
  defaultBodyFile,
14520
- workflowDraftPath: path12.join(config.docsDir, paths.prPath),
14825
+ workflowDraftPath: path13.join(config.docsDir, paths.prPath),
14521
14826
  generatedBody,
14522
14827
  requiredSections: getRequiredPrSections(config.lang),
14523
14828
  kindLabel: tg(config.lang, "kindPr"),
@@ -14535,7 +14840,7 @@ function githubCommand(program2) {
14535
14840
  `${feature.type}-pr-sanitized`,
14536
14841
  config.lang
14537
14842
  );
14538
- await fs.ensureDir(path12.dirname(sanitizedBodyFile));
14843
+ await fs.ensureDir(path13.dirname(sanitizedBodyFile));
14539
14844
  await fs.writeFile(sanitizedBodyFile, body, "utf-8");
14540
14845
  bodyFile = sanitizedBodyFile;
14541
14846
  }
@@ -14563,7 +14868,7 @@ function githubCommand(program2) {
14563
14868
  if (preparedBody.source === "generated") {
14564
14869
  await fs.writeFile(bodyFile, body, "utf-8");
14565
14870
  } else {
14566
- await fs.ensureDir(path12.dirname(fallbackBodyFile));
14871
+ await fs.ensureDir(path13.dirname(fallbackBodyFile));
14567
14872
  await fs.writeFile(fallbackBodyFile, body, "utf-8");
14568
14873
  bodyFile = fallbackBodyFile;
14569
14874
  }
@@ -14624,13 +14929,13 @@ function githubCommand(program2) {
14624
14929
  }
14625
14930
  if (prUrl && options.syncTasks !== false) {
14626
14931
  const syncedTasks = syncTasksPrMetadata(
14627
- path12.join(config.docsDir, paths.tasksPath),
14932
+ path13.join(config.docsDir, paths.tasksPath),
14628
14933
  prUrl,
14629
14934
  "Review",
14630
14935
  config.lang
14631
14936
  );
14632
14937
  const syncedDraft = syncPrDraftMetadata(
14633
- path12.join(config.docsDir, paths.prPath),
14938
+ path13.join(config.docsDir, paths.prPath),
14634
14939
  prUrl,
14635
14940
  "Review"
14636
14941
  );
@@ -14671,13 +14976,13 @@ function githubCommand(program2) {
14671
14976
  mergeAlreadyMerged = merged.alreadyMerged;
14672
14977
  if (prUrl && options.syncTasks !== false) {
14673
14978
  const mergedTasksSync = syncTasksPrMetadata(
14674
- path12.join(config.docsDir, paths.tasksPath),
14979
+ path13.join(config.docsDir, paths.tasksPath),
14675
14980
  prUrl,
14676
14981
  "Approved",
14677
14982
  config.lang
14678
14983
  );
14679
14984
  const mergedDraftSync = syncPrDraftMetadata(
14680
- path12.join(config.docsDir, paths.prPath),
14985
+ path13.join(config.docsDir, paths.prPath),
14681
14986
  prUrl,
14682
14987
  "Approved"
14683
14988
  );
@@ -14761,35 +15066,35 @@ function githubCommand(program2) {
14761
15066
  return;
14762
15067
  }
14763
15068
  console.log();
14764
- console.log(chalk8.bold(tg(config.lang, "prHeader")));
15069
+ console.log(chalk9.bold(tg(config.lang, "prHeader")));
14765
15070
  console.log(
14766
- chalk8.gray(
15071
+ chalk9.gray(
14767
15072
  `- ${tg(config.lang, "labelFeature")}: ${feature.folderName}`
14768
15073
  )
14769
15074
  );
14770
15075
  console.log(
14771
- chalk8.gray(
15076
+ chalk9.gray(
14772
15077
  `- ${tg(config.lang, "labelBodyFile")}: ${bodyFile}`
14773
15078
  )
14774
15079
  );
14775
15080
  console.log(
14776
- chalk8.gray(
15081
+ chalk9.gray(
14777
15082
  `- ${tg(config.lang, "labelLabels")}: ${labels.join(", ")}`
14778
15083
  )
14779
15084
  );
14780
15085
  if (prUrl) {
14781
15086
  console.log(
14782
- chalk8.gray(`- ${tg(config.lang, "labelPr")}: ${prUrl}`)
15087
+ chalk9.gray(`- ${tg(config.lang, "labelPr")}: ${prUrl}`)
14783
15088
  );
14784
15089
  }
14785
15090
  if (syncChanged) {
14786
15091
  console.log(
14787
- chalk8.green(tg(config.lang, "prTasksSynced"))
15092
+ chalk9.green(tg(config.lang, "prTasksSynced"))
14788
15093
  );
14789
15094
  }
14790
15095
  if (options.merge) {
14791
15096
  console.log(
14792
- chalk8.green(
15097
+ chalk9.green(
14793
15098
  tg(config.lang, "prMerged", {
14794
15099
  attempts: mergedAttempts ?? 1
14795
15100
  })
@@ -14797,15 +15102,15 @@ function githubCommand(program2) {
14797
15102
  );
14798
15103
  if (mergeAlreadyMerged) {
14799
15104
  console.log(
14800
- chalk8.yellow(tg(config.lang, "prAlreadyMergedNotice"))
15105
+ chalk9.yellow(tg(config.lang, "prAlreadyMergedNotice"))
14801
15106
  );
14802
15107
  }
14803
15108
  for (const warning of postMergeWarnings) {
14804
- console.log(chalk8.yellow(`\u26A0\uFE0F ${warning}`));
15109
+ console.log(chalk9.yellow(`\u26A0\uFE0F ${warning}`));
14805
15110
  }
14806
15111
  } else if (!options.create) {
14807
15112
  console.log(
14808
- chalk8.blue(tg(config.lang, "prTemplateGenerated"))
15113
+ chalk9.blue(tg(config.lang, "prTemplateGenerated"))
14809
15114
  );
14810
15115
  }
14811
15116
  console.log();
@@ -14824,8 +15129,8 @@ function githubCommand(program2) {
14824
15129
  );
14825
15130
  } else {
14826
15131
  console.error(
14827
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
14828
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
15132
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
15133
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
14829
15134
  );
14830
15135
  printCliErrorSuggestions(suggestions, lang);
14831
15136
  }
@@ -14883,10 +15188,10 @@ function docsCommand(program2) {
14883
15188
  return;
14884
15189
  }
14885
15190
  console.log();
14886
- console.log(chalk8.bold(tr(config.lang, "cli", "docs.listHeader")));
15191
+ console.log(chalk9.bold(tr(config.lang, "cli", "docs.listHeader")));
14887
15192
  for (const doc of docsList) {
14888
15193
  console.log(`- ${doc.id}: ${doc.title}`);
14889
- console.log(chalk8.gray(` ${doc.command}`));
15194
+ console.log(chalk9.gray(` ${doc.command}`));
14890
15195
  }
14891
15196
  console.log();
14892
15197
  } catch (error) {
@@ -14905,8 +15210,8 @@ function docsCommand(program2) {
14905
15210
  );
14906
15211
  } else {
14907
15212
  console.error(
14908
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
14909
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
15213
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
15214
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
14910
15215
  );
14911
15216
  printCliErrorSuggestions(suggestions, lang);
14912
15217
  }
@@ -14948,25 +15253,25 @@ function docsCommand(program2) {
14948
15253
  );
14949
15254
  return;
14950
15255
  }
14951
- const relativeFromCwd = path12.relative(process.cwd(), loaded.entry.absolutePath);
15256
+ const relativeFromCwd = path13.relative(process.cwd(), loaded.entry.absolutePath);
14952
15257
  console.log();
14953
- console.log(chalk8.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
15258
+ console.log(chalk9.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
14954
15259
  console.log(
14955
- chalk8.gray(
15260
+ chalk9.gray(
14956
15261
  `${tr(config.lang, "cli", "docs.sourceLabel")}: ${relativeFromCwd || loaded.entry.absolutePath}`
14957
15262
  )
14958
15263
  );
14959
15264
  console.log(
14960
- chalk8.gray(`${tr(config.lang, "cli", "docs.hashLabel")}: ${loaded.hash}`)
15265
+ chalk9.gray(`${tr(config.lang, "cli", "docs.hashLabel")}: ${loaded.hash}`)
14961
15266
  );
14962
15267
  console.log();
14963
15268
  process.stdout.write(loaded.content.endsWith("\n") ? loaded.content : `${loaded.content}
14964
15269
  `);
14965
15270
  if (followups.length > 0) {
14966
15271
  console.log();
14967
- console.log(chalk8.blue(`${tr(config.lang, "cli", "docs.nextDocs")}:`));
15272
+ console.log(chalk9.blue(`${tr(config.lang, "cli", "docs.nextDocs")}:`));
14968
15273
  for (const followup of followups) {
14969
- console.log(chalk8.gray(`- ${followup.command}`));
15274
+ console.log(chalk9.gray(`- ${followup.command}`));
14970
15275
  }
14971
15276
  console.log();
14972
15277
  }
@@ -14986,8 +15291,8 @@ function docsCommand(program2) {
14986
15291
  );
14987
15292
  } else {
14988
15293
  console.error(
14989
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
14990
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
15294
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
15295
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
14991
15296
  );
14992
15297
  printCliErrorSuggestions(suggestions, lang);
14993
15298
  }
@@ -15016,8 +15321,8 @@ function detectCommand(program2) {
15016
15321
  );
15017
15322
  } else {
15018
15323
  console.error(
15019
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
15020
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
15324
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
15325
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
15021
15326
  );
15022
15327
  printCliErrorSuggestions(suggestions, lang);
15023
15328
  }
@@ -15028,7 +15333,7 @@ function detectCommand(program2) {
15028
15333
  }
15029
15334
  async function runDetect(options) {
15030
15335
  const cwd = process.cwd();
15031
- const targetCwd = options.dir ? path12.resolve(cwd, options.dir) : cwd;
15336
+ const targetCwd = options.dir ? path13.resolve(cwd, options.dir) : cwd;
15032
15337
  const config = await getConfig(targetCwd);
15033
15338
  const detected = !!config;
15034
15339
  const reasonCode = detected ? "PROJECT_DETECTED" : "PROJECT_NOT_DETECTED";
@@ -15055,7 +15360,7 @@ async function runDetect(options) {
15055
15360
  );
15056
15361
  return;
15057
15362
  }
15058
- const configPath2 = path12.join(config.docsDir, ".lee-spec-kit.json");
15363
+ const configPath2 = path13.join(config.docsDir, ".lee-spec-kit.json");
15059
15364
  const configFilePresent2 = await fs.pathExists(configPath2);
15060
15365
  const detectionSource2 = configFilePresent2 ? "config" : "heuristic";
15061
15366
  console.log(
@@ -15081,26 +15386,26 @@ async function runDetect(options) {
15081
15386
  }
15082
15387
  const lang = config?.lang ?? DEFAULT_LANG;
15083
15388
  console.log();
15084
- console.log(chalk8.blue(tr(lang, "cli", "detect.header")));
15085
- console.log(chalk8.gray(`- ${tr(lang, "cli", "detect.labelTarget")}: ${targetCwd}`));
15389
+ console.log(chalk9.blue(tr(lang, "cli", "detect.header")));
15390
+ console.log(chalk9.gray(`- ${tr(lang, "cli", "detect.labelTarget")}: ${targetCwd}`));
15086
15391
  if (!config) {
15087
- console.log(chalk8.yellow(`- ${tr(lang, "cli", "detect.resultNotDetected")}`));
15088
- console.log(chalk8.gray(`- ${tr(lang, "cli", "detect.notDetectedHint")}`));
15392
+ console.log(chalk9.yellow(`- ${tr(lang, "cli", "detect.resultNotDetected")}`));
15393
+ console.log(chalk9.gray(`- ${tr(lang, "cli", "detect.notDetectedHint")}`));
15089
15394
  console.log();
15090
15395
  return;
15091
15396
  }
15092
- const configPath = path12.join(config.docsDir, ".lee-spec-kit.json");
15397
+ const configPath = path13.join(config.docsDir, ".lee-spec-kit.json");
15093
15398
  const configFilePresent = await fs.pathExists(configPath);
15094
15399
  const detectionSource = configFilePresent ? "config" : "heuristic";
15095
- console.log(chalk8.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
15096
- console.log(chalk8.gray(`- ${tr(lang, "cli", "detect.labelDocsDir")}: ${config.docsDir}`));
15400
+ console.log(chalk9.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
15401
+ console.log(chalk9.gray(`- ${tr(lang, "cli", "detect.labelDocsDir")}: ${config.docsDir}`));
15097
15402
  console.log(
15098
- chalk8.gray(
15403
+ chalk9.gray(
15099
15404
  `- ${tr(lang, "cli", "detect.labelConfigPath")}: ${configFilePresent ? configPath : "-"}`
15100
15405
  )
15101
15406
  );
15102
15407
  console.log(
15103
- chalk8.gray(
15408
+ chalk9.gray(
15104
15409
  `- ${tr(lang, "cli", "detect.labelSource")}: ${tr(
15105
15410
  lang,
15106
15411
  "cli",
@@ -15109,14 +15414,14 @@ async function runDetect(options) {
15109
15414
  )
15110
15415
  );
15111
15416
  console.log(
15112
- chalk8.gray(
15417
+ chalk9.gray(
15113
15418
  `- ${tr(lang, "cli", "detect.labelProjectType")}: ${config.projectType}`
15114
15419
  )
15115
15420
  );
15116
- console.log(chalk8.gray(`- ${tr(lang, "cli", "detect.labelLang")}: ${config.lang}`));
15421
+ console.log(chalk9.gray(`- ${tr(lang, "cli", "detect.labelLang")}: ${config.lang}`));
15117
15422
  if (config.projectName) {
15118
15423
  console.log(
15119
- chalk8.gray(
15424
+ chalk9.gray(
15120
15425
  `- ${tr(lang, "cli", "detect.labelProjectName")}: ${config.projectName}`
15121
15426
  )
15122
15427
  );
@@ -15166,19 +15471,19 @@ function hasTemplateMarkers(content) {
15166
15471
  return patterns.some((pattern) => pattern.test(content));
15167
15472
  }
15168
15473
  async function countFeatureDirs(ctx, docsDir, projectType) {
15169
- const featuresRoot = path12.join(docsDir, "features");
15474
+ const featuresRoot = path13.join(docsDir, "features");
15170
15475
  if (projectType === "single") {
15171
15476
  const dirs = await listSubdirectories(ctx.fs, featuresRoot);
15172
- return dirs.filter((value) => path12.basename(value) !== "feature-base").length;
15477
+ return dirs.filter((value) => path13.basename(value) !== "feature-base").length;
15173
15478
  }
15174
15479
  const components = await listSubdirectories(ctx.fs, featuresRoot);
15175
15480
  let total = 0;
15176
15481
  for (const componentDir of components) {
15177
- const componentName = path12.basename(componentDir).trim().toLowerCase();
15482
+ const componentName = path13.basename(componentDir).trim().toLowerCase();
15178
15483
  if (!componentName || componentName === "feature-base") continue;
15179
15484
  const dirs = await listSubdirectories(ctx.fs, componentDir);
15180
15485
  total += dirs.filter(
15181
- (value) => path12.basename(value) !== "feature-base"
15486
+ (value) => path13.basename(value) !== "feature-base"
15182
15487
  ).length;
15183
15488
  }
15184
15489
  return total;
@@ -15190,7 +15495,7 @@ async function hasUserPrdFile(ctx, prdDir) {
15190
15495
  ignoreDirs: ["node_modules"]
15191
15496
  });
15192
15497
  return files.some(
15193
- (absolutePath) => path12.basename(absolutePath).toLowerCase() !== "readme.md"
15498
+ (absolutePath) => path13.basename(absolutePath).toLowerCase() !== "readme.md"
15194
15499
  );
15195
15500
  }
15196
15501
  function finalizeChecks(checks) {
@@ -15207,17 +15512,17 @@ function finalizeChecks(checks) {
15207
15512
  function printOnboardResult(lang, result) {
15208
15513
  console.log();
15209
15514
  console.log(
15210
- chalk8.bold(t(lang, "\u{1F9ED} Onboarding \uC810\uAC80", "\u{1F9ED} Onboarding Checks"))
15515
+ chalk9.bold(t(lang, "\u{1F9ED} Onboarding \uC810\uAC80", "\u{1F9ED} Onboarding Checks"))
15211
15516
  );
15212
15517
  for (const check of result.checks) {
15213
- const mark = check.status === "ok" ? chalk8.green("\u2705") : check.status === "warn" ? chalk8.yellow("\u26A0\uFE0F") : chalk8.red("\u274C");
15214
- const level = check.status === "ok" ? chalk8.green("OK") : check.status === "warn" ? chalk8.yellow("WARN") : chalk8.red("BLOCK");
15518
+ const mark = check.status === "ok" ? chalk9.green("\u2705") : check.status === "warn" ? chalk9.yellow("\u26A0\uFE0F") : chalk9.red("\u274C");
15519
+ const level = check.status === "ok" ? chalk9.green("OK") : check.status === "warn" ? chalk9.yellow("WARN") : chalk9.red("BLOCK");
15215
15520
  console.log(`${mark} [${level}] ${check.title}`);
15216
15521
  console.log(` ${check.message}`);
15217
- if (check.path) console.log(chalk8.gray(` path: ${check.path}`));
15522
+ if (check.path) console.log(chalk9.gray(` path: ${check.path}`));
15218
15523
  if (check.suggestedCommand) {
15219
15524
  console.log(
15220
- chalk8.gray(
15525
+ chalk9.gray(
15221
15526
  ` ${t(lang, "\uB2E4\uC74C \uBA85\uB839", "next")}: ${check.suggestedCommand}`
15222
15527
  )
15223
15528
  );
@@ -15225,7 +15530,7 @@ function printOnboardResult(lang, result) {
15225
15530
  }
15226
15531
  console.log();
15227
15532
  console.log(
15228
- chalk8.bold(
15533
+ chalk9.bold(
15229
15534
  t(
15230
15535
  lang,
15231
15536
  `\uC694\uC57D: OK ${result.summary.ok}, WARN ${result.summary.warn}, BLOCK ${result.summary.block}`,
@@ -15235,13 +15540,13 @@ function printOnboardResult(lang, result) {
15235
15540
  );
15236
15541
  if (result.status === "ready") {
15237
15542
  console.log(
15238
- chalk8.green(
15543
+ chalk9.green(
15239
15544
  t(lang, "\uC628\uBCF4\uB529 \uC900\uBE44\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.", "Onboarding checks passed.")
15240
15545
  )
15241
15546
  );
15242
15547
  } else if (result.status === "needs_action") {
15243
15548
  console.log(
15244
- chalk8.yellow(
15549
+ chalk9.yellow(
15245
15550
  t(
15246
15551
  lang,
15247
15552
  "\uCD94\uAC00 \uC815\uB9AC\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
@@ -15251,7 +15556,7 @@ function printOnboardResult(lang, result) {
15251
15556
  );
15252
15557
  } else {
15253
15558
  console.log(
15254
- chalk8.red(
15559
+ chalk9.red(
15255
15560
  t(
15256
15561
  lang,
15257
15562
  "\uC628\uBCF4\uB529 \uC120\uD589 \uC791\uC5C5\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
@@ -15359,7 +15664,7 @@ async function runOnboardChecks(ctx) {
15359
15664
  });
15360
15665
  }
15361
15666
  }
15362
- const constitutionPath = path12.join(docsDir, "agents", "constitution.md");
15667
+ const constitutionPath = path13.join(docsDir, "agents", "constitution.md");
15363
15668
  if (!await fs.pathExists(constitutionPath)) {
15364
15669
  checks.push({
15365
15670
  id: "constitution_exists",
@@ -15401,7 +15706,7 @@ async function runOnboardChecks(ctx) {
15401
15706
  });
15402
15707
  }
15403
15708
  }
15404
- const customPath = path12.join(docsDir, "agents", "custom.md");
15709
+ const customPath = path13.join(docsDir, "agents", "custom.md");
15405
15710
  if (await fs.pathExists(customPath)) {
15406
15711
  const content = await fs.readFile(customPath, "utf-8");
15407
15712
  if (hasTemplateMarkers(content)) {
@@ -15430,7 +15735,7 @@ async function runOnboardChecks(ctx) {
15430
15735
  });
15431
15736
  }
15432
15737
  }
15433
- const prdDir = path12.join(docsDir, "prd");
15738
+ const prdDir = path13.join(docsDir, "prd");
15434
15739
  const featureCount = await countFeatureDirs(ctx, docsDir, config.projectType);
15435
15740
  const prdReady = await hasUserPrdFile(ctx, prdDir);
15436
15741
  if (!prdReady) {
@@ -15448,7 +15753,7 @@ async function runOnboardChecks(ctx) {
15448
15753
  "PRD is empty. If features already exist, fill PRD as soon as possible."
15449
15754
  ),
15450
15755
  path: prdDir,
15451
- suggestedCommand: `touch ${quotePath(path12.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
15756
+ suggestedCommand: `touch ${quotePath(path13.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
15452
15757
  });
15453
15758
  } else {
15454
15759
  checks.push({
@@ -15589,8 +15894,8 @@ function onboardCommand(program2) {
15589
15894
  );
15590
15895
  } else {
15591
15896
  console.error(
15592
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
15593
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
15897
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
15898
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
15594
15899
  );
15595
15900
  printCliErrorSuggestions(suggestions, lang);
15596
15901
  }
@@ -15633,6 +15938,14 @@ function asNonEmptyString(value, fallback) {
15633
15938
  const trimmed = value.trim();
15634
15939
  return trimmed || fallback;
15635
15940
  }
15941
+ function asRequiredNonEmptyString(value, field) {
15942
+ const normalized = asNonEmptyString(value, "");
15943
+ if (normalized) return normalized;
15944
+ throw createCliError(
15945
+ "VALIDATION_FAILED",
15946
+ `Evidence JSON ${field} is required.`
15947
+ );
15948
+ }
15636
15949
  function asRequiredBoolean(value, field) {
15637
15950
  if (typeof value === "boolean") return value;
15638
15951
  throw createCliError(
@@ -15711,6 +16024,61 @@ function normalizeCommandsExecuted(value) {
15711
16024
  return entry.trim();
15712
16025
  });
15713
16026
  }
16027
+ function normalizeRequiredPathList(value, field) {
16028
+ if (!Array.isArray(value)) {
16029
+ throw createCliError(
16030
+ "VALIDATION_FAILED",
16031
+ `Evidence JSON ${field} must be a non-empty array of repo-relative paths.`
16032
+ );
16033
+ }
16034
+ const out = value.map((entry, index) => {
16035
+ if (typeof entry !== "string" || !entry.trim()) {
16036
+ throw createCliError(
16037
+ "VALIDATION_FAILED",
16038
+ `Evidence JSON ${field}[${index}] must be a non-empty repo-relative path string.`
16039
+ );
16040
+ }
16041
+ return normalizeGitPath3(entry);
16042
+ }).filter(Boolean);
16043
+ if (out.length === 0) {
16044
+ throw createCliError(
16045
+ "VALIDATION_FAILED",
16046
+ `Evidence JSON ${field} must include at least one repo-relative path.`
16047
+ );
16048
+ }
16049
+ return uniquePaths(out);
16050
+ }
16051
+ function normalizeRiskSummaries(value) {
16052
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
16053
+ throw createCliError(
16054
+ "VALIDATION_FAILED",
16055
+ 'Evidence JSON "riskSummaries" is required and must include blocking, important, and minor fields.'
16056
+ );
16057
+ }
16058
+ const riskSummaries = value;
16059
+ return {
16060
+ blocking: asRequiredReviewField(
16061
+ riskSummaries.blocking,
16062
+ '"riskSummaries.blocking"',
16063
+ { allowExplicitNone: true }
16064
+ ),
16065
+ important: asRequiredReviewField(
16066
+ riskSummaries.important,
16067
+ '"riskSummaries.important"',
16068
+ { allowExplicitNone: true }
16069
+ ),
16070
+ minor: asRequiredReviewField(
16071
+ riskSummaries.minor,
16072
+ '"riskSummaries.minor"',
16073
+ { allowExplicitNone: true }
16074
+ )
16075
+ };
16076
+ }
16077
+ function formatMissingPathGuidance(field, missingFiles) {
16078
+ return `Evidence JSON ${field} is missing these repo-relative paths:
16079
+ ${missingFiles.map((file) => `- ${file}`).join("\n")}
16080
+ Use paths relative to the project git root, matching files.path entries.`;
16081
+ }
15714
16082
  function normalizeGitPath3(value) {
15715
16083
  return value.trim().replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
15716
16084
  }
@@ -15823,7 +16191,7 @@ var PrePrReviewValidator = class {
15823
16191
  return result.evidence;
15824
16192
  }
15825
16193
  async validateEvidenceWithScope(evidencePath, projectRoot) {
15826
- const fullPath = path12.resolve(evidencePath);
16194
+ const fullPath = path13.resolve(evidencePath);
15827
16195
  if (!await fs.pathExists(fullPath)) {
15828
16196
  throw createCliError(
15829
16197
  "INVALID_ARGUMENT",
@@ -15866,6 +16234,27 @@ var PrePrReviewValidator = class {
15866
16234
  evidence.blockingFindings,
15867
16235
  '"blockingFindings"'
15868
16236
  ),
16237
+ baseSha: asRequiredNonEmptyString(evidence.baseSha, '"baseSha"'),
16238
+ headSha: asRequiredNonEmptyString(evidence.headSha, '"headSha"'),
16239
+ changedFiles: normalizeRequiredPathList(
16240
+ evidence.changedFiles,
16241
+ '"changedFiles"'
16242
+ ),
16243
+ reviewedFiles: normalizeRequiredPathList(
16244
+ evidence.reviewedFiles,
16245
+ '"reviewedFiles"'
16246
+ ),
16247
+ riskSummaries: normalizeRiskSummaries(evidence.riskSummaries),
16248
+ approvalRationale: asRequiredReviewField(
16249
+ evidence.approvalRationale,
16250
+ '"approvalRationale"'
16251
+ ),
16252
+ coverage: {
16253
+ changedFileCount: 0,
16254
+ reviewedFileCount: 0,
16255
+ reviewCoverageRatio: 0,
16256
+ missingFiles: []
16257
+ },
15869
16258
  files: normalizeEvidenceFiles(evidence.files),
15870
16259
  residualRisks: normalizeResidualRisks(evidence.residualRisks),
15871
16260
  commandsExecuted: normalizeCommandsExecuted(evidence.commandsExecuted)
@@ -15900,9 +16289,9 @@ var PrePrReviewValidator = class {
15900
16289
  ]);
15901
16290
  const reviewedFiles = new Set(
15902
16291
  normalizedEvidence.files.map(
15903
- (f) => path12.relative(
16292
+ (f) => path13.relative(
15904
16293
  projectRoot,
15905
- path12.resolve(projectRoot, f.path)
16294
+ path13.resolve(projectRoot, f.path)
15906
16295
  )
15907
16296
  ).map((entry) => normalizeGitPath3(entry)).filter(Boolean)
15908
16297
  );
@@ -15914,6 +16303,36 @@ var PrePrReviewValidator = class {
15914
16303
  ${missingFiles.map((f) => `- ${f}`).join("\n")}`
15915
16304
  );
15916
16305
  }
16306
+ const changedFilesInEvidence = new Set(
16307
+ normalizedEvidence.changedFiles.map((entry) => normalizeGitPath3(entry))
16308
+ );
16309
+ const missingChangedFiles = changedFiles.filter(
16310
+ (file) => !changedFilesInEvidence.has(file)
16311
+ );
16312
+ if (missingChangedFiles.length > 0) {
16313
+ throw createCliError(
16314
+ "VALIDATION_FAILED",
16315
+ formatMissingPathGuidance('"changedFiles"', missingChangedFiles)
16316
+ );
16317
+ }
16318
+ const reviewedFilesInEvidence = new Set(
16319
+ normalizedEvidence.reviewedFiles.map((entry) => normalizeGitPath3(entry))
16320
+ );
16321
+ const missingReviewedFiles = changedFiles.filter(
16322
+ (file) => !reviewedFilesInEvidence.has(file)
16323
+ );
16324
+ if (missingReviewedFiles.length > 0) {
16325
+ throw createCliError(
16326
+ "VALIDATION_FAILED",
16327
+ formatMissingPathGuidance('"reviewedFiles"', missingReviewedFiles)
16328
+ );
16329
+ }
16330
+ normalizedEvidence.coverage = {
16331
+ changedFileCount: changedFiles.length,
16332
+ reviewedFileCount: normalizedEvidence.reviewedFiles.length,
16333
+ reviewCoverageRatio: changedFiles.length === 0 ? 1 : normalizedEvidence.reviewedFiles.length / changedFiles.length,
16334
+ missingFiles: missingReviewedFiles
16335
+ };
15917
16336
  return {
15918
16337
  evidence: normalizedEvidence,
15919
16338
  scope
@@ -16048,11 +16467,27 @@ var DEFAULT_EVIDENCE_FOR_ANY_MODE = {
16048
16467
  specAlignmentChecked: true,
16049
16468
  findingCount: 0,
16050
16469
  blockingFindings: 0,
16470
+ baseSha: "unrecorded",
16471
+ headSha: "unrecorded",
16472
+ changedFiles: [],
16473
+ reviewedFiles: [],
16474
+ riskSummaries: {
16475
+ blocking: "none",
16476
+ important: "manual direct record without structured evidence",
16477
+ minor: "manual direct record without structured evidence"
16478
+ },
16479
+ approvalRationale: "manual direct record without structured evidence; not valid for approve",
16480
+ coverage: {
16481
+ changedFileCount: 0,
16482
+ reviewedFileCount: 0,
16483
+ reviewCoverageRatio: 0,
16484
+ missingFiles: []
16485
+ },
16051
16486
  files: [],
16052
16487
  residualRisks: ["none"],
16053
16488
  commandsExecuted: []
16054
16489
  };
16055
- function escapeRegExp4(value) {
16490
+ function escapeRegExp5(value) {
16056
16491
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16057
16492
  }
16058
16493
  function normalizeDecision(raw) {
@@ -16066,14 +16501,14 @@ function normalizeDecision(raw) {
16066
16501
  return null;
16067
16502
  }
16068
16503
  function findSpecLineIndex(lines, keys) {
16069
- const escaped = keys.map((key) => escapeRegExp4(key));
16504
+ const escaped = keys.map((key) => escapeRegExp5(key));
16070
16505
  const re = new RegExp(
16071
16506
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
16072
16507
  );
16073
16508
  return lines.findIndex((line) => re.test(line));
16074
16509
  }
16075
16510
  function replaceSpecLine(line, keys, preferredKey, value) {
16076
- const escaped = keys.map((key) => escapeRegExp4(key));
16511
+ const escaped = keys.map((key) => escapeRegExp5(key));
16077
16512
  const re = new RegExp(
16078
16513
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
16079
16514
  );
@@ -16163,11 +16598,28 @@ ${normalizedCommands.map((c) => ` - \`${c}\``).join("\n")}
16163
16598
  - **Spec Alignment Checked**: ${input.evidence.specAlignmentChecked ? "yes" : "no"}
16164
16599
  - **Finding Count**: ${input.evidence.findingCount}
16165
16600
  - **Blocking Findings**: ${input.evidence.blockingFindings}
16601
+ - **Base SHA**: ${input.evidence.baseSha}
16602
+ - **Head SHA**: ${input.evidence.headSha}
16603
+ - **Approval Rationale**: ${input.evidence.approvalRationale}
16166
16604
  ${commandsRun}
16167
16605
 
16168
16606
  - **Residual Risks**:
16169
16607
  ${residualRisksSection}
16170
16608
 
16609
+ - **Risk Summaries**:
16610
+ - Blocking: ${input.evidence.riskSummaries.blocking}
16611
+ - Important: ${input.evidence.riskSummaries.important}
16612
+ - Minor: ${input.evidence.riskSummaries.minor}
16613
+
16614
+ - **Evidence Coverage**:
16615
+ - Changed File Count: ${input.evidence.coverage.changedFileCount}
16616
+ - Reviewed File Count: ${input.evidence.coverage.reviewedFileCount}
16617
+ - Review Coverage Ratio: ${input.evidence.coverage.reviewCoverageRatio.toFixed(2)}
16618
+ - Reviewed Files:
16619
+ ${input.evidence.reviewedFiles.length > 0 ? input.evidence.reviewedFiles.map((entry) => ` - ${entry}`).join("\n") : " - (none)"}
16620
+ - Evidence Changed Files:
16621
+ ${input.evidence.changedFiles.length > 0 ? input.evidence.changedFiles.map((entry) => ` - ${entry}`).join("\n") : " - (none)"}
16622
+
16171
16623
  - **Review Scope**:
16172
16624
  - **Main Base Ref**: ${input.scope.baseRef}
16173
16625
  - **Main Merge Base**: ${input.scope.mergeBase ?? "unresolved"}
@@ -16221,7 +16673,7 @@ function prePrReviewCommand(program2) {
16221
16673
  })
16222
16674
  );
16223
16675
  } else {
16224
- console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
16676
+ console.error(chalk9.red(`[${cliError.code}] ${cliError.message}`));
16225
16677
  printCliErrorSuggestions(suggestions, lang);
16226
16678
  }
16227
16679
  process.exitCode = 1;
@@ -16233,7 +16685,7 @@ function prePrReviewCommand(program2) {
16233
16685
  "Decision outcome: approve | changes_requested | blocked"
16234
16686
  ).option("--note <text>", "Decision note text").option(
16235
16687
  "--evidence <path>",
16236
- "Optional review evidence path (for example review-trace.json); required only when policy demands it"
16688
+ "Structured review evidence path (for example review-trace.json); required for approve and whenever policy demands it"
16237
16689
  ).option("--json", "Output JSON").action(
16238
16690
  async (featureName, options) => {
16239
16691
  try {
@@ -16253,7 +16705,7 @@ function prePrReviewCommand(program2) {
16253
16705
  })
16254
16706
  );
16255
16707
  } else {
16256
- console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
16708
+ console.error(chalk9.red(`[${cliError.code}] ${cliError.message}`));
16257
16709
  printCliErrorSuggestions(suggestions, lang);
16258
16710
  }
16259
16711
  process.exitCode = 1;
@@ -16300,7 +16752,7 @@ async function runPrePrReviewRun(featureName, options) {
16300
16752
  );
16301
16753
  const policy = resolvePrePrReviewPolicy(config.workflow);
16302
16754
  const preferred = getPreferredKeys(config.lang);
16303
- const tasksPath = path12.join(feature.path, "tasks.md");
16755
+ const tasksPath = path13.join(feature.path, "tasks.md");
16304
16756
  let tasksUpdated = false;
16305
16757
  if (await fs.pathExists(tasksPath)) {
16306
16758
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
@@ -16351,7 +16803,7 @@ async function runPrePrReviewRun(featureName, options) {
16351
16803
  fallbackToMainAgentWhenQuotaExceeded: true,
16352
16804
  nextStepRequirement: "generate_review_trace_then_record",
16353
16805
  delegatedWorkRequired: true,
16354
- nextMainState: "pre_pr_review_running",
16806
+ nextMainState: "pre_pr_review_in_progress",
16355
16807
  evidenceFile: "review-trace.json",
16356
16808
  tasksUpdated,
16357
16809
  tasksPath,
@@ -16370,26 +16822,26 @@ async function runPrePrReviewRun(featureName, options) {
16370
16822
  console.log(prompt);
16371
16823
  console.log();
16372
16824
  console.log(
16373
- chalk8.yellow(
16374
- config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. review-trace.json\uC744 \uC9C1\uC811 \uC0DD\uC131\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the review handoff. It does not generate review-trace.json or advance workflow state by itself."
16825
+ chalk9.yellow(
16826
+ config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. review-trace.json\uC744 \uC9C1\uC811 \uC0DD\uC131\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the review handoff. It does not complete the review or advance workflow state by itself."
16375
16827
  )
16376
16828
  );
16377
16829
  console.log(
16378
- chalk8.gray(
16830
+ chalk9.gray(
16379
16831
  config.lang === "ko" ? "- \uAE30\uC874 pre-PR \uB9AC\uBDF0 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694." : "- Reuse the existing pre-PR helper agent if one already exists; default to a single helper agent."
16380
16832
  )
16381
16833
  );
16382
16834
  console.log(
16383
- chalk8.gray(
16835
+ chalk9.gray(
16384
16836
  config.lang === "ko" ? "- \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uC138\uC694." : "- If helper-agent quota is exhausted, continue the review in the main agent."
16385
16837
  )
16386
16838
  );
16387
16839
  console.log(`Reuse key: pre-pr:${featureRef}`);
16388
16840
  console.log(`Suggested parallelism: 1`);
16389
- console.log(`Next main state: pre_pr_review_running`);
16841
+ console.log(`Next main state: pre_pr_review_in_progress`);
16390
16842
  console.log(`Evidence file: review-trace.json`);
16391
16843
  console.log(
16392
- config.lang === "ko" ? "Next required: delegated review\uB97C \uC774\uC5B4\uC11C \uC218\uD589\uD558\uACE0 review-trace.json\uC744 \uB9CC\uB4E0 \uB4A4 pre-pr-review\uB85C \uAE30\uB85D" : "Next required: continue the delegated review, generate review-trace.json, then record the result with pre-pr-review"
16844
+ config.lang === "ko" ? "Next required: delegated review\uB97C \uC774\uC5B4\uC11C \uC218\uD589\uD558\uACE0 \uAD6C\uC870\uD654\uB41C review-trace.json\uC744 \uB9CC\uB4E0 \uB4A4 pre-pr-review\uB85C \uAE30\uB85D" : "Next required: continue the delegated review, generate structured review-trace.json, then record the result with pre-pr-review"
16393
16845
  );
16394
16846
  if (tasksUpdated) {
16395
16847
  console.log(`tasks.md updated: ${tasksPath}`);
@@ -16411,7 +16863,7 @@ async function runPrePrReview(featureName, options) {
16411
16863
  `tasks.md not found for feature: ${feature.folderName}`
16412
16864
  );
16413
16865
  }
16414
- const tasksPath = path12.join(feature.path, "tasks.md");
16866
+ const tasksPath = path13.join(feature.path, "tasks.md");
16415
16867
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
16416
16868
  const policy = resolvePrePrReviewPolicy(config.workflow);
16417
16869
  const preferred = getPreferredKeys(config.lang);
@@ -16444,6 +16896,12 @@ async function runPrePrReview(featureName, options) {
16444
16896
  "`--evidence <path>` is required when workflow.prePrReview.enforceExecutionEvidence=true."
16445
16897
  );
16446
16898
  }
16899
+ if (decision === "approve" && !options.evidence) {
16900
+ throw createCliError(
16901
+ "INVALID_ARGUMENT",
16902
+ "`--evidence <path>` is required for approve decisions. Generate structured review evidence first, for example `--evidence review-trace.json`."
16903
+ );
16904
+ }
16447
16905
  if (options.evidence) {
16448
16906
  const validator = new PrePrReviewValidator(ctx);
16449
16907
  const validationResult = await validator.validateEvidenceWithScope(
@@ -16503,7 +16961,7 @@ async function runPrePrReview(featureName, options) {
16503
16961
  }
16504
16962
  }
16505
16963
  }
16506
- const decisionsPath = path12.join(feature.path, "decisions.md");
16964
+ const decisionsPath = path13.join(feature.path, "decisions.md");
16507
16965
  const decisionLogEntry = buildReportContent({
16508
16966
  folderName: feature.folderName,
16509
16967
  date,
@@ -16519,9 +16977,9 @@ async function runPrePrReview(featureName, options) {
16519
16977
  await fs.writeFile(decisionsPath, nextDecisions, "utf-8");
16520
16978
  }
16521
16979
  const decisionsPathFromDocs = normalizePathForDoc(
16522
- path12.join(feature.docs.featurePathFromDocs, "decisions.md")
16980
+ path13.join(feature.docs.featurePathFromDocs, "decisions.md")
16523
16981
  );
16524
- const evidencePath = path12.basename(config.docsDir) === "docs" ? normalizePathForDoc(path12.join("docs", decisionsPathFromDocs)) : decisionsPathFromDocs;
16982
+ const evidencePath = path13.basename(config.docsDir) === "docs" ? normalizePathForDoc(path13.join("docs", decisionsPathFromDocs)) : decisionsPathFromDocs;
16525
16983
  let nextTasks = tasksContent;
16526
16984
  nextTasks = upsertSpecLine(
16527
16985
  nextTasks,
@@ -16568,26 +17026,26 @@ async function runPrePrReview(featureName, options) {
16568
17026
  return;
16569
17027
  }
16570
17028
  console.log();
16571
- console.log(chalk8.green(`\u2705 pre-pr-review completed: ${feature.folderName}`));
16572
- console.log(chalk8.gray(`- Decision: ${decision}`));
16573
- console.log(chalk8.gray(`- Decisions log: ${decisionsPath}`));
17029
+ console.log(chalk9.green(`\u2705 pre-pr-review completed: ${feature.folderName}`));
17030
+ console.log(chalk9.gray(`- Decision: ${decision}`));
17031
+ console.log(chalk9.gray(`- Decisions log: ${decisionsPath}`));
16574
17032
  if (nextTasks !== tasksContent) {
16575
- console.log(chalk8.gray(`- tasks.md updated: ${tasksPath}`));
17033
+ console.log(chalk9.gray(`- tasks.md updated: ${tasksPath}`));
16576
17034
  }
16577
17035
  console.log();
16578
17036
  }
16579
- function escapeRegExp5(value) {
17037
+ function escapeRegExp6(value) {
16580
17038
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16581
17039
  }
16582
17040
  function findSpecLineIndex2(lines, keys) {
16583
- const escaped = keys.map((key) => escapeRegExp5(key));
17041
+ const escaped = keys.map((key) => escapeRegExp6(key));
16584
17042
  const re = new RegExp(
16585
17043
  `^\\s*-\\s*\\*\\*(?:${escaped.join("|")})\\*\\*\\s*:\\s*`
16586
17044
  );
16587
17045
  return lines.findIndex((line) => re.test(line));
16588
17046
  }
16589
17047
  function replaceSpecLine2(line, keys, preferredKey, value) {
16590
- const escaped = keys.map((key) => escapeRegExp5(key));
17048
+ const escaped = keys.map((key) => escapeRegExp6(key));
16591
17049
  const re = new RegExp(
16592
17050
  `^(\\s*-\\s*\\*\\*)(?:${escaped.join("|")})(\\*\\*\\s*:\\s*)(.*)$`
16593
17051
  );
@@ -16662,7 +17120,7 @@ async function runCodeReviewRun(featureName, options) {
16662
17120
  );
16663
17121
  }
16664
17122
  const feature = state.matchedFeature;
16665
- const tasksPath = path12.join(feature.path, "tasks.md");
17123
+ const tasksPath = path13.join(feature.path, "tasks.md");
16666
17124
  let tasksUpdated = false;
16667
17125
  if (await fs.pathExists(tasksPath)) {
16668
17126
  const tasksContent = await fs.readFile(tasksPath, "utf-8");
@@ -16697,7 +17155,7 @@ async function runCodeReviewRun(featureName, options) {
16697
17155
  nextMainState: "code_review_running",
16698
17156
  tasksUpdated,
16699
17157
  tasksPath,
16700
- decisionsPath: path12.join(feature.path, "decisions.md"),
17158
+ decisionsPath: path13.join(feature.path, "decisions.md"),
16701
17159
  prompt,
16702
17160
  recordedAt: getLocalDateString()
16703
17161
  };
@@ -16708,30 +17166,30 @@ async function runCodeReviewRun(featureName, options) {
16708
17166
  console.log(prompt);
16709
17167
  console.log();
16710
17168
  console.log(
16711
- chalk8.yellow(
17169
+ chalk9.yellow(
16712
17170
  config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uB300\uC751\uC6A9 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \uCF54\uBA58\uD2B8\uB97C \uC9C1\uC811 \uC77D\uC5B4\uC624\uAC70\uB098 evidence/decision\uC744 \uC790\uB3D9 \uAE30\uB85D\uD558\uC9C0 \uC54A\uC73C\uBA70, \uC0C1\uD0DC\uB3C4 \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares a handoff for addressing PR review comments. It does not fetch comments automatically, record review evidence/decision, or advance workflow state by itself."
16713
17171
  )
16714
17172
  );
16715
- console.log(chalk8.gray(`- substate: ${payload.substateId}`));
16716
- console.log(chalk8.gray(`- owner: ${payload.owner}`));
16717
- console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
16718
- console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
17173
+ console.log(chalk9.gray(`- substate: ${payload.substateId}`));
17174
+ console.log(chalk9.gray(`- owner: ${payload.owner}`));
17175
+ console.log(chalk9.gray(`- reuse key: ${payload.reuseKey}`));
17176
+ console.log(chalk9.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
16719
17177
  console.log(
16720
- chalk8.gray(
17178
+ chalk9.gray(
16721
17179
  `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
16722
17180
  )
16723
17181
  );
16724
- console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
17182
+ console.log(chalk9.gray(`- next main state: ${payload.nextMainState}`));
16725
17183
  if (tasksUpdated) {
16726
- console.log(chalk8.gray(`- tasks.md updated: ${payload.tasksPath}`));
17184
+ console.log(chalk9.gray(`- tasks.md updated: ${payload.tasksPath}`));
16727
17185
  console.log(
16728
- chalk8.gray(
17186
+ chalk9.gray(
16729
17187
  config.lang === "ko" ? "- PR \uB9AC\uBDF0 \uC0C1\uD0DC: Running" : "- PR Review status: Running"
16730
17188
  )
16731
17189
  );
16732
17190
  }
16733
- console.log(chalk8.gray(`- tasks.md: ${payload.tasksPath}`));
16734
- console.log(chalk8.gray(`- decisions.md: ${payload.decisionsPath}`));
17191
+ console.log(chalk9.gray(`- tasks.md: ${payload.tasksPath}`));
17192
+ console.log(chalk9.gray(`- decisions.md: ${payload.decisionsPath}`));
16735
17193
  }
16736
17194
  function codeReviewRunCommand(program2) {
16737
17195
  program2.command("code-review-run [feature-name]").description("Prepare a PR review execution handoff for sub-agent work").option("--component <component>", "Component name for multi projects").option("--json", "Output JSON").action(
@@ -16753,7 +17211,7 @@ function codeReviewRunCommand(program2) {
16753
17211
  })
16754
17212
  );
16755
17213
  } else {
16756
- console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
17214
+ console.error(chalk9.red(`[${cliError.code}] ${cliError.message}`));
16757
17215
  printCliErrorSuggestions(suggestions, lang);
16758
17216
  }
16759
17217
  process.exitCode = 1;
@@ -16788,8 +17246,8 @@ function requirementsCommand(program2) {
16788
17246
  const lang = ctx?.config?.lang ?? DEFAULT_LANG;
16789
17247
  const cliError = toCliError(error);
16790
17248
  console.error(
16791
- chalk8.red(tr(lang, "cli", "common.errorLabel")),
16792
- chalk8.red(`[${cliError.code}] ${cliError.message}`)
17249
+ chalk9.red(tr(lang, "cli", "common.errorLabel")),
17250
+ chalk9.red(`[${cliError.code}] ${cliError.message}`)
16793
17251
  );
16794
17252
  process.exitCode = 1;
16795
17253
  }
@@ -16822,7 +17280,7 @@ async function runRequirements(options) {
16822
17280
  }
16823
17281
  for (const feature of scan.features) {
16824
17282
  if (!feature.docs.tasksExists) continue;
16825
- const tasksPath = path12.join(feature.path, "tasks.md");
17283
+ const tasksPath = path13.join(feature.path, "tasks.md");
16826
17284
  let tasksContent = "";
16827
17285
  try {
16828
17286
  tasksContent = await ctx.fs.readFile(tasksPath, "utf-8");
@@ -16956,10 +17414,10 @@ async function runRequirements(options) {
16956
17414
  process.stdout.write(`${lines.join("\n")}
16957
17415
  `);
16958
17416
  if (options.write) {
16959
- const outputPath = path12.join(docsDir, "prd", "status.md");
17417
+ const outputPath = path13.join(docsDir, "prd", "status.md");
16960
17418
  await ctx.fs.writeFile(outputPath, `${lines.join("\n")}
16961
17419
  `, "utf-8");
16962
- console.log(chalk8.green(`\u2705 wrote: ${outputPath}`));
17420
+ console.log(chalk9.green(`\u2705 wrote: ${outputPath}`));
16963
17421
  }
16964
17422
  if (options.strict && issuesFound) process.exitCode = 1;
16965
17423
  }
@@ -17041,7 +17499,7 @@ async function resolveTaskRunContext(featureName, options) {
17041
17499
  }
17042
17500
  async function runTaskRun(featureName, options) {
17043
17501
  const { config, feature } = await resolveTaskRunContext(featureName, options);
17044
- const tasksPath = path12.join(feature.path, "tasks.md");
17502
+ const tasksPath = path13.join(feature.path, "tasks.md");
17045
17503
  if (!await fs.pathExists(tasksPath)) {
17046
17504
  throw createCliError(
17047
17505
  "PRECONDITION_FAILED",
@@ -17112,20 +17570,20 @@ async function runTaskRun(featureName, options) {
17112
17570
  }
17113
17571
  console.log(prompt);
17114
17572
  console.log();
17115
- console.log(chalk8.gray(`- substate: ${payload.substateId}`));
17116
- console.log(chalk8.gray(`- owner: ${payload.owner}`));
17117
- console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
17118
- console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
17573
+ console.log(chalk9.gray(`- substate: ${payload.substateId}`));
17574
+ console.log(chalk9.gray(`- owner: ${payload.owner}`));
17575
+ console.log(chalk9.gray(`- reuse key: ${payload.reuseKey}`));
17576
+ console.log(chalk9.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
17119
17577
  console.log(
17120
- chalk8.gray(
17578
+ chalk9.gray(
17121
17579
  `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
17122
17580
  )
17123
17581
  );
17124
- console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
17582
+ console.log(chalk9.gray(`- next main state: ${payload.nextMainState}`));
17125
17583
  if (tasksUpdated) {
17126
17584
  console.log();
17127
- console.log(chalk8.gray(`- tasks.md updated: ${tasksPath}`));
17128
- console.log(chalk8.gray(`- task status: TODO -> DOING`));
17585
+ console.log(chalk9.gray(`- tasks.md updated: ${tasksPath}`));
17586
+ console.log(chalk9.gray(`- task status: TODO -> DOING`));
17129
17587
  }
17130
17588
  }
17131
17589
  function taskRunCommand(program2) {
@@ -17149,7 +17607,7 @@ function taskRunCommand(program2) {
17149
17607
  })
17150
17608
  );
17151
17609
  } else {
17152
- console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
17610
+ console.error(chalk9.red(`[${cliError.code}] ${cliError.message}`));
17153
17611
  printCliErrorSuggestions(suggestions, lang);
17154
17612
  }
17155
17613
  process.exitCode = 1;
@@ -17200,7 +17658,7 @@ async function resolveTaskCompleteContext(featureName, options) {
17200
17658
  }
17201
17659
  async function runTaskComplete(featureName, options) {
17202
17660
  const { feature } = await resolveTaskCompleteContext(featureName, options);
17203
- const tasksPath = path12.join(feature.path, "tasks.md");
17661
+ const tasksPath = path13.join(feature.path, "tasks.md");
17204
17662
  if (!await fs.pathExists(tasksPath)) {
17205
17663
  throw createCliError(
17206
17664
  "PRECONDITION_FAILED",
@@ -17260,13 +17718,13 @@ async function runTaskComplete(featureName, options) {
17260
17718
  return;
17261
17719
  }
17262
17720
  console.log(
17263
- chalk8.green(
17721
+ chalk9.green(
17264
17722
  `Marked task ${resolvedTask.taskId} as DONE for ${feature.folderName}.`
17265
17723
  )
17266
17724
  );
17267
- console.log(chalk8.gray(`- tasks.md updated: ${tasksPath}`));
17268
- console.log(chalk8.gray(`- status: ${resolvedTask.status} -> DONE`));
17269
- console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
17725
+ console.log(chalk9.gray(`- tasks.md updated: ${tasksPath}`));
17726
+ console.log(chalk9.gray(`- status: ${resolvedTask.status} -> DONE`));
17727
+ console.log(chalk9.gray(`- next main state: ${payload.nextMainState}`));
17270
17728
  }
17271
17729
  function taskCompleteCommand(program2) {
17272
17730
  program2.command("task-complete [feature-name]").description("Mark the active DOING/REVIEW task as DONE").option("--component <component>", "Component name for multi projects").option("--task <task-id>", "Explicit task id to mark DONE").option("--json", "Output JSON").action(
@@ -17288,7 +17746,7 @@ function taskCompleteCommand(program2) {
17288
17746
  })
17289
17747
  );
17290
17748
  } else {
17291
- console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
17749
+ console.error(chalk9.red(`[${cliError.code}] ${cliError.message}`));
17292
17750
  printCliErrorSuggestions(suggestions, lang);
17293
17751
  }
17294
17752
  process.exitCode = 1;
@@ -17335,15 +17793,15 @@ function getBanner(opts) {
17335
17793
  ${version}
17336
17794
  ` : "\n";
17337
17795
  if (process.stdout.isTTY) {
17338
- return `${chalk8.cyan(ascii)}${chalk8.gray(footer)}`;
17796
+ return `${chalk9.cyan(ascii)}${chalk9.gray(footer)}`;
17339
17797
  }
17340
17798
  return `${ascii}${footer}`;
17341
17799
  }
17342
- var CACHE_FILE = path12.join(os.homedir(), ".lee-spec-kit-version-cache.json");
17800
+ var CACHE_FILE = path13.join(os.homedir(), ".lee-spec-kit-version-cache.json");
17343
17801
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
17344
17802
  function getCurrentVersion() {
17345
17803
  try {
17346
- const packageJsonPath = path12.join(__dirname$1, "..", "package.json");
17804
+ const packageJsonPath = path13.join(__dirname$1, "..", "package.json");
17347
17805
  if (fs.existsSync(packageJsonPath)) {
17348
17806
  const pkg = fs.readJsonSync(packageJsonPath);
17349
17807
  return pkg.version;
@@ -17377,8 +17835,8 @@ function resolveUpdateNoticeLang() {
17377
17835
  }
17378
17836
  function printUpdateNotice(current, latest, lang) {
17379
17837
  console.log();
17380
- console.log(chalk8.yellow(tr(lang, "cli", "versionCheck.noticeAvailable", { latest, current })));
17381
- console.log(chalk8.gray(tr(lang, "cli", "versionCheck.updateCommand")));
17838
+ console.log(chalk9.yellow(tr(lang, "cli", "versionCheck.noticeAvailable", { latest, current })));
17839
+ console.log(chalk9.gray(tr(lang, "cli", "versionCheck.updateCommand")));
17382
17840
  console.log();
17383
17841
  }
17384
17842
  function spawnBackgroundVersionCheck() {
@@ -17447,7 +17905,7 @@ function shouldCheckForUpdates() {
17447
17905
  if (shouldCheckForUpdates()) checkForUpdates();
17448
17906
  function getCliVersion() {
17449
17907
  try {
17450
- const packageJsonPath = path12.join(__dirname$1, "..", "package.json");
17908
+ const packageJsonPath = path13.join(__dirname$1, "..", "package.json");
17451
17909
  if (fs.existsSync(packageJsonPath)) {
17452
17910
  const pkg = fs.readJsonSync(packageJsonPath);
17453
17911
  if (pkg?.version) return String(pkg.version);
@@ -17465,6 +17923,7 @@ if (shouldShowBanner()) {
17465
17923
  }
17466
17924
  initCommand(program);
17467
17925
  featureCommand(program);
17926
+ ideaCommand(program);
17468
17927
  statusCommand(program);
17469
17928
  updateCommand(program);
17470
17929
  configCommand(program);