lee-spec-kit 0.6.14 → 0.6.15

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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import path18 from 'path';
2
+ import path19 from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { program } from 'commander';
5
5
  import fs15 from 'fs-extra';
@@ -11,7 +11,7 @@ import os from 'os';
11
11
  import { createHash, randomUUID } from 'crypto';
12
12
 
13
13
  var getFilename = () => fileURLToPath(import.meta.url);
14
- var getDirname = () => path18.dirname(getFilename());
14
+ var getDirname = () => path19.dirname(getFilename());
15
15
  var __dirname$1 = /* @__PURE__ */ getDirname();
16
16
  async function copyTemplates(src, dest) {
17
17
  await fs15.copy(src, dest, {
@@ -42,10 +42,10 @@ async function replaceInFiles(dir, replacements) {
42
42
  }
43
43
  }
44
44
  var __filename2 = fileURLToPath(import.meta.url);
45
- var __dirname2 = path18.dirname(__filename2);
45
+ var __dirname2 = path19.dirname(__filename2);
46
46
  function getTemplatesDir() {
47
- const rootDir = path18.resolve(__dirname2, "..");
48
- return path18.join(rootDir, "templates");
47
+ const rootDir = path19.resolve(__dirname2, "..");
48
+ return path19.join(rootDir, "templates");
49
49
  }
50
50
 
51
51
  // src/utils/i18n.ts
@@ -131,13 +131,13 @@ var I18N = {
131
131
  "context.tipShowAll": "\uC804\uCCB4 \uBCF4\uAE30",
132
132
  "context.tipShowDone": "\uC644\uB8CC\uB9CC \uBCF4\uAE30",
133
133
  "context.checkRequired": "[\uD655\uC778 \uD544\uC694] ",
134
- "context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uC815\uCC45\uC740 \uC138\uC158 \uC2DC\uC791(\uB610\uB294 context \uC555\uCD95/\uB9AC\uC14B \uC9C1\uD6C4)\uC5D0 1\uD68C \uD655\uC778\uD558\uACE0, \uC774\uD6C4\uC5D0\uB294 \uC815\uCC45/\uC124\uC815 \uBCC0\uACBD \uB610\uB294 \uC0AC\uC6A9\uC790 \uC0C8\uB85C\uACE0\uCE68 \uC694\uCCAD \uC2DC\uC5D0\uB9CC \uC7AC\uD655\uC778\uD558\uC138\uC694. (git push/merge/merge commit \uD3EC\uD568) [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` (\uC608: `A`, `A OK`) \uC751\uB2F5\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589 (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
134
+ "context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uC815\uCC45\uC740 \uC138\uC158 \uC2DC\uC791(\uB610\uB294 context \uC555\uCD95/\uB9AC\uC14B \uC9C1\uD6C4)\uC5D0 1\uD68C \uD655\uC778\uD558\uACE0, \uC774\uD6C4\uC5D0\uB294 \uC815\uCC45/\uC124\uC815 \uBCC0\uACBD \uB610\uB294 \uC0AC\uC6A9\uC790 \uC0C8\uB85C\uACE0\uCE68 \uC694\uCCAD \uC2DC\uC5D0\uB9CC \uC7AC\uD655\uC778\uD558\uC138\uC694. (git push/merge/merge commit \uD3EC\uD568) [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB77C\uBCA8 \uD1A0\uD070\uC774 \uD3EC\uD568\uB41C \uC751\uB2F5(\uC608: `A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589 (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
135
135
  "context.actionOptionHint": "\uC2B9\uC778 \uC751\uB2F5 \uD615\uC2DD: \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 (\uC608: `A`, `A OK`, `A \uC9C4\uD589\uD574`)",
136
136
  "context.actionExplainHint": "\uC2B9\uC778 \uC694\uCCAD \uC804, \uAC01 \uB77C\uBCA8\uC774 \uBB34\uC5C7\uC744 \uC2E4\uD589/\uBCC0\uACBD\uD558\uB294\uC9C0 \uD55C \uC904 \uC694\uC57D\uACFC \uD568\uAED8 \uC124\uBA85\uD558\uC138\uC694.",
137
- "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example})",
137
+ "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example}, `A \uC9C4\uD589\uD574`)",
138
138
  "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
139
139
  "context.suggestionCommandHint": "\uB77C\uBCA8 \uCC38\uACE0 \uBA85\uB839: {command}",
140
- "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example})",
140
+ "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example}, `A \uC9C4\uD589\uD574`)",
141
141
  "context.suggestion.createFeature": "\uC0C8 Feature\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4",
142
142
  "context.suggestion.showDone": "\uC644\uB8CC\uB41C Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
143
143
  "context.suggestion.showAll": "\uC804\uCCB4 Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
@@ -156,6 +156,8 @@ var I18N = {
156
156
  "context.list.completePrePrReview": "Pre-PR \uB9AC\uBDF0 \uC644\uB8CC \uCC98\uB9AC",
157
157
  "context.list.addPrePrFindings": "Pre-PR Findings \uD544\uB4DC/\uAC12 \uBCF4\uC644",
158
158
  "context.list.addPrePrEvidence": "Pre-PR Evidence \uADFC\uAC70 \uCD94\uAC00",
159
+ "context.list.addPrReviewFindings": "PR \uB9AC\uBDF0 Findings \uD544\uB4DC/\uAC12 \uBCF4\uC644",
160
+ "context.list.addPrReviewEvidence": "PR \uB9AC\uBDF0 Evidence \uADFC\uAC70 \uCD94\uAC00",
159
161
  "context.list.resolvePrePrMajorFindings": "Pre-PR \uC8FC\uC694 Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
160
162
  "context.list.resolvePrePrMinorFindings": "Pre-PR minor Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
161
163
  "context.list.setPrStatus": "PR \uC0C1\uD0DC \uC124\uC815",
@@ -419,9 +421,9 @@ var I18N = {
419
421
  tasksImprove: "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
420
422
  tasksApproval: "tasks.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC9C4\uD589 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC73C\uC138\uC694. (\uC2B9\uC778 \uD6C4 \uBB38\uC11C \uC0C1\uD0DC\uB97C Approved\uB85C \uBCC0\uACBD)",
421
423
  docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
422
- issueCreateAndWrite: "\uC774\uC288 \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694.",
424
+ issueCreateAndWrite: "\uC774\uC288 \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694.",
423
425
  issuePrepareFromDoc: "`issue.md`\uB97C \uAE30\uC900\uC73C\uB85C \uC774\uC288 \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC544 \uC0C1\uD0DC\uB97C `Ready`\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
424
- issueCreateFromDoc: "`issue.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 GitHub Issue\uB97C \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C \uC774\uC288 \uBC88\uD638\uB97C `issue.md`\uC640 `spec.md/tasks.md`\uC5D0 \uBC18\uC601\uD558\uC138\uC694.",
426
+ issueCreateFromDoc: "`issue.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 GitHub Issue\uB97C \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C \uC774\uC288 \uBC88\uD638\uB97C `tasks.md`\uC5D0 \uBC18\uC601\uD558\uC138\uC694.",
425
427
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
426
428
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
427
429
  projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uBC88 \uD0DC\uC2A4\uD06C\uC5D0\uC11C \uC218\uC815\uD55C \uD30C\uC77C\uB9CC \uC120\uD0DD\uD574 git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
@@ -437,30 +439,40 @@ var I18N = {
437
439
  checkTaskStatuses: "\uD0DC\uC2A4\uD06C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. ({done}/{total})",
438
440
  taskCommitGateStrictBlock: "\uB2E4\uC74C TODO \uD0DC\uC2A4\uD06C\uB85C \uB118\uC5B4\uAC00\uAE30 \uC804\uC5D0 `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B` \uADDC\uCE59\uC744 \uCDA9\uC871\uD574\uC57C \uD569\uB2C8\uB2E4. \uC810\uAC80 \uACB0\uACFC: {reason}. \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694.",
439
441
  taskCommitGateWarnProceed: "\u26A0\uFE0F \uD0DC\uC2A4\uD06C \uCEE4\uBC0B \uB2E8\uC704 \uC810\uAC80 \uACBD\uACE0: {reason}. \uD604\uC7AC\uB294 \uC9C4\uD589 \uAC00\uB2A5\uD558\uC9C0\uB9CC `1 \uD0DC\uC2A4\uD06C = 1 \uCEE4\uBC0B`\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
440
- taskCommitGateReasonNoTasksCommit: "\uCD5C\uADFC tasks.md \uCEE4\uBC0B\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
441
- taskCommitGateReasonTasksFileUnavailable: "\uCD5C\uADFC \uCEE4\uBC0B\uC5D0\uC11C tasks.md \uC774\uB825\uC744 \uD310\uB3C5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
442
- taskCommitGateReasonDoneCount: "\uCD5C\uADFC tasks.md \uCEE4\uBC0B\uC758 DONE \uC804\uD658 \uC218\uAC00 {count}\uAC1C\uC785\uB2C8\uB2E4 (\uC815\uC0C1: 1\uAC1C)",
443
- taskCommitGateReasonMismatchLastDone: "\uCD5C\uADFC tasks.md \uCEE4\uBC0B\uC774 \uC9C1\uC804 \uC644\uB8CC \uD0DC\uC2A4\uD06C\uC640 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
442
+ taskCommitGateReasonNoTasksCommit: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
443
+ taskCommitGateReasonTasksFileUnavailable: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B \uC774\uB825\uC744 \uD310\uB3C5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
444
+ taskCommitGateReasonDoneCount: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B \uC810\uAC80 \uACB0\uACFC\uAC00 \uC608\uC0C1\uACFC \uB2E4\uB985\uB2C8\uB2E4 ({count})",
445
+ 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",
444
446
  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)",
445
447
  prePrReviewFieldMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0**: Pending | Done` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
446
448
  prePrReviewFindingsMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0 Findings` \uD544\uB4DC\uAC00 \uC5C6\uAC70\uB098 \uAC12 \uD615\uC2DD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
447
449
  prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 placeholder\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uADFC\uAC70(\uBB38\uC11C \uACBD\uB85C/\uB9C1\uD06C/\uB85C\uADF8)\uB97C \uCC44\uC6B0\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
448
450
  prePrReviewMajorBlocked: "Pre-PR \uC8FC\uC694 Findings\uAC00 {count}\uAC74\uC73C\uB85C \uAE30\uB85D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `blockOnFindings=true` \uC815\uCC45\uC5D0\uC11C\uB294 \uC8FC\uC694 \uC774\uC288 \uD574\uACB0/\uD569\uC758 \uC804 PR \uC0DD\uC131\uC73C\uB85C \uC9C4\uD589\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
449
451
  prePrReviewMinorBlocked: "Pre-PR minor Findings\uAC00 {count}\uAC74\uC73C\uB85C \uAE30\uB85D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `minorPolicy=block` \uC815\uCC45\uC5D0\uC11C\uB294 minor \uC774\uC288 \uC815\uB9AC/\uD569\uC758 \uC804 PR \uC0DD\uC131\uC73C\uB85C \uC9C4\uD589\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
450
- prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9). \uC2A4\uD0AC\uC744 \uC4F8 \uC218 \uC5C6\uC73C\uBA74 `{fallback}` \uC815\uCC45\uC73C\uB85C \uC9C4\uD589\uD558\uACE0 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. Major \uC815\uCC45: {findingsPolicy}. Minor \uC815\uCC45: {minorFindingsPolicy}",
452
+ prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 `{fallback}`\uC774\uBA70, `create-pr` \uBB38\uC11C\uC758 `Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8` \uC139\uC158\uC744 \uD56D\uC0C1 \uC218\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9)\uB85C \uCD94\uAC00 \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC644\uB8CC \uD6C4 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. Major \uC815\uCC45: {findingsPolicy}. Minor \uC815\uCC45: {minorFindingsPolicy}",
451
453
  prePrReviewFindingsBlock: "\uC911\uC694 \uC774\uC288\uB294 \uC218\uC815/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
452
454
  prePrReviewFindingsWarn: "\uB9AC\uC2A4\uD06C\uB97C \uACF5\uC720\uD558\uBA74 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
453
455
  prePrReviewMinorFindingsBlock: "minor \uC774\uC288\uB3C4 \uC815\uB9AC/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
454
456
  prePrReviewMinorFindingsWarn: "minor \uC774\uC288\uB294 \uAE30\uB85D/\uACF5\uC720 \uD6C4 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
457
+ prReviewFindingsFieldMissing: "tasks.md\uC5D0 `PR \uB9AC\uBDF0 Findings` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
458
+ prReviewFindingsMissing: "tasks.md\uC758 `PR \uB9AC\uBDF0 Findings` \uAC12\uC774 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
459
+ prReviewEvidenceFieldMissing: "tasks.md\uC5D0 `PR \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Evidence**: -` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
460
+ prReviewEvidenceMissing: "tasks.md\uC758 `PR \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 placeholder\uC785\uB2C8\uB2E4. \uC2E4\uC81C\uB85C \uD574\uACB0/\uD569\uC758\uD55C \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uADFC\uAC70(\uB9C1\uD06C/\uB85C\uADF8/\uBB38\uC11C)\uB97C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
455
461
  prCreate: "PR \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBCC0\uACBD \uC0AC\uD56D/\uD14C\uC2A4\uD2B8 \uC139\uC158\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 PR\uC744 \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 tasks.md\uC5D0 PR \uB9C1\uD06C\uB97C \uAE30\uB85D\uD558\uC138\uC694.",
456
462
  prCreatePrepareFromDoc: "`pr.md`\uB97C \uAE30\uC900\uC73C\uB85C PR \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC544 \uC0C1\uD0DC\uB97C `Ready`\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
457
- prCreateExecuteFromDoc: "`pr.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C/PR \uC0C1\uD0DC\uB97C `pr.md`\uC640 `tasks.md`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.",
463
+ prCreateExecuteFromDoc: "`pr.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C/PR \uC0C1\uD0DC\uB97C `tasks.md`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694. (`pr.md`\uB294 \uC0C1\uD0DC `Ready`\uB9CC \uC720\uC9C0)",
458
464
  prCreatePrepare: "PR \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBCC0\uACBD \uC0AC\uD56D/\uD14C\uC2A4\uD2B8 \uC139\uC158\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, PR \uC0DD\uC131 \uC804 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
459
465
  prCreateExecute: "\uD655\uC815\uB41C PR \uBCF8\uBB38\uC73C\uB85C PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C\uB97C tasks.md\uC758 PR \uD544\uB4DC\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.",
460
466
  prCreateRequiredSequence: "PR \uC0DD\uC131\uC740 \uD544\uC218 2\uB2E8\uACC4\uC785\uB2C8\uB2E4: (1) PR \uBCF8\uBB38 \uD15C\uD50C\uB9BF \uC0DD\uC131/\uBCF4\uC644 + \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK), (2) PR \uC0DD\uC131 + tasks.md PR \uB9C1\uD06C \uAE30\uB85D. \uC704 \uC21C\uC11C\uB97C \uBAA8\uB450 \uC644\uB8CC\uD558\uC138\uC694.",
461
467
  prFillStatus: "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694. (PR \uC0DD\uC131/\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C\uB294 Review\uB97C \uC720\uC9C0\uD569\uB2C8\uB2E4.)",
462
468
  prResolveReview: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uB294 \uB3D9\uC548 PR \uC0C1\uD0DC\uB294 Review\uB85C \uC720\uC9C0\uD558\uC138\uC694. \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD0DC\uC2A4\uD06C\uBA85\uC774 \uC544\uB2C8\uB77C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694. \uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uBA74 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uC131\uACF5 \uC2DC PR \uC0C1\uD0DC\uAC00 Approved\uB85C \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.)",
463
- prReviewResolve: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uB294 \uB3D9\uC548 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC720\uC9C0\uD558\uC138\uC694. \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD0DC\uC2A4\uD06C\uBA85\uC774 \uC544\uB2C8\uB77C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694.",
469
+ prReviewResolve: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uBA3C\uC800 \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815 \uC791\uC5C5\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uC9C4\uD589 \uC911\uC5D0\uB294 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC720\uC9C0\uD558\uC138\uC694. \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD0DC\uC2A4\uD06C\uBA85\uC774 \uC544\uB2C8\uB77C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694. `PR \uB9AC\uBDF0 Findings/Evidence`\uB97C \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uACE0, \uCEE4\uBC0B \uD6C4 \uC6D0\uACA9 \uBC18\uC601(push)\uB3C4 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589\uD558\uC138\uC694.",
470
+ prReviewPush: '\uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uC6D0\uACA9 PR \uBE0C\uB79C\uCE58\uC5D0 \uBC18\uC601\uD558\uB824\uBA74 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 `cd "{projectGitCwd}" && git push`\uB97C \uC2E4\uD589\uD558\uC138\uC694.',
471
+ prReviewRemoteBlocked: "\uC6D0\uACA9 PR \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uACB0\uACFC \uC544\uC9C1 \uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: {reasons}. \uB9AC\uBDF0 \uCF54\uBA58\uD2B8/\uCCB4\uD06C \uC0C1\uD0DC\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
472
+ prReviewRemoteReasonChangesRequested: "\uB9AC\uBDF0 \uC2B9\uC778 \uC0C1\uD0DC\uAC00 \uBCC0\uACBD \uC694\uCCAD \uB610\uB294 \uCD94\uAC00 \uB9AC\uBDF0 \uD544\uC694 \uC0C1\uD0DC\uC785\uB2C8\uB2E4",
473
+ prReviewRemoteReasonChecksFailing: "\uC2E4\uD328\uD55C \uCCB4\uD06C\uAC00 {count}\uAC74 \uC788\uC2B5\uB2C8\uB2E4",
474
+ prReviewRemoteReasonChecksPending: "\uB300\uAE30 \uC911\uC778 \uCCB4\uD06C\uAC00 {count}\uAC74 \uC788\uC2B5\uB2C8\uB2E4",
475
+ prReviewRemoteReasonMergeBlocked: "\uBA38\uC9C0 \uC0C1\uD0DC\uAC00 `{status}`\uB85C \uCC28\uB2E8\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4",
464
476
  prReviewMerge: "\uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uBA74 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uC131\uACF5 \uC2DC PR \uC0C1\uD0DC\uAC00 Approved\uB85C \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.)",
465
477
  prRequestReview: "\uB9AC\uBDF0\uC5B4\uC5D0\uAC8C \uB9AC\uBDF0\uB97C \uC694\uCCAD\uD558\uACE0 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815/\uC720\uC9C0\uD558\uC138\uC694.",
466
478
  featureDone: "\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC694\uAD6C\uC0AC\uD56D\uACFC \uBAA8\uB4E0 \uD0DC\uC2A4\uD06C/\uC644\uB8CC \uC870\uAC74\uC774 \uCDA9\uC871\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774 Feature\uB294 \uC644\uB8CC \uC0C1\uD0DC\uC785\uB2C8\uB2E4.",
@@ -477,13 +489,20 @@ var I18N = {
477
489
  legacyTasksPrePrReviewField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`)",
478
490
  legacyTasksPrePrFindingsField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Findings` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0 Findings**: major=0, minor=0`)",
479
491
  legacyTasksPrePrEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
492
+ legacyTasksPrReviewFindingsField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Findings` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0`)",
493
+ legacyTasksPrReviewEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
480
494
  workflowSpecNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC spec.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (spec.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
481
495
  workflowPlanNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC plan.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (plan.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
482
- workflowIssueMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC \uC774\uC288 \uBC88\uD638\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uC138\uC694.)",
496
+ workflowIssueMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC \uC774\uC288 \uBC88\uD638\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uC138\uC694.)",
483
497
  workflowProjectUncommittedChanges: "\uC644\uB8CC \uC870\uAC74 \uC774\uC804\uC5D0 \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uBCC0\uACBD\uC0AC\uD56D\uC744 \uCEE4\uBC0B\uD574\uC57C \uD569\uB2C8\uB2E4. (\uD504\uB85C\uC81D\uD2B8 \uC6CC\uD06C\uD2B8\uB9AC \uBBF8\uCEE4\uBC0B \uBCC0\uACBD \uC874\uC7AC)",
484
498
  workflowPrLinkMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uB9C1\uD06C\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uD544\uB4DC\uB97C \uCC44\uC6B0\uC138\uC694.)",
485
499
  workflowPrStatusMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (PR \uC0DD\uC131/\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C\uB294 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694.)",
486
500
  workflowPrStatusNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (PR \uC0DD\uC131/\uB9AC\uBDF0 \uB2E8\uACC4\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0, merge \uC131\uACF5 \uC2DC\uC5D0\uB9CC Approved\uB85C \uB3D9\uAE30\uD654\uD558\uC138\uC694.)",
501
+ workflowPrReviewFindingsMissing: "\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C `PR \uB9AC\uBDF0 Findings`\uAC00 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`major=0, minor=0` \uD615\uC2DD)",
502
+ workflowPrReviewEvidenceMissing: "\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C `PR \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (\uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uCC98\uB9AC \uADFC\uAC70\uB97C \uAE30\uB85D\uD558\uC138\uC694.)",
503
+ workflowPrRemoteChangesRequested: "\uC6D0\uACA9 PR\uC5D0\uC11C \uBCC0\uACBD \uC694\uCCAD \uB610\uB294 \uCD94\uAC00 \uB9AC\uBDF0\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCF54\uBA58\uD2B8 \uBC18\uC601 \uD6C4 push\uD558\uACE0 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
504
+ workflowPrRemoteChecksFailing: "\uC6D0\uACA9 PR \uCCB4\uD06C \uC2E4\uD328\uAC00 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC2E4\uD328 \uC6D0\uC778\uC744 \uD574\uACB0 \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
505
+ workflowPrRemoteChecksPending: "\uC6D0\uACA9 PR \uCCB4\uD06C \uB300\uAE30\uAC00 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCCB4\uD06C \uC644\uB8CC \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
487
506
  workflowPrePrReviewMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. (tasks.md\uC5D0 `- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`\uC744 \uCD94\uAC00\uD558\uC138\uC694.)",
488
507
  workflowPrePrReviewNotDone: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0`\uAC00 Done\uC774 \uC544\uB2D9\uB2C8\uB2E4. (\uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0 \uD6C4 Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
489
508
  workflowPrePrFindingsMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Findings`\uAC00 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`major=0, minor=0` \uD615\uC2DD)",
@@ -562,13 +581,13 @@ var I18N = {
562
581
  "context.tipShowAll": "Show all",
563
582
  "context.tipShowDone": "Show done only",
564
583
  "context.checkRequired": "[CHECK required] ",
565
- "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for `<label>` or `<label> OK` (e.g. `A`, `A OK`) before proceeding (config: approval can override)",
584
+ "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for a reply that includes a label token (e.g. `A`, `A OK`, `A proceed`) before proceeding (config: approval can override)",
566
585
  "context.actionOptionHint": "Approval reply format: include a label token (e.g. `A`, `A OK`, `A proceed`)",
567
586
  "context.actionExplainHint": "Before requesting approval, explain what each label will run/change with a one-line summary.",
568
- "context.finalLabelPrompt": "Available labels now: {labels}. Please reply in `<label>` or `<label> OK` format. (e.g. {example})",
587
+ "context.finalLabelPrompt": "Available labels now: {labels}. Please reply with a format that includes a label token. (e.g. {example}, `A proceed`)",
569
588
  "context.suggestionHeader": "Suggested Next Options",
570
589
  "context.suggestionCommandHint": "Reference command: {command}",
571
- "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply in `<label>` or `<label> OK` format. (e.g. {example})",
590
+ "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply with a format that includes a label token. (e.g. {example}, `A proceed`)",
572
591
  "context.suggestion.createFeature": "Create a new feature",
573
592
  "context.suggestion.showDone": "Show completed features",
574
593
  "context.suggestion.showAll": "Show all features",
@@ -587,6 +606,8 @@ var I18N = {
587
606
  "context.list.completePrePrReview": "Complete Pre-PR review",
588
607
  "context.list.addPrePrFindings": "Add/fill Pre-PR Findings",
589
608
  "context.list.addPrePrEvidence": "Add Pre-PR Evidence",
609
+ "context.list.addPrReviewFindings": "Add/fill PR Review Findings",
610
+ "context.list.addPrReviewEvidence": "Add PR Review Evidence",
590
611
  "context.list.resolvePrePrMajorFindings": "Resolve major pre-PR findings ({count})",
591
612
  "context.list.resolvePrePrMinorFindings": "Resolve minor pre-PR findings ({count})",
592
613
  "context.list.setPrStatus": "Set PR Status",
@@ -850,9 +871,9 @@ var I18N = {
850
871
  tasksImprove: "Improve tasks.md and change Doc Status to Review.",
851
872
  tasksApproval: "Share tasks.md with the user and get progress approval (`A` or `A OK` format). (Then set Doc Status to Approved)",
852
873
  docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
853
- issueCreateAndWrite: "Generate the issue body template, refine goals/completion criteria, get explicit user OK, create the issue, then update issue number in spec.md/tasks.md and prepare a docs commit.",
874
+ issueCreateAndWrite: "Generate the issue body template, refine goals/completion criteria, get explicit user OK, create the issue, then update issue number in tasks.md and prepare a docs commit.",
854
875
  issuePrepareFromDoc: "Use `issue.md` to refine issue title/body/labels draft, get explicit user OK, then set status to `Ready`.",
855
- issueCreateFromDoc: "When `issue.md` status is `Ready`, create the GitHub Issue and sync the created issue number into `issue.md` and `spec.md/tasks.md`.",
876
+ issueCreateFromDoc: "When `issue.md` status is `Ready`, create the GitHub Issue and sync the created issue number into `tasks.md`.",
856
877
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
857
878
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} docs update"',
858
879
  projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files changed in this task with git add [files], then run again." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
@@ -868,30 +889,40 @@ var I18N = {
868
889
  checkTaskStatuses: "Check task statuses. ({done}/{total})",
869
890
  taskCommitGateStrictBlock: "Before moving to the next TODO task, you must satisfy the `1 task = 1 commit` rule. Check result: {reason}. Re-align task commit boundaries, then continue.",
870
891
  taskCommitGateWarnProceed: "\u26A0\uFE0F Task commit boundary warning: {reason}. You may continue, but `1 task = 1 commit` is recommended.",
871
- taskCommitGateReasonNoTasksCommit: "No recent tasks.md commit was found",
872
- taskCommitGateReasonTasksFileUnavailable: "Cannot read tasks.md history from the latest commit",
873
- taskCommitGateReasonDoneCount: "DONE transitions in the latest tasks.md commit: {count} (expected: 1)",
874
- taskCommitGateReasonMismatchLastDone: "The latest tasks.md commit does not match the last completed task",
892
+ taskCommitGateReasonNoTasksCommit: "No recent project code commit was found",
893
+ taskCommitGateReasonTasksFileUnavailable: "Cannot read recent project code commit history",
894
+ taskCommitGateReasonDoneCount: "Project commit gate check result is unexpected ({count})",
895
+ taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
875
896
  prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
876
897
  prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
877
898
  prePrReviewFindingsMissing: "tasks.md is missing `Pre-PR Findings` or uses an invalid format. Record it as `- **Pre-PR Findings**: major=0, minor=0`. (CHECK required)",
878
899
  prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty or placeholder. Add concrete review evidence (doc path/link/log). (CHECK required)",
879
900
  prePrReviewMajorBlocked: "Pre-PR major findings are recorded ({count}). With `blockOnFindings=true`, PR creation is blocked until major findings are resolved/aligned.",
880
901
  prePrReviewMinorBlocked: "Pre-PR minor findings are recorded ({count}). With `minorPolicy=block`, PR creation is blocked until minor findings are resolved/aligned.",
881
- prePrReviewRun: "Run a pre-PR code review before creating the PR. Preferred skills: {skills} (if a better installed skill fits this change, propose it first). If no skill can run, use `{fallback}` and set `Pre-PR Review` to Done in tasks.md. Major policy: {findingsPolicy}. Minor policy: {minorFindingsPolicy}",
902
+ prePrReviewRun: "Run a pre-PR code review before creating the PR. Always execute the `{fallback}` baseline by following the `Pre-PR Baseline Checklist` section in the `create-pr` doc. Then use preferred skills ({skills}) for deeper review (if a better installed skill fits this change, propose it first). After completing it, set `Pre-PR Review` to Done in tasks.md. Major policy: {findingsPolicy}. Minor policy: {minorFindingsPolicy}",
882
903
  prePrReviewFindingsBlock: "major findings must be fixed/aligned before PR creation",
883
904
  prePrReviewFindingsWarn: "you may proceed after sharing the risks",
884
905
  prePrReviewMinorFindingsBlock: "minor findings must also be fixed/aligned before PR creation",
885
906
  prePrReviewMinorFindingsWarn: "you may proceed after documenting/sharing minor risks",
907
+ prReviewFindingsFieldMissing: "tasks.md is missing the `PR Review Findings` field. Add `- **PR Review Findings**: major=0, minor=0` and continue. (CHECK required)",
908
+ prReviewFindingsMissing: "tasks.md `PR Review Findings` is missing or invalid. Record it as `- **PR Review Findings**: major=0, minor=0`. (CHECK required)",
909
+ prReviewEvidenceFieldMissing: "tasks.md is missing the `PR Review Evidence` field. Add `- **PR Review Evidence**: -` and continue. (CHECK required)",
910
+ prReviewEvidenceMissing: "tasks.md `PR Review Evidence` is empty or placeholder. Record concrete evidence for resolved/aligned review comments. (CHECK required)",
886
911
  prCreate: "Generate the PR body template, refine changes/tests sections, get explicit user OK, create the PR, then record the PR link in tasks.md.",
887
912
  prCreatePrepareFromDoc: "Use `pr.md` to refine PR title/body/labels draft, get explicit user OK, then set status to `Ready`.",
888
- prCreateExecuteFromDoc: "When `pr.md` status is `Ready`, create the PR and record the PR link/status in `pr.md` and `tasks.md`.",
913
+ prCreateExecuteFromDoc: "When `pr.md` status is `Ready`, create the PR and record the PR link/status in `tasks.md`. (Keep only `pr.md` status as `Ready`.)",
889
914
  prCreatePrepare: "Generate the PR body template, refine changes/tests sections, and get explicit user OK before PR creation.",
890
915
  prCreateExecute: "Create the PR with the finalized body, then record the created PR link in tasks.md.",
891
916
  prCreateRequiredSequence: "PR creation is a required 2-step sequence: (1) generate/refine PR body template + explicit user OK, (2) create PR + record PR link in tasks.md. Complete both in order.",
892
917
  prFillStatus: "Set PR Status in tasks.md to Review. (Keep Review during PR creation/review stages.)",
893
918
  prResolveReview: "Keep PR Status as Review while addressing comments. For review-fix commits, use commit messages that summarize resolved review feedback (not task titles). Once ready to merge, get explicit user OK and run `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`. (On success, PR Status is synced to Approved.)",
894
- prReviewResolve: "Keep PR Status as Review while addressing comments. For review-fix commits, use commit messages that summarize resolved review feedback (not task titles).",
919
+ prReviewResolve: "First review/analyze the PR comments, then apply the required fixes. Keep PR Status as Review while addressing comments. For review-fix commits, use commit messages that summarize resolved review feedback (not task titles). Keep `PR Review Findings/Evidence` updated, then run push only after explicit user OK.",
920
+ prReviewPush: 'To reflect review-fix commits on the PR head branch, get explicit user OK and run `cd "{projectGitCwd}" && git push`.',
921
+ prReviewRemoteBlocked: "Remote PR checks indicate this PR is not ready to merge yet: {reasons}. Resolve review comments/check statuses, then re-check.",
922
+ prReviewRemoteReasonChangesRequested: "review decision is changes requested or additional review required",
923
+ prReviewRemoteReasonChecksFailing: "{count} failing check(s) detected",
924
+ prReviewRemoteReasonChecksPending: "{count} pending check(s) detected",
925
+ prReviewRemoteReasonMergeBlocked: "merge state is blocked (`{status}`)",
895
926
  prReviewMerge: "When ready to merge, get explicit user OK and run `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`. (On success, PR Status is synced to Approved.)",
896
927
  prRequestReview: "Request review and set/keep PR Status as Review.",
897
928
  featureDone: "Workflow requirements and all tasks/completion criteria are satisfied. This feature is done.",
@@ -908,13 +939,20 @@ var I18N = {
908
939
  legacyTasksPrePrReviewField: "Legacy tasks.md format detected. Add `Pre-PR Review` before PR steps. (`- **Pre-PR Review**: Pending | Done`)",
909
940
  legacyTasksPrePrFindingsField: "Legacy tasks.md format detected. Add `Pre-PR Findings` before PR steps. (`- **Pre-PR Findings**: major=0, minor=0`)",
910
941
  legacyTasksPrePrEvidenceField: "Legacy tasks.md format detected. Add `Pre-PR Evidence` before PR steps.",
942
+ legacyTasksPrReviewFindingsField: "Legacy tasks.md format detected. Add `PR Review Findings` before review iteration. (`- **PR Review Findings**: major=0, minor=0`)",
943
+ legacyTasksPrReviewEvidenceField: "Legacy tasks.md format detected. Add `PR Review Evidence` before review iteration.",
911
944
  workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
912
945
  workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
913
- workflowIssueMissing: "Implementation is done but Issue Number is missing. (Fill Issue Number in spec.md/tasks.md.)",
946
+ workflowIssueMissing: "Implementation is done but Issue Number is missing. (Fill Issue Number in tasks.md.)",
914
947
  workflowProjectUncommittedChanges: "Commit project code changes before completing workflow. (Project worktree has uncommitted changes.)",
915
948
  workflowPrLinkMissing: "Implementation is done but PR link is missing. (Fill the PR field in tasks.md.)",
916
949
  workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Review during PR creation/review stages.)",
917
950
  workflowPrStatusNotApproved: "Implementation is done but PR Status is not Approved. (Keep PR Status as Review before merge and sync to Approved only after successful merge.)",
951
+ workflowPrReviewFindingsMissing: "In review stage, `PR Review Findings` is missing or invalid. (Use `major=0, minor=0` format.)",
952
+ workflowPrReviewEvidenceMissing: "In review stage, `PR Review Evidence` is empty. (Record evidence for review comment handling.)",
953
+ workflowPrRemoteChangesRequested: "Remote PR shows changes requested or additional review required. Address comments, push, then re-check.",
954
+ workflowPrRemoteChecksFailing: "Remote PR has {count} failing check(s). Fix failures, then re-check.",
955
+ workflowPrRemoteChecksPending: "Remote PR has {count} pending check(s). Wait for checks to complete, then re-check.",
918
956
  workflowPrePrReviewMissing: "Implementation is done but `Pre-PR Review` is missing. (Add `- **Pre-PR Review**: Pending | Done` in tasks.md.)",
919
957
  workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)",
920
958
  workflowPrePrFindingsMissing: "Implementation is done but `Pre-PR Findings` is missing or invalid. (Use `major=0, minor=0` format.)",
@@ -1307,10 +1345,10 @@ function sleep(ms) {
1307
1345
  return new Promise((resolve) => globalThis.setTimeout(resolve, ms));
1308
1346
  }
1309
1347
  function toScopeKey(value) {
1310
- return createHash("sha1").update(path18.resolve(value)).digest("hex").slice(0, 16);
1348
+ return createHash("sha1").update(path19.resolve(value)).digest("hex").slice(0, 16);
1311
1349
  }
1312
1350
  function getTempRuntimeDir(scopePath) {
1313
- return path18.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1351
+ return path19.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1314
1352
  }
1315
1353
  function resolveGitRuntimeDir(cwd) {
1316
1354
  try {
@@ -1324,38 +1362,38 @@ function resolveGitRuntimeDir(cwd) {
1324
1362
  }
1325
1363
  ).trim();
1326
1364
  if (!out) return null;
1327
- return path18.isAbsolute(out) ? out : path18.resolve(cwd, out);
1365
+ return path19.isAbsolute(out) ? out : path19.resolve(cwd, out);
1328
1366
  } catch {
1329
1367
  return null;
1330
1368
  }
1331
1369
  }
1332
1370
  function getRuntimeStateDir(cwd) {
1333
- const resolved = path18.resolve(cwd);
1371
+ const resolved = path19.resolve(cwd);
1334
1372
  return resolveGitRuntimeDir(resolved) ?? getTempRuntimeDir(resolved);
1335
1373
  }
1336
1374
  function getDocsLockPath(docsDir) {
1337
- return path18.join(
1375
+ return path19.join(
1338
1376
  getRuntimeStateDir(docsDir),
1339
1377
  "locks",
1340
1378
  `docs-${toScopeKey(docsDir)}.lock`
1341
1379
  );
1342
1380
  }
1343
1381
  function getInitLockPath(targetDir) {
1344
- return path18.join(
1345
- getRuntimeStateDir(path18.dirname(path18.resolve(targetDir))),
1382
+ return path19.join(
1383
+ getRuntimeStateDir(path19.dirname(path19.resolve(targetDir))),
1346
1384
  "locks",
1347
1385
  `init-${toScopeKey(targetDir)}.lock`
1348
1386
  );
1349
1387
  }
1350
1388
  function getApprovalTicketStorePath(docsDir) {
1351
- return path18.join(
1389
+ return path19.join(
1352
1390
  getRuntimeStateDir(docsDir),
1353
1391
  "tickets",
1354
1392
  `approval-${toScopeKey(docsDir)}.json`
1355
1393
  );
1356
1394
  }
1357
1395
  function getProjectExecutionLockPath(cwd) {
1358
- return path18.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1396
+ return path19.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1359
1397
  }
1360
1398
  async function isStaleLock(lockPath, staleMs) {
1361
1399
  try {
@@ -1396,7 +1434,7 @@ function isProcessAlive(pid) {
1396
1434
  }
1397
1435
  }
1398
1436
  async function tryAcquire(lockPath, owner) {
1399
- await fs15.ensureDir(path18.dirname(lockPath));
1437
+ await fs15.ensureDir(path19.dirname(lockPath));
1400
1438
  try {
1401
1439
  const fd = await fs15.open(lockPath, "wx");
1402
1440
  const payload = JSON.stringify(
@@ -1473,30 +1511,30 @@ var ENGINE_MANAGED_AGENT_FILES = [
1473
1511
  "pr-template.md"
1474
1512
  ];
1475
1513
  var ENGINE_MANAGED_AGENT_DIRS = ["skills"];
1476
- var ENGINE_MANAGED_FEATURE_PATH = path18.join(
1514
+ var ENGINE_MANAGED_FEATURE_PATH = path19.join(
1477
1515
  "features",
1478
1516
  "feature-base"
1479
1517
  );
1480
1518
  async function pruneEngineManagedDocs(docsDir) {
1481
1519
  const removed = [];
1482
1520
  for (const file of ENGINE_MANAGED_AGENT_FILES) {
1483
- const target = path18.join(docsDir, "agents", file);
1521
+ const target = path19.join(docsDir, "agents", file);
1484
1522
  if (await fs15.pathExists(target)) {
1485
1523
  await fs15.remove(target);
1486
- removed.push(path18.relative(docsDir, target));
1524
+ removed.push(path19.relative(docsDir, target));
1487
1525
  }
1488
1526
  }
1489
1527
  for (const dir of ENGINE_MANAGED_AGENT_DIRS) {
1490
- const target = path18.join(docsDir, "agents", dir);
1528
+ const target = path19.join(docsDir, "agents", dir);
1491
1529
  if (await fs15.pathExists(target)) {
1492
1530
  await fs15.remove(target);
1493
- removed.push(path18.relative(docsDir, target));
1531
+ removed.push(path19.relative(docsDir, target));
1494
1532
  }
1495
1533
  }
1496
- const featureBasePath = path18.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1534
+ const featureBasePath = path19.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1497
1535
  if (await fs15.pathExists(featureBasePath)) {
1498
1536
  await fs15.remove(featureBasePath);
1499
- removed.push(path18.relative(docsDir, featureBasePath));
1537
+ removed.push(path19.relative(docsDir, featureBasePath));
1500
1538
  }
1501
1539
  return removed;
1502
1540
  }
@@ -1637,7 +1675,7 @@ ${tr(lang2, "cli", "common.canceled")}`)
1637
1675
  }
1638
1676
  async function runInit(options) {
1639
1677
  const cwd = process.cwd();
1640
- const defaultName = path18.basename(cwd);
1678
+ const defaultName = path19.basename(cwd);
1641
1679
  let projectName = options.name || defaultName;
1642
1680
  let projectType = options.type;
1643
1681
  let components = parseComponentsOption(options.components);
@@ -1650,7 +1688,7 @@ async function runInit(options) {
1650
1688
  const componentProjectRoots = parseComponentProjectRootsOption(
1651
1689
  options.componentProjectRoots
1652
1690
  );
1653
- const targetDir = path18.resolve(cwd, options.dir || "./docs");
1691
+ const targetDir = path19.resolve(cwd, options.dir || "./docs");
1654
1692
  const skipPrompts = !!options.yes || !!options.nonInteractive;
1655
1693
  if (options.docsRepo && !["embedded", "standalone"].includes(options.docsRepo)) {
1656
1694
  throw createCliError(
@@ -2039,7 +2077,7 @@ async function runInit(options) {
2039
2077
  );
2040
2078
  console.log();
2041
2079
  const templatesDir = getTemplatesDir();
2042
- const commonPath = path18.join(templatesDir, lang, "common");
2080
+ const commonPath = path19.join(templatesDir, lang, "common");
2043
2081
  if (!await fs15.pathExists(commonPath)) {
2044
2082
  throw new Error(
2045
2083
  tr(lang, "cli", "init.error.templateNotFound", { path: commonPath })
@@ -2047,11 +2085,11 @@ async function runInit(options) {
2047
2085
  }
2048
2086
  await copyTemplates(commonPath, targetDir);
2049
2087
  if (projectType === "multi") {
2050
- const featuresRoot = path18.join(targetDir, "features");
2088
+ const featuresRoot = path19.join(targetDir, "features");
2051
2089
  for (const component of components) {
2052
- const componentDir = path18.join(featuresRoot, component);
2090
+ const componentDir = path19.join(featuresRoot, component);
2053
2091
  await fs15.ensureDir(componentDir);
2054
- const readmePath = path18.join(componentDir, "README.md");
2092
+ const readmePath = path19.join(componentDir, "README.md");
2055
2093
  if (!await fs15.pathExists(readmePath)) {
2056
2094
  await fs15.writeFile(
2057
2095
  readmePath,
@@ -2104,7 +2142,7 @@ async function runInit(options) {
2104
2142
  config.projectRoot = projectRoot;
2105
2143
  }
2106
2144
  }
2107
- const configPath = path18.join(targetDir, ".lee-spec-kit.json");
2145
+ const configPath = path19.join(targetDir, ".lee-spec-kit.json");
2108
2146
  await fs15.writeJson(configPath, config, { spaces: 2 });
2109
2147
  console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
2110
2148
  console.log();
@@ -2151,7 +2189,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2151
2189
  }
2152
2190
  };
2153
2191
  const toGitPath = (input) => input.replace(/\\/g, "/").replace(/^\.\//, "");
2154
- const toRepoRelativePath2 = (workdir, relativePath2) => {
2192
+ const toRepoRelativePath = (workdir, relativePath2) => {
2155
2193
  if (relativePath2 === ".") return ".";
2156
2194
  try {
2157
2195
  const prefix = execFileSync("git", ["rev-parse", "--show-prefix"], {
@@ -2173,7 +2211,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2173
2211
  console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
2174
2212
  runGit(["init"], cwd);
2175
2213
  }
2176
- const relativePath = path18.relative(cwd, targetDir);
2214
+ const relativePath = path19.relative(cwd, targetDir);
2177
2215
  const stagedBeforeAdd = getCachedStagedFiles(cwd);
2178
2216
  if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
2179
2217
  console.log(
@@ -2186,7 +2224,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2186
2224
  return;
2187
2225
  }
2188
2226
  if (relativePath !== "." && isPathIgnored(cwd, relativePath)) {
2189
- const repoRelativePath = toRepoRelativePath2(cwd, relativePath);
2227
+ const repoRelativePath = toRepoRelativePath(cwd, relativePath);
2190
2228
  console.log(
2191
2229
  chalk6.yellow(
2192
2230
  tr(lang, "cli", "init.warn.docsPathIgnoredSkipCommit", {
@@ -2230,17 +2268,17 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2230
2268
  }
2231
2269
  function getAncestorDirs(startDir) {
2232
2270
  const dirs = [];
2233
- let current = path18.resolve(startDir);
2271
+ let current = path19.resolve(startDir);
2234
2272
  while (true) {
2235
2273
  dirs.push(current);
2236
- const parent = path18.dirname(current);
2274
+ const parent = path19.dirname(current);
2237
2275
  if (parent === current) break;
2238
2276
  current = parent;
2239
2277
  }
2240
2278
  return dirs;
2241
2279
  }
2242
2280
  function hasWorkspaceBoundary(dir) {
2243
- return fs15.existsSync(path18.join(dir, "package.json")) || fs15.existsSync(path18.join(dir, ".git"));
2281
+ return fs15.existsSync(path19.join(dir, "package.json")) || fs15.existsSync(path19.join(dir, ".git"));
2244
2282
  }
2245
2283
  function getSearchBaseDirs(cwd) {
2246
2284
  const ancestors = getAncestorDirs(cwd);
@@ -2256,7 +2294,7 @@ function normalizeComponentKeys(value) {
2256
2294
  return Object.keys(value).map((key) => key.trim().toLowerCase()).filter(Boolean);
2257
2295
  }
2258
2296
  async function inferComponentsFromFeaturesDir(docsDir) {
2259
- const featuresPath = path18.join(docsDir, "features");
2297
+ const featuresPath = path19.join(docsDir, "features");
2260
2298
  if (!await fs15.pathExists(featuresPath)) return [];
2261
2299
  const entries = await fs15.readdir(featuresPath, { withFileTypes: true });
2262
2300
  const inferred = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name.trim().toLowerCase()).filter(
@@ -2267,21 +2305,21 @@ async function inferComponentsFromFeaturesDir(docsDir) {
2267
2305
  async function getConfig(cwd) {
2268
2306
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2269
2307
  const baseDirs = [
2270
- ...explicitDocsDir ? [path18.resolve(explicitDocsDir)] : [],
2308
+ ...explicitDocsDir ? [path19.resolve(explicitDocsDir)] : [],
2271
2309
  ...getSearchBaseDirs(cwd)
2272
2310
  ];
2273
2311
  const visitedBaseDirs = /* @__PURE__ */ new Set();
2274
2312
  const visitedDocsDirs = /* @__PURE__ */ new Set();
2275
2313
  for (const baseDir of baseDirs) {
2276
- const resolvedBaseDir = path18.resolve(baseDir);
2314
+ const resolvedBaseDir = path19.resolve(baseDir);
2277
2315
  if (visitedBaseDirs.has(resolvedBaseDir)) continue;
2278
2316
  visitedBaseDirs.add(resolvedBaseDir);
2279
- const possibleDocsDirs = [path18.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2317
+ const possibleDocsDirs = [path19.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2280
2318
  for (const docsDir of possibleDocsDirs) {
2281
- const resolvedDocsDir = path18.resolve(docsDir);
2319
+ const resolvedDocsDir = path19.resolve(docsDir);
2282
2320
  if (visitedDocsDirs.has(resolvedDocsDir)) continue;
2283
2321
  visitedDocsDirs.add(resolvedDocsDir);
2284
- const configPath = path18.join(resolvedDocsDir, ".lee-spec-kit.json");
2322
+ const configPath = path19.join(resolvedDocsDir, ".lee-spec-kit.json");
2285
2323
  if (await fs15.pathExists(configPath)) {
2286
2324
  try {
2287
2325
  const configFile = await fs15.readJson(configPath);
@@ -2311,16 +2349,16 @@ async function getConfig(cwd) {
2311
2349
  } catch {
2312
2350
  }
2313
2351
  }
2314
- const agentsPath = path18.join(resolvedDocsDir, "agents");
2315
- const featuresPath = path18.join(resolvedDocsDir, "features");
2352
+ const agentsPath = path19.join(resolvedDocsDir, "agents");
2353
+ const featuresPath = path19.join(resolvedDocsDir, "features");
2316
2354
  if (await fs15.pathExists(agentsPath) && await fs15.pathExists(featuresPath)) {
2317
2355
  const inferredComponents = await inferComponentsFromFeaturesDir(resolvedDocsDir);
2318
2356
  const projectType = inferredComponents.length > 0 ? "multi" : "single";
2319
2357
  const components = projectType === "multi" ? resolveProjectComponents("multi", inferredComponents) : void 0;
2320
2358
  const langProbeCandidates = [
2321
- path18.join(agentsPath, "custom.md"),
2322
- path18.join(agentsPath, "constitution.md"),
2323
- path18.join(agentsPath, "agents.md")
2359
+ path19.join(agentsPath, "custom.md"),
2360
+ path19.join(agentsPath, "constitution.md"),
2361
+ path19.join(agentsPath, "agents.md")
2324
2362
  ];
2325
2363
  let lang = "en";
2326
2364
  for (const candidate of langProbeCandidates) {
@@ -2386,13 +2424,13 @@ async function patchMarkdownIfExists(filePath, transform) {
2386
2424
  await fs15.writeFile(filePath, transform(content), "utf-8");
2387
2425
  }
2388
2426
  async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
2389
- await patchMarkdownIfExists(path18.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2427
+ await patchMarkdownIfExists(path19.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2390
2428
  await patchMarkdownIfExists(
2391
- path18.join(featureDir, "tasks.md"),
2429
+ path19.join(featureDir, "tasks.md"),
2392
2430
  (content) => sanitizeTasksForLocal(content, lang)
2393
2431
  );
2394
- await fs15.remove(path18.join(featureDir, "issue.md"));
2395
- await fs15.remove(path18.join(featureDir, "pr.md"));
2432
+ await fs15.remove(path19.join(featureDir, "issue.md"));
2433
+ await fs15.remove(path19.join(featureDir, "pr.md"));
2396
2434
  }
2397
2435
 
2398
2436
  // src/commands/feature.ts
@@ -2537,19 +2575,19 @@ async function runFeature(name, options) {
2537
2575
  }
2538
2576
  let featuresDir;
2539
2577
  if (projectType === "multi") {
2540
- featuresDir = path18.join(docsDir, "features", component);
2578
+ featuresDir = path19.join(docsDir, "features", component);
2541
2579
  } else {
2542
- featuresDir = path18.join(docsDir, "features");
2580
+ featuresDir = path19.join(docsDir, "features");
2543
2581
  }
2544
2582
  const featureFolderName = `${featureId}-${name}`;
2545
- const featureDir = path18.join(featuresDir, featureFolderName);
2583
+ const featureDir = path19.join(featuresDir, featureFolderName);
2546
2584
  if (await fs15.pathExists(featureDir)) {
2547
2585
  throw createCliError(
2548
2586
  "INVALID_ARGUMENT",
2549
2587
  tr(lang, "cli", "feature.folderExists", { path: featureDir })
2550
2588
  );
2551
2589
  }
2552
- const featureBasePath = path18.join(
2590
+ const featureBasePath = path19.join(
2553
2591
  getTemplatesDir(),
2554
2592
  lang,
2555
2593
  "common",
@@ -2608,7 +2646,7 @@ async function runFeature(name, options) {
2608
2646
  featureName: name,
2609
2647
  component: projectType === "multi" ? component : void 0,
2610
2648
  featurePath: featureDir,
2611
- featurePathFromDocs: path18.relative(docsDir, featureDir)
2649
+ featurePathFromDocs: path19.relative(docsDir, featureDir)
2612
2650
  };
2613
2651
  },
2614
2652
  { owner: "feature" }
@@ -2620,9 +2658,9 @@ function sleep2(ms) {
2620
2658
  async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2621
2659
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2622
2660
  const candidates = [
2623
- ...explicitDocsDir ? [path18.resolve(explicitDocsDir)] : [],
2624
- path18.resolve(cwd, "docs"),
2625
- path18.resolve(cwd)
2661
+ ...explicitDocsDir ? [path19.resolve(explicitDocsDir)] : [],
2662
+ path19.resolve(cwd, "docs"),
2663
+ path19.resolve(cwd)
2626
2664
  ];
2627
2665
  const endAt = Date.now() + timeoutMs;
2628
2666
  while (Date.now() < endAt) {
@@ -2649,11 +2687,11 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2649
2687
  return getConfig(cwd);
2650
2688
  }
2651
2689
  async function getNextFeatureId(docsDir, projectType, components) {
2652
- const featuresDir = path18.join(docsDir, "features");
2690
+ const featuresDir = path19.join(docsDir, "features");
2653
2691
  let max = 0;
2654
2692
  const scanDirs = [];
2655
2693
  if (projectType === "multi") {
2656
- scanDirs.push(...components.map((component) => path18.join(featuresDir, component)));
2694
+ scanDirs.push(...components.map((component) => path19.join(featuresDir, component)));
2657
2695
  } else {
2658
2696
  scanDirs.push(featuresDir);
2659
2697
  }
@@ -2798,6 +2836,36 @@ function getFindingsPolicyText(lang, blockOnFindings) {
2798
2836
  function getMinorFindingsPolicyText(lang, minorPolicy) {
2799
2837
  return minorPolicy === "block" ? tr(lang, "messages", "prePrReviewMinorFindingsBlock") : tr(lang, "messages", "prePrReviewMinorFindingsWarn");
2800
2838
  }
2839
+ function getPrReviewRemoteBlockReasons(feature, lang) {
2840
+ const remote = feature.pr.remote;
2841
+ if (!remote || !remote.available) return [];
2842
+ const reasons = [];
2843
+ if (remote.hasBlockingReview) {
2844
+ reasons.push(tr(lang, "messages", "prReviewRemoteReasonChangesRequested"));
2845
+ }
2846
+ if (remote.failingChecks > 0) {
2847
+ reasons.push(
2848
+ tr(lang, "messages", "prReviewRemoteReasonChecksFailing", {
2849
+ count: remote.failingChecks
2850
+ })
2851
+ );
2852
+ }
2853
+ if (remote.pendingChecks > 0) {
2854
+ reasons.push(
2855
+ tr(lang, "messages", "prReviewRemoteReasonChecksPending", {
2856
+ count: remote.pendingChecks
2857
+ })
2858
+ );
2859
+ }
2860
+ if (remote.mergeBlocked) {
2861
+ reasons.push(
2862
+ tr(lang, "messages", "prReviewRemoteReasonMergeBlocked", {
2863
+ status: remote.mergeStateStatus || "UNKNOWN"
2864
+ })
2865
+ );
2866
+ }
2867
+ return reasons;
2868
+ }
2801
2869
  function normalizeCommitTopicText(value) {
2802
2870
  return value.replace(/\s+/g, " ").trim();
2803
2871
  }
@@ -2815,19 +2883,11 @@ function resolveProjectCommitTopic(feature) {
2815
2883
  }
2816
2884
  function shouldBlockTaskCommitGate(policy, check) {
2817
2885
  if (policy !== "strict") return false;
2818
- if (check.reason === "MULTIPLE_DONE_TRANSITIONS") {
2819
- return (check.newDoneCount ?? 0) > 1;
2820
- }
2821
- return false;
2886
+ return !check.pass;
2822
2887
  }
2823
2888
  function normalizeGitRelativePath(value) {
2824
2889
  return value.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
2825
2890
  }
2826
- function toRepoRelativePath(cwd, relativePathFromCwd) {
2827
- const prefix = (readGitText(cwd, ["rev-parse", "--show-prefix"]) || "").trim().replace(/\/+$/, "");
2828
- if (!prefix) return normalizeGitRelativePath(relativePathFromCwd);
2829
- return normalizeGitRelativePath(`${prefix}/${relativePathFromCwd}`);
2830
- }
2831
2891
  function readGitText(cwd, args) {
2832
2892
  try {
2833
2893
  return execFileSync("git", args, {
@@ -2842,79 +2902,45 @@ function readGitText(cwd, args) {
2842
2902
  function normalizeTaskTopic(value) {
2843
2903
  return normalizeCommitTopicText(value).replace(/^T-[A-Za-z0-9-]+\s+/, "");
2844
2904
  }
2845
- function parseDoneTaskTopicCounts(content) {
2846
- const counts = /* @__PURE__ */ new Map();
2847
- const lines = content.split("\n");
2848
- let inCodeBlock = false;
2849
- for (const line of lines) {
2850
- if (/^\s*(```|~~~)/.test(line)) {
2851
- inCodeBlock = !inCodeBlock;
2852
- continue;
2853
- }
2854
- if (inCodeBlock) continue;
2855
- const match = line.match(/^\s*-\s*\[([A-Z]+)\]((?:\[[^\]]+\])*)\s*(.+?)\s*$/);
2856
- if (!match) continue;
2857
- if (match[1].toUpperCase() !== "DONE") continue;
2858
- const topic = normalizeTaskTopic(match[3] || "");
2859
- if (!topic) continue;
2860
- counts.set(topic, (counts.get(topic) || 0) + 1);
2861
- }
2862
- return counts;
2905
+ function normalizeCommitSubjectForGate(value) {
2906
+ return normalizeCommitTopicText(value).replace(/^[a-z]+(?:\([^)]*\))?!?:\s*/i, "").toLowerCase();
2863
2907
  }
2864
2908
  function checkTaskCommitGate(feature) {
2865
- const tasksPath = normalizeGitRelativePath(`${feature.docs.featurePathFromDocs}/tasks.md`);
2866
- const docsGitCwd = feature.git.docsGitCwd;
2867
- const repoTasksPath = toRepoRelativePath(docsGitCwd, tasksPath);
2868
- const latestTasksCommit = (readGitText(docsGitCwd, ["rev-list", "-n", "1", "HEAD", "--", tasksPath]) || "").trim();
2869
- if (!latestTasksCommit) {
2870
- return { pass: false, reason: "NO_TASKS_COMMIT" };
2871
- }
2872
- const currentContent = readGitText(docsGitCwd, ["show", `${latestTasksCommit}:${repoTasksPath}`]);
2873
- if (currentContent === void 0) {
2874
- return { pass: false, reason: "TASKS_FILE_UNAVAILABLE" };
2875
- }
2876
- const previousContent = readGitText(docsGitCwd, ["show", `${latestTasksCommit}^:${repoTasksPath}`]) || "";
2877
- const currentDone = parseDoneTaskTopicCounts(currentContent);
2878
- const previousDone = parseDoneTaskTopicCounts(previousContent);
2879
- let newDoneCount = 0;
2880
- for (const [topic, currentCount] of currentDone.entries()) {
2881
- const previousCount = previousDone.get(topic) || 0;
2882
- if (currentCount > previousCount) {
2883
- newDoneCount += currentCount - previousCount;
2884
- }
2885
- }
2886
- if (newDoneCount > 1) {
2887
- return {
2888
- pass: false,
2889
- reason: "MULTIPLE_DONE_TRANSITIONS",
2890
- newDoneCount
2891
- };
2909
+ const projectGitCwd = feature.git.projectGitCwd;
2910
+ const lastDoneTopic = normalizeTaskTopic(feature.lastDoneTask?.title || "");
2911
+ if (!projectGitCwd || !lastDoneTopic) {
2912
+ return { pass: true };
2892
2913
  }
2893
- if (newDoneCount === 1) {
2894
- const lastDoneTopic = normalizeTaskTopic(feature.lastDoneTask?.title || "");
2895
- if (lastDoneTopic) {
2896
- const previousCount = previousDone.get(lastDoneTopic) || 0;
2897
- const currentCount = currentDone.get(lastDoneTopic) || 0;
2898
- if (currentCount <= previousCount) {
2899
- return { pass: false, reason: "MISMATCH_LAST_DONE", newDoneCount };
2900
- }
2901
- }
2914
+ const args = ["log", "-n", "1", "--pretty=%s", "--", "."];
2915
+ const relativeDocsDir = path19.relative(projectGitCwd, feature.git.docsGitCwd);
2916
+ const normalizedDocsDir = normalizeGitRelativePath(relativeDocsDir);
2917
+ if (normalizedDocsDir && normalizedDocsDir !== "." && normalizedDocsDir !== ".." && !normalizedDocsDir.startsWith("../")) {
2918
+ args.push(`:(exclude)${normalizedDocsDir}/**`);
2919
+ }
2920
+ const latestProjectSubject = readGitText(projectGitCwd, args);
2921
+ if (latestProjectSubject === void 0) {
2922
+ return { pass: false, reason: "PROJECT_LOG_UNAVAILABLE" };
2923
+ }
2924
+ const normalizedSubject = normalizeCommitSubjectForGate(latestProjectSubject);
2925
+ if (!normalizedSubject) {
2926
+ return { pass: false, reason: "NO_PROJECT_COMMIT" };
2902
2927
  }
2903
- return { pass: true, reason: "MULTIPLE_DONE_TRANSITIONS", newDoneCount };
2928
+ const normalizedLastDone = normalizeTaskTopic(lastDoneTopic).toLowerCase();
2929
+ if (!normalizedSubject.includes(normalizedLastDone)) {
2930
+ return { pass: false, reason: "MISMATCH_LAST_DONE" };
2931
+ }
2932
+ return { pass: true };
2904
2933
  }
2905
2934
  function getTaskCommitGateReasonText(lang, check) {
2906
2935
  switch (check.reason) {
2907
- case "NO_TASKS_COMMIT":
2936
+ case "NO_PROJECT_COMMIT":
2908
2937
  return tr(lang, "messages", "taskCommitGateReasonNoTasksCommit");
2909
- case "TASKS_FILE_UNAVAILABLE":
2938
+ case "PROJECT_LOG_UNAVAILABLE":
2910
2939
  return tr(lang, "messages", "taskCommitGateReasonTasksFileUnavailable");
2911
2940
  case "MISMATCH_LAST_DONE":
2912
2941
  return tr(lang, "messages", "taskCommitGateReasonMismatchLastDone");
2913
- case "MULTIPLE_DONE_TRANSITIONS":
2914
2942
  default:
2915
- return tr(lang, "messages", "taskCommitGateReasonDoneCount", {
2916
- count: check.newDoneCount ?? 0
2917
- });
2943
+ return tr(lang, "messages", "taskCommitGateReasonMismatchLastDone");
2918
2944
  }
2919
2945
  }
2920
2946
  function getStepDefinitions(lang, workflow) {
@@ -3720,22 +3746,85 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3720
3746
  ];
3721
3747
  }
3722
3748
  if (f.pr.status === "Review") {
3723
- return [
3749
+ if (!f.docs.prReviewFindingsFieldExists) {
3750
+ return [
3751
+ {
3752
+ type: "instruction",
3753
+ category: "code_review",
3754
+ requiresUserCheck: true,
3755
+ message: tr(lang, "messages", "prReviewFindingsFieldMissing")
3756
+ }
3757
+ ];
3758
+ }
3759
+ if (!f.prReview.findings) {
3760
+ return [
3761
+ {
3762
+ type: "instruction",
3763
+ category: "code_review",
3764
+ requiresUserCheck: true,
3765
+ message: tr(lang, "messages", "prReviewFindingsMissing")
3766
+ }
3767
+ ];
3768
+ }
3769
+ if (!f.docs.prReviewEvidenceFieldExists) {
3770
+ return [
3771
+ {
3772
+ type: "instruction",
3773
+ category: "code_review",
3774
+ requiresUserCheck: true,
3775
+ message: tr(lang, "messages", "prReviewEvidenceFieldMissing")
3776
+ }
3777
+ ];
3778
+ }
3779
+ if ((f.prReview.findings.major > 0 || f.prReview.findings.minor > 0) && !f.prReview.evidenceProvided) {
3780
+ return [
3781
+ {
3782
+ type: "instruction",
3783
+ category: "code_review",
3784
+ requiresUserCheck: true,
3785
+ message: tr(lang, "messages", "prReviewEvidenceMissing")
3786
+ }
3787
+ ];
3788
+ }
3789
+ const remoteBlockReasons = getPrReviewRemoteBlockReasons(f, lang);
3790
+ const actions = [
3724
3791
  {
3725
3792
  type: "instruction",
3726
3793
  category: "code_review",
3727
3794
  requiresUserCheck: true,
3728
3795
  message: tr(lang, "messages", "prReviewResolve")
3729
- },
3730
- {
3796
+ }
3797
+ ];
3798
+ if (!f.git.projectGitCwd) {
3799
+ actions.push({
3731
3800
  type: "instruction",
3732
3801
  category: "code_review",
3733
3802
  requiresUserCheck: true,
3734
- message: tr(lang, "messages", "prReviewMerge", {
3735
- featureRef: f.id || f.folderName
3803
+ message: tr(lang, "messages", "standaloneNeedsProjectRoot")
3804
+ });
3805
+ } else {
3806
+ actions.push({
3807
+ type: "command",
3808
+ category: "code_review",
3809
+ requiresUserCheck: true,
3810
+ scope: "project",
3811
+ cwd: f.git.projectGitCwd,
3812
+ cmd: tr(lang, "messages", "prReviewPush", {
3813
+ projectGitCwd: f.git.projectGitCwd
3736
3814
  })
3737
- }
3738
- ];
3815
+ });
3816
+ }
3817
+ actions.push({
3818
+ type: "instruction",
3819
+ category: "code_review",
3820
+ requiresUserCheck: true,
3821
+ message: remoteBlockReasons.length > 0 ? tr(lang, "messages", "prReviewRemoteBlocked", {
3822
+ reasons: remoteBlockReasons.join("; ")
3823
+ }) : tr(lang, "messages", "prReviewMerge", {
3824
+ featureRef: f.id || f.folderName
3825
+ })
3826
+ });
3827
+ return actions;
3739
3828
  }
3740
3829
  return [
3741
3830
  {
@@ -4071,7 +4160,7 @@ function parsePrePrReviewStatus(value) {
4071
4160
  if (/^pending$/i.test(trimmed)) return "Pending";
4072
4161
  return void 0;
4073
4162
  }
4074
- function parsePrePrFindings(value) {
4163
+ function parseReviewFindings(value) {
4075
4164
  if (!value) return void 0;
4076
4165
  const trimmed = value.trim();
4077
4166
  if (!trimmed || trimmed.includes("|")) return void 0;
@@ -4109,13 +4198,13 @@ function parsePrLink(value) {
4109
4198
  return trimmed;
4110
4199
  }
4111
4200
  function normalizeGitPath(value) {
4112
- return value.split(path18.sep).join("/");
4201
+ return value.split(path19.sep).join("/");
4113
4202
  }
4114
4203
  function resolveProjectStatusPaths(projectGitCwd, docsDir) {
4115
- const relativeDocsDir = path18.relative(projectGitCwd, docsDir);
4204
+ const relativeDocsDir = path19.relative(projectGitCwd, docsDir);
4116
4205
  if (!relativeDocsDir) return [];
4117
- if (path18.isAbsolute(relativeDocsDir)) return [];
4118
- if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path18.sep}`)) {
4206
+ if (path19.isAbsolute(relativeDocsDir)) return [];
4207
+ if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path19.sep}`)) {
4119
4208
  return [];
4120
4209
  }
4121
4210
  const normalizedDocsDir = normalizeGitPath(relativeDocsDir).replace(/\/+$/, "");
@@ -4136,6 +4225,93 @@ function uniqueNormalizedPaths(values) {
4136
4225
  }
4137
4226
  var PROJECT_DIRTY_STATUS_CACHE = /* @__PURE__ */ new Map();
4138
4227
  var COMPONENT_STATUS_PATH_CACHE = /* @__PURE__ */ new Map();
4228
+ var PR_REMOTE_STATUS_CACHE = /* @__PURE__ */ new Map();
4229
+ function toUpperToken(value) {
4230
+ if (typeof value !== "string") return void 0;
4231
+ const normalized = value.trim().toUpperCase();
4232
+ return normalized || void 0;
4233
+ }
4234
+ function parseCheckSignal(check) {
4235
+ if (!check || typeof check !== "object") return { failing: false, pending: false };
4236
+ const row = check;
4237
+ const tokens = /* @__PURE__ */ new Set();
4238
+ for (const key of ["conclusion", "status", "state"]) {
4239
+ const token = toUpperToken(row[key]);
4240
+ if (token) tokens.add(token);
4241
+ }
4242
+ for (const token of tokens) {
4243
+ if (token === "FAILURE" || token === "FAILED" || token === "ERROR" || token === "TIMED_OUT" || token === "CANCELLED" || token === "ACTION_REQUIRED" || token === "STARTUP_FAILURE") {
4244
+ return { failing: true, pending: false };
4245
+ }
4246
+ }
4247
+ for (const token of tokens) {
4248
+ if (token === "PENDING" || token === "IN_PROGRESS" || token === "QUEUED" || token === "EXPECTED" || token === "WAITING" || token === "REQUESTED") {
4249
+ return { failing: false, pending: true };
4250
+ }
4251
+ }
4252
+ return { failing: false, pending: false };
4253
+ }
4254
+ function isMergeBlockedState(value) {
4255
+ if (!value) return false;
4256
+ return value === "BLOCKED" || value === "DIRTY" || value === "BEHIND" || value === "DRAFT" || value === "HAS_HOOKS" || value === "UNKNOWN" || value === "UNSTABLE";
4257
+ }
4258
+ function resolvePrRemoteStatus(prRef, projectGitCwd) {
4259
+ const cacheKey = `${projectGitCwd}::${prRef}`;
4260
+ if (PR_REMOTE_STATUS_CACHE.has(cacheKey)) {
4261
+ return PR_REMOTE_STATUS_CACHE.get(cacheKey) || null;
4262
+ }
4263
+ try {
4264
+ const raw = execFileSync(
4265
+ "gh",
4266
+ [
4267
+ "pr",
4268
+ "view",
4269
+ prRef,
4270
+ "--json",
4271
+ "reviewDecision,mergeStateStatus,isDraft,statusCheckRollup"
4272
+ ],
4273
+ {
4274
+ cwd: projectGitCwd,
4275
+ encoding: "utf-8",
4276
+ stdio: ["ignore", "pipe", "pipe"],
4277
+ timeout: 5e3,
4278
+ maxBuffer: 1024 * 1024
4279
+ }
4280
+ ).trim();
4281
+ if (!raw) {
4282
+ PR_REMOTE_STATUS_CACHE.set(cacheKey, null);
4283
+ return null;
4284
+ }
4285
+ const parsed = JSON.parse(raw);
4286
+ const reviewDecision = toUpperToken(parsed.reviewDecision);
4287
+ const mergeStateStatus = toUpperToken(parsed.mergeStateStatus);
4288
+ const isDraft = parsed.isDraft === true;
4289
+ let failingChecks = 0;
4290
+ let pendingChecks = 0;
4291
+ const rollup = Array.isArray(parsed.statusCheckRollup) ? parsed.statusCheckRollup : [];
4292
+ for (const check of rollup) {
4293
+ const signal = parseCheckSignal(check);
4294
+ if (signal.failing) failingChecks++;
4295
+ else if (signal.pending) pendingChecks++;
4296
+ }
4297
+ const remote = {
4298
+ source: "gh",
4299
+ available: true,
4300
+ reviewDecision,
4301
+ mergeStateStatus,
4302
+ isDraft,
4303
+ hasBlockingReview: reviewDecision === "CHANGES_REQUESTED" || reviewDecision === "REVIEW_REQUIRED",
4304
+ mergeBlocked: isDraft || isMergeBlockedState(mergeStateStatus),
4305
+ failingChecks,
4306
+ pendingChecks
4307
+ };
4308
+ PR_REMOTE_STATUS_CACHE.set(cacheKey, remote);
4309
+ return remote;
4310
+ } catch {
4311
+ PR_REMOTE_STATUS_CACHE.set(cacheKey, null);
4312
+ return null;
4313
+ }
4314
+ }
4139
4315
  async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4140
4316
  const configured = workflow?.componentPaths?.[component];
4141
4317
  const configuredCandidates = Array.isArray(configured) ? configured.map((value) => String(value).trim()).filter(Boolean) : [];
@@ -4149,10 +4325,10 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4149
4325
  const normalizedCandidates = uniqueNormalizedPaths(
4150
4326
  candidates.map((candidate) => {
4151
4327
  if (!candidate) return "";
4152
- if (!path18.isAbsolute(candidate)) return candidate;
4153
- const relative = path18.relative(projectGitCwd, candidate);
4328
+ if (!path19.isAbsolute(candidate)) return candidate;
4329
+ const relative = path19.relative(projectGitCwd, candidate);
4154
4330
  if (!relative) return "";
4155
- if (relative === ".." || relative.startsWith(`..${path18.sep}`)) return "";
4331
+ if (relative === ".." || relative.startsWith(`..${path19.sep}`)) return "";
4156
4332
  return relative;
4157
4333
  }).filter(Boolean)
4158
4334
  );
@@ -4165,7 +4341,7 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4165
4341
  if (cached) return [...cached];
4166
4342
  const existing = [];
4167
4343
  for (const candidate of normalizedCandidates) {
4168
- if (await fs15.pathExists(path18.join(projectGitCwd, candidate))) {
4344
+ if (await fs15.pathExists(path19.join(projectGitCwd, candidate))) {
4169
4345
  existing.push(candidate);
4170
4346
  }
4171
4347
  }
@@ -4254,15 +4430,15 @@ async function parseFeature(featurePath, type, context, options) {
4254
4430
  const lang = options.lang;
4255
4431
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
4256
4432
  const prePrReviewPolicy = resolvePrePrReviewPolicy(options.workflow);
4257
- const folderName = path18.basename(featurePath);
4433
+ const folderName = path19.basename(featurePath);
4258
4434
  const match = folderName.match(/^(F\d+)-(.+)$/);
4259
4435
  const id = match?.[1];
4260
4436
  const slug = match?.[2] || folderName;
4261
- const specPath = path18.join(featurePath, "spec.md");
4262
- const planPath = path18.join(featurePath, "plan.md");
4263
- const tasksPath = path18.join(featurePath, "tasks.md");
4264
- const issueDocPath = path18.join(featurePath, "issue.md");
4265
- const prDocPath = path18.join(featurePath, "pr.md");
4437
+ const specPath = path19.join(featurePath, "spec.md");
4438
+ const planPath = path19.join(featurePath, "plan.md");
4439
+ const tasksPath = path19.join(featurePath, "tasks.md");
4440
+ const issueDocPath = path19.join(featurePath, "issue.md");
4441
+ const prDocPath = path19.join(featurePath, "pr.md");
4266
4442
  let specStatus;
4267
4443
  let issueNumber;
4268
4444
  const specExists = await fs15.pathExists(specPath);
@@ -4292,8 +4468,12 @@ async function parseFeature(featurePath, type, context, options) {
4292
4468
  let prePrFindings;
4293
4469
  let prePrEvidence;
4294
4470
  let prePrEvidenceProvided = false;
4471
+ let prReviewFindings;
4472
+ let prReviewEvidence;
4473
+ let prReviewEvidenceProvided = false;
4295
4474
  let prLink;
4296
4475
  let prStatus;
4476
+ let prRemote;
4297
4477
  let prFieldExists = false;
4298
4478
  let prStatusFieldExists = false;
4299
4479
  let issueDocStatus;
@@ -4306,6 +4486,8 @@ async function parseFeature(featurePath, type, context, options) {
4306
4486
  let prePrReviewFieldExists = false;
4307
4487
  let prePrFindingsFieldExists = false;
4308
4488
  let prePrEvidenceFieldExists = false;
4489
+ let prReviewFindingsFieldExists = false;
4490
+ let prReviewEvidenceFieldExists = false;
4309
4491
  if (tasksExists) {
4310
4492
  const content = await fs15.readFile(tasksPath, "utf-8");
4311
4493
  const {
@@ -4322,10 +4504,12 @@ async function parseFeature(featurePath, type, context, options) {
4322
4504
  lastDoneTask = lastDone;
4323
4505
  nextTodoTask = nextTodo;
4324
4506
  completionChecklist = parseCompletionChecklist(content);
4325
- if (!issueNumber) {
4326
- const issueValue = extractFirstSpecValue(content, ["\uC774\uC288 \uBC88\uD638", "Issue Number", "Issue"]);
4327
- issueNumber = parseIssueNumber(issueValue);
4328
- }
4507
+ const issueValue = extractFirstSpecValue(content, [
4508
+ "\uC774\uC288 \uBC88\uD638",
4509
+ "Issue Number",
4510
+ "Issue"
4511
+ ]);
4512
+ issueNumber = parseIssueNumber(issueValue);
4329
4513
  const tasksDocStatusValue = extractFirstSpecValue(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
4330
4514
  tasksDocStatusFieldExists = hasAnySpecKey(content, ["\uBB38\uC11C \uC0C1\uD0DC", "Doc Status"]);
4331
4515
  tasksDocStatus = parseDocStatus(tasksDocStatusValue);
@@ -4352,7 +4536,7 @@ async function parseFeature(featurePath, type, context, options) {
4352
4536
  "PR \uC804 \uB9AC\uBDF0 Findings",
4353
4537
  "Pre-PR Findings"
4354
4538
  ]);
4355
- prePrFindings = parsePrePrFindings(prePrFindingsValue);
4539
+ prePrFindings = parseReviewFindings(prePrFindingsValue);
4356
4540
  const prePrEvidenceValue = extractFirstSpecValue(content, [
4357
4541
  "PR \uC804 \uB9AC\uBDF0 Evidence",
4358
4542
  "Pre-PR Evidence"
@@ -4363,6 +4547,25 @@ async function parseFeature(featurePath, type, context, options) {
4363
4547
  ]);
4364
4548
  prePrEvidence = prePrEvidenceValue?.trim();
4365
4549
  prePrEvidenceProvided = !isPlaceholderReviewEvidence(prePrEvidenceValue);
4550
+ const prReviewFindingsValue = extractFirstSpecValue(content, [
4551
+ "PR \uB9AC\uBDF0 Findings",
4552
+ "PR Review Findings"
4553
+ ]);
4554
+ prReviewFindingsFieldExists = hasAnySpecKey(content, [
4555
+ "PR \uB9AC\uBDF0 Findings",
4556
+ "PR Review Findings"
4557
+ ]);
4558
+ prReviewFindings = parseReviewFindings(prReviewFindingsValue);
4559
+ const prReviewEvidenceValue = extractFirstSpecValue(content, [
4560
+ "PR \uB9AC\uBDF0 Evidence",
4561
+ "PR Review Evidence"
4562
+ ]);
4563
+ prReviewEvidenceFieldExists = hasAnySpecKey(content, [
4564
+ "PR \uB9AC\uBDF0 Evidence",
4565
+ "PR Review Evidence"
4566
+ ]);
4567
+ prReviewEvidence = prReviewEvidenceValue?.trim();
4568
+ prReviewEvidenceProvided = !isPlaceholderReviewEvidence(prReviewEvidenceValue);
4366
4569
  }
4367
4570
  const issueDocExists = await fs15.pathExists(issueDocPath);
4368
4571
  if (issueDocExists) {
@@ -4370,20 +4573,11 @@ async function parseFeature(featurePath, type, context, options) {
4370
4573
  const issueDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4371
4574
  issueDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
4372
4575
  issueDocStatus = parseWorkflowDocStatus(issueDocStatusValue);
4373
- const issueValue = extractFirstSpecValue(content, [
4374
- "\uC774\uC288 \uBC88\uD638",
4375
- "Issue Number",
4376
- "Issue"
4377
- ]);
4378
4576
  issueDocIssueFieldExists = hasAnySpecKey(content, [
4379
4577
  "\uC774\uC288 \uBC88\uD638",
4380
4578
  "Issue Number",
4381
4579
  "Issue"
4382
4580
  ]);
4383
- const parsedIssueFromDoc = parseIssueNumber(issueValue);
4384
- if (parsedIssueFromDoc) {
4385
- issueNumber = parsedIssueFromDoc;
4386
- }
4387
4581
  }
4388
4582
  const prDocExists = await fs15.pathExists(prDocPath);
4389
4583
  if (prDocExists) {
@@ -4391,27 +4585,11 @@ async function parseFeature(featurePath, type, context, options) {
4391
4585
  const prDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4392
4586
  prDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
4393
4587
  prDocStatus = parseWorkflowDocStatus(prDocStatusValue);
4394
- const prValue = extractFirstSpecValue(content, ["PR", "Pull Request"]);
4395
4588
  prDocPrFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
4396
- const parsedPrLink = parsePrLink(prValue);
4397
- if (parsedPrLink) {
4398
- prLink = parsedPrLink;
4399
- }
4400
- const prReviewStatusValue = extractFirstSpecValue(content, [
4401
- "PR \uC0C1\uD0DC",
4402
- "PR Status"
4403
- ]);
4404
4589
  prDocReviewStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
4405
- const parsedPrStatus = parsePrReviewStatus(prReviewStatusValue);
4406
- if (parsedPrStatus) {
4407
- prStatus = parsedPrStatus;
4408
- }
4409
- }
4410
- if (prDocPrFieldExists) {
4411
- prFieldExists = true;
4412
4590
  }
4413
- if (prDocReviewStatusFieldExists) {
4414
- prStatusFieldExists = true;
4591
+ if (workflowPolicy.requireReview && prStatus === "Review" && prLink && context.projectGitCwd) {
4592
+ prRemote = resolvePrRemoteStatus(prLink, context.projectGitCwd) || void 0;
4415
4593
  }
4416
4594
  const warnings = [];
4417
4595
  if (context.projectBranchAvailable === false) {
@@ -4423,7 +4601,7 @@ async function parseFeature(featurePath, type, context, options) {
4423
4601
  slug,
4424
4602
  folderName
4425
4603
  );
4426
- const relativeFeaturePathFromDocs = path18.relative(context.docsDir, featurePath);
4604
+ const relativeFeaturePathFromDocs = path19.relative(context.docsDir, featurePath);
4427
4605
  const normalizedFeaturePathFromDocs = normalizeGitPath(relativeFeaturePathFromDocs);
4428
4606
  const docsPathIgnored = typeof context.docsPathIgnored === "boolean" ? context.docsPathIgnored : isGitPathIgnored(context.docsGitCwd, normalizedFeaturePathFromDocs);
4429
4607
  let docsHasUncommittedChanges = typeof context.docsHasUncommittedChanges === "boolean" ? context.docsHasUncommittedChanges : false;
@@ -4509,6 +4687,12 @@ async function parseFeature(featurePath, type, context, options) {
4509
4687
  if (tasksExists && prePrReviewPolicy.enabled && !prePrEvidenceFieldExists) {
4510
4688
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrEvidenceField"));
4511
4689
  }
4690
+ if (tasksExists && workflowPolicy.requireReview && !prReviewFindingsFieldExists) {
4691
+ warnings.push(tr(lang, "warnings", "legacyTasksPrReviewFindingsField"));
4692
+ }
4693
+ if (tasksExists && workflowPolicy.requireReview && !prReviewEvidenceFieldExists) {
4694
+ warnings.push(tr(lang, "warnings", "legacyTasksPrReviewEvidenceField"));
4695
+ }
4512
4696
  if (tasksExists && !tasksDocStatusFieldExists) {
4513
4697
  warnings.push(tr(lang, "warnings", "legacyTasksDocStatusField"));
4514
4698
  }
@@ -4518,6 +4702,23 @@ async function parseFeature(featurePath, type, context, options) {
4518
4702
  if (projectHasUncommittedChanges) {
4519
4703
  warnings.push(tr(lang, "warnings", "projectUncommittedChanges"));
4520
4704
  }
4705
+ if (prRemote?.hasBlockingReview) {
4706
+ warnings.push(tr(lang, "warnings", "workflowPrRemoteChangesRequested"));
4707
+ }
4708
+ if ((prRemote?.failingChecks || 0) > 0) {
4709
+ warnings.push(
4710
+ tr(lang, "warnings", "workflowPrRemoteChecksFailing", {
4711
+ count: prRemote?.failingChecks || 0
4712
+ })
4713
+ );
4714
+ }
4715
+ if ((prRemote?.pendingChecks || 0) > 0) {
4716
+ warnings.push(
4717
+ tr(lang, "warnings", "workflowPrRemoteChecksPending", {
4718
+ count: prRemote?.pendingChecks || 0
4719
+ })
4720
+ );
4721
+ }
4521
4722
  const tasksDocApproved = !tasksDocStatusFieldExists || tasksDocStatus === "Approved";
4522
4723
  const implementationDone = tasksExists && tasksSummary.total > 0 && tasksSummary.total === tasksSummary.done && isCompletionChecklistDone2({ completionChecklist }) && tasksDocApproved;
4523
4724
  const workflowDone = implementationDone && !docsHasUncommittedChanges && !projectHasUncommittedChanges && specStatus === "Approved" && planStatus === "Approved" && (!workflowPolicy.requireIssue || !!issueNumber) && (!workflowPolicy.requirePr || isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink) && (!workflowPolicy.requireReview || prStatus === "Approved") && isPrePrReviewSatisfied2(
@@ -4554,6 +4755,14 @@ async function parseFeature(featurePath, type, context, options) {
4554
4755
  if (!prStatus) warnings.push(tr(lang, "warnings", "workflowPrStatusMissing"));
4555
4756
  if (prStatus && prStatus !== "Approved") {
4556
4757
  warnings.push(tr(lang, "warnings", "workflowPrStatusNotApproved"));
4758
+ if (prStatus === "Review") {
4759
+ if (!prReviewFindingsFieldExists || !prReviewFindings) {
4760
+ warnings.push(tr(lang, "warnings", "workflowPrReviewFindingsMissing"));
4761
+ }
4762
+ if ((!prReviewEvidenceFieldExists || !prReviewEvidenceProvided) && (prReviewFindings?.major || 0) + (prReviewFindings?.minor || 0) > 0) {
4763
+ warnings.push(tr(lang, "warnings", "workflowPrReviewEvidenceMissing"));
4764
+ }
4765
+ }
4557
4766
  }
4558
4767
  }
4559
4768
  }
@@ -4606,7 +4815,12 @@ async function parseFeature(featurePath, type, context, options) {
4606
4815
  evidence: prePrEvidence,
4607
4816
  evidenceProvided: prePrEvidenceProvided
4608
4817
  },
4609
- pr: { link: prLink, status: prStatus },
4818
+ prReview: {
4819
+ findings: prReviewFindings,
4820
+ evidence: prReviewEvidence,
4821
+ evidenceProvided: prReviewEvidenceProvided
4822
+ },
4823
+ pr: { link: prLink, status: prStatus, remote: prRemote },
4610
4824
  git: {
4611
4825
  docsBranch: context.docsBranch,
4612
4826
  projectBranch: context.projectBranch,
@@ -4638,7 +4852,9 @@ async function parseFeature(featurePath, type, context, options) {
4638
4852
  prStatusFieldExists,
4639
4853
  prePrReviewFieldExists,
4640
4854
  prePrFindingsFieldExists,
4641
- prePrEvidenceFieldExists
4855
+ prePrEvidenceFieldExists,
4856
+ prReviewFindingsFieldExists,
4857
+ prReviewEvidenceFieldExists
4642
4858
  }
4643
4859
  };
4644
4860
  const { currentStep, actions, nextAction } = resolveFeatureProgress(
@@ -4783,7 +4999,7 @@ async function scanFeatures(config) {
4783
4999
  }
4784
5000
  }
4785
5001
  const relativeFeaturePaths = allFeatureDirs.map(
4786
- (dir) => normalizeRelPath(path18.relative(config.docsDir, dir))
5002
+ (dir) => normalizeRelPath(path19.relative(config.docsDir, dir))
4787
5003
  );
4788
5004
  const docsGitMeta = buildDocsFeatureGitMeta(config.docsDir, relativeFeaturePaths);
4789
5005
  const parseTargets = config.projectType === "single" ? [{ type: "single", dirs: componentFeatureDirs.get("single") || [] }] : resolveProjectComponents(config.projectType, config.components).map((component) => ({
@@ -4794,7 +5010,7 @@ async function scanFeatures(config) {
4794
5010
  const parsed = await Promise.all(
4795
5011
  target.dirs.map(async (dir) => {
4796
5012
  const relativeFeaturePathFromDocs = normalizeRelPath(
4797
- path18.relative(config.docsDir, dir)
5013
+ path19.relative(config.docsDir, dir)
4798
5014
  );
4799
5015
  const docsMeta = docsGitMeta.get(relativeFeaturePathFromDocs);
4800
5016
  return parseFeature(
@@ -4863,13 +5079,13 @@ async function runStatus(options) {
4863
5079
  );
4864
5080
  }
4865
5081
  const { docsDir, projectType, projectName, lang } = config;
4866
- const featuresDir = path18.join(docsDir, "features");
5082
+ const featuresDir = path19.join(docsDir, "features");
4867
5083
  const scan = await scanFeatures(config);
4868
5084
  const features = [];
4869
5085
  const idMap = /* @__PURE__ */ new Map();
4870
5086
  for (const f of scan.features) {
4871
5087
  const id = f.id || "UNKNOWN";
4872
- const relPath = path18.relative(docsDir, f.path);
5088
+ const relPath = path19.relative(docsDir, f.path);
4873
5089
  if (!idMap.has(id)) idMap.set(id, []);
4874
5090
  idMap.get(id).push(relPath);
4875
5091
  if (!f.docs.specExists || !f.docs.tasksExists) continue;
@@ -4950,7 +5166,7 @@ async function runStatus(options) {
4950
5166
  }
4951
5167
  console.log();
4952
5168
  if (options.write) {
4953
- const outputPath = path18.join(featuresDir, "status.md");
5169
+ const outputPath = path19.join(featuresDir, "status.md");
4954
5170
  const date = getLocalDateString();
4955
5171
  const content = [
4956
5172
  "# Feature Status",
@@ -4978,7 +5194,7 @@ function escapeRegExp2(value) {
4978
5194
  }
4979
5195
  async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderName) {
4980
5196
  try {
4981
- const specPath = path18.join(featureDir, "spec.md");
5197
+ const specPath = path19.join(featureDir, "spec.md");
4982
5198
  if (!await fs15.pathExists(specPath)) return fallbackSlug;
4983
5199
  const content = await fs15.readFile(specPath, "utf-8");
4984
5200
  const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
@@ -5060,10 +5276,10 @@ async function runUpdate(options) {
5060
5276
  console.log(chalk6.blue(tr(lang, "cli", "update.updatingAgents")));
5061
5277
  }
5062
5278
  if (agentsMode === "all") {
5063
- const commonAgentsBase = path18.join(templatesDir, lang, "common", "agents");
5064
- const targetAgentsBase = path18.join(docsDir, "agents");
5065
- const commonAgents = agentsMode === "skills" ? path18.join(commonAgentsBase, "skills") : commonAgentsBase;
5066
- const targetAgents = agentsMode === "skills" ? path18.join(targetAgentsBase, "skills") : targetAgentsBase;
5279
+ const commonAgentsBase = path19.join(templatesDir, lang, "common", "agents");
5280
+ const targetAgentsBase = path19.join(docsDir, "agents");
5281
+ const commonAgents = agentsMode === "skills" ? path19.join(commonAgentsBase, "skills") : commonAgentsBase;
5282
+ const targetAgents = agentsMode === "skills" ? path19.join(targetAgentsBase, "skills") : targetAgentsBase;
5067
5283
  const featurePath = projectType === "multi" ? "docs/features/{component}" : "docs/features";
5068
5284
  const projectName = config.projectName ?? "{{projectName}}";
5069
5285
  const commonReplacements = {
@@ -5143,7 +5359,7 @@ function normalizeSkillList2(raw) {
5143
5359
  return [...deduped];
5144
5360
  }
5145
5361
  async function backfillMissingConfigDefaults(docsDir) {
5146
- const configPath = path18.join(docsDir, ".lee-spec-kit.json");
5362
+ const configPath = path19.join(docsDir, ".lee-spec-kit.json");
5147
5363
  if (!await fs15.pathExists(configPath)) {
5148
5364
  return { changed: false, changedPaths: [] };
5149
5365
  }
@@ -5216,8 +5432,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
5216
5432
  const files = await fs15.readdir(sourceDir);
5217
5433
  let updatedCount = 0;
5218
5434
  for (const file of files) {
5219
- const sourcePath = path18.join(sourceDir, file);
5220
- const targetPath = path18.join(targetDir, file);
5435
+ const sourcePath = path19.join(sourceDir, file);
5436
+ const targetPath = path19.join(targetDir, file);
5221
5437
  const stat = await fs15.stat(sourcePath);
5222
5438
  if (stat.isFile()) {
5223
5439
  if (protectedFiles.has(file)) {
@@ -5300,7 +5516,7 @@ function extractPorcelainPaths(line) {
5300
5516
  function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
5301
5517
  const top = getGitTopLevel2(docsDir);
5302
5518
  if (!top) return null;
5303
- const rel = path18.relative(top, docsDir) || ".";
5519
+ const rel = path19.relative(top, docsDir) || ".";
5304
5520
  try {
5305
5521
  const output = execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
5306
5522
  cwd: top,
@@ -5312,7 +5528,7 @@ function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
5312
5528
  }
5313
5529
  const ignoredRelPaths = new Set(
5314
5530
  ignoredAbsPaths.map(
5315
- (absPath) => normalizeGitPath2(path18.relative(top, absPath) || ".")
5531
+ (absPath) => normalizeGitPath2(path19.relative(top, absPath) || ".")
5316
5532
  )
5317
5533
  );
5318
5534
  const filtered = output.split("\n").filter((line) => {
@@ -5369,7 +5585,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
5369
5585
  }
5370
5586
  async function runConfig(options) {
5371
5587
  const cwd = process.cwd();
5372
- const targetCwd = options.dir ? path18.resolve(cwd, options.dir) : cwd;
5588
+ const targetCwd = options.dir ? path19.resolve(cwd, options.dir) : cwd;
5373
5589
  const config = await getConfig(targetCwd);
5374
5590
  if (!config) {
5375
5591
  throw createCliError(
@@ -5377,7 +5593,7 @@ async function runConfig(options) {
5377
5593
  tr(DEFAULT_LANG, "cli", "common.configNotFound")
5378
5594
  );
5379
5595
  }
5380
- const configPath = path18.join(config.docsDir, ".lee-spec-kit.json");
5596
+ const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
5381
5597
  if (!options.projectRoot) {
5382
5598
  console.log();
5383
5599
  console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
@@ -5743,42 +5959,42 @@ var BUILTIN_DOC_DEFINITIONS = [
5743
5959
  {
5744
5960
  id: "agents",
5745
5961
  title: { ko: "\uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uADDC\uCE59", en: "Agent Operating Rules" },
5746
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "agents.md")
5962
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "agents.md")
5747
5963
  },
5748
5964
  {
5749
5965
  id: "git-workflow",
5750
5966
  title: { ko: "Git \uC6CC\uD06C\uD50C\uB85C\uC6B0", en: "Git Workflow" },
5751
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "git-workflow.md")
5967
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "git-workflow.md")
5752
5968
  },
5753
5969
  {
5754
5970
  id: "issue-doc",
5755
5971
  title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
5756
- relativePath: (_, lang) => path18.join(lang, "common", "features", "feature-base", "issue.md")
5972
+ relativePath: (_, lang) => path19.join(lang, "common", "features", "feature-base", "issue.md")
5757
5973
  },
5758
5974
  {
5759
5975
  id: "pr-doc",
5760
5976
  title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
5761
- relativePath: (_, lang) => path18.join(lang, "common", "features", "feature-base", "pr.md")
5977
+ relativePath: (_, lang) => path19.join(lang, "common", "features", "feature-base", "pr.md")
5762
5978
  },
5763
5979
  {
5764
5980
  id: "create-feature",
5765
5981
  title: { ko: "create-feature \uC2A4\uD0AC", en: "create-feature skill" },
5766
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "skills", "create-feature.md")
5982
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-feature.md")
5767
5983
  },
5768
5984
  {
5769
5985
  id: "execute-task",
5770
5986
  title: { ko: "execute-task \uC2A4\uD0AC", en: "execute-task skill" },
5771
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "skills", "execute-task.md")
5987
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "execute-task.md")
5772
5988
  },
5773
5989
  {
5774
5990
  id: "create-issue",
5775
5991
  title: { ko: "create-issue \uC2A4\uD0AC", en: "create-issue skill" },
5776
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "skills", "create-issue.md")
5992
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-issue.md")
5777
5993
  },
5778
5994
  {
5779
5995
  id: "create-pr",
5780
5996
  title: { ko: "create-pr \uC2A4\uD0AC", en: "create-pr skill" },
5781
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "skills", "create-pr.md")
5997
+ relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-pr.md")
5782
5998
  }
5783
5999
  ];
5784
6000
  var DOC_FOLLOWUPS = {
@@ -5865,7 +6081,7 @@ function listBuiltinDocs(projectType, lang) {
5865
6081
  id: doc.id,
5866
6082
  title: doc.title[lang],
5867
6083
  relativePath,
5868
- absolutePath: path18.join(templatesDir, relativePath)
6084
+ absolutePath: path19.join(templatesDir, relativePath)
5869
6085
  };
5870
6086
  });
5871
6087
  }
@@ -5914,7 +6130,7 @@ function parseApprovalLabel(input, validLabels) {
5914
6130
  function getApprovalTicketPaths(config) {
5915
6131
  return {
5916
6132
  runtimePath: getApprovalTicketStorePath(config.docsDir),
5917
- legacyPath: path18.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
6133
+ legacyPath: path19.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
5918
6134
  };
5919
6135
  }
5920
6136
  function getApprovalSessionId() {
@@ -5942,7 +6158,7 @@ async function loadApprovalTicketStore(storePath) {
5942
6158
  }
5943
6159
  }
5944
6160
  async function saveApprovalTicketStore(storePath, payload) {
5945
- await fs15.ensureDir(path18.dirname(storePath));
6161
+ await fs15.ensureDir(path19.dirname(storePath));
5946
6162
  await fs15.writeJson(storePath, payload, { spaces: 2 });
5947
6163
  }
5948
6164
  async function resolveApprovalTicketStoreAndPath(config, nowMs) {
@@ -6355,6 +6571,12 @@ function getListLabel(f, stepsMap, lang, workflowPolicy, prePrReviewPolicy) {
6355
6571
  if (workflowPolicy.requireReview && !f.pr.status) {
6356
6572
  return tr(lang, "cli", "context.list.setPrStatus");
6357
6573
  }
6574
+ if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewFindingsFieldExists || !f.prReview.findings)) {
6575
+ return tr(lang, "cli", "context.list.addPrReviewFindings");
6576
+ }
6577
+ if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewEvidenceFieldExists || (f.prReview.findings?.major || 0) + (f.prReview.findings?.minor || 0) > 0 && !f.prReview.evidenceProvided)) {
6578
+ return tr(lang, "cli", "context.list.addPrReviewEvidence");
6579
+ }
6358
6580
  if (workflowPolicy.requireReview && f.pr.status !== "Approved") {
6359
6581
  return tr(lang, "cli", "context.list.prStatusToApproved", {
6360
6582
  status: f.pr.status
@@ -6734,7 +6956,7 @@ async function runContext(featureName, options) {
6734
6956
  if (f.issueNumber) {
6735
6957
  console.log(` \u2022 Issue: #${f.issueNumber}`);
6736
6958
  }
6737
- console.log(` \u2022 Path: ${path18.relative(cwd, f.path)}`);
6959
+ console.log(` \u2022 Path: ${path19.relative(cwd, f.path)}`);
6738
6960
  if (f.git.projectBranch) {
6739
6961
  console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
6740
6962
  }
@@ -7063,7 +7285,7 @@ var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
7063
7285
  ]);
7064
7286
  function formatPath(cwd, p) {
7065
7287
  if (!p) return "";
7066
- return path18.isAbsolute(p) ? path18.relative(cwd, p) : p;
7288
+ return path19.isAbsolute(p) ? path19.relative(cwd, p) : p;
7067
7289
  }
7068
7290
  function detectPlaceholders(content) {
7069
7291
  const patterns = [
@@ -7212,7 +7434,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
7212
7434
  const placeholderContext = {
7213
7435
  projectName: config.projectName,
7214
7436
  featureName: f.slug,
7215
- featurePath: f.docs.featurePathFromDocs || path18.relative(config.docsDir, f.path),
7437
+ featurePath: f.docs.featurePathFromDocs || path19.relative(config.docsDir, f.path),
7216
7438
  repoType: f.type,
7217
7439
  featureNumber
7218
7440
  };
@@ -7222,7 +7444,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
7222
7444
  "tasks.md"
7223
7445
  ];
7224
7446
  for (const file of files) {
7225
- const fullPath = path18.join(f.path, file);
7447
+ const fullPath = path19.join(f.path, file);
7226
7448
  if (!await fs15.pathExists(fullPath)) continue;
7227
7449
  const original = await fs15.readFile(fullPath, "utf-8");
7228
7450
  let next = original;
@@ -7267,7 +7489,7 @@ async function checkDocsStructure(config, cwd) {
7267
7489
  const issues = [];
7268
7490
  const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
7269
7491
  for (const dir of requiredDirs) {
7270
- const p = path18.join(config.docsDir, dir);
7492
+ const p = path19.join(config.docsDir, dir);
7271
7493
  if (!await fs15.pathExists(p)) {
7272
7494
  issues.push({
7273
7495
  level: "error",
@@ -7277,7 +7499,7 @@ async function checkDocsStructure(config, cwd) {
7277
7499
  });
7278
7500
  }
7279
7501
  }
7280
- const configPath = path18.join(config.docsDir, ".lee-spec-kit.json");
7502
+ const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
7281
7503
  if (!await fs15.pathExists(configPath)) {
7282
7504
  issues.push({
7283
7505
  level: "warn",
@@ -7300,7 +7522,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7300
7522
  }
7301
7523
  const idMap = /* @__PURE__ */ new Map();
7302
7524
  for (const f of features) {
7303
- const rel = f.docs.featurePathFromDocs || path18.relative(config.docsDir, f.path);
7525
+ const rel = f.docs.featurePathFromDocs || path19.relative(config.docsDir, f.path);
7304
7526
  const id = f.id || "UNKNOWN";
7305
7527
  if (!idMap.has(id)) idMap.set(id, []);
7306
7528
  idMap.get(id).push(rel);
@@ -7308,7 +7530,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7308
7530
  if (!isInitialTemplateState) {
7309
7531
  const featureDocs = ["spec.md", "plan.md", "tasks.md"];
7310
7532
  for (const file of featureDocs) {
7311
- const p = path18.join(f.path, file);
7533
+ const p = path19.join(f.path, file);
7312
7534
  if (!await fs15.pathExists(p)) continue;
7313
7535
  const content = await fs15.readFile(p, "utf-8");
7314
7536
  const placeholders = detectPlaceholders(content);
@@ -7323,7 +7545,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7323
7545
  });
7324
7546
  }
7325
7547
  if (decisionsPlaceholderMode !== "off") {
7326
- const decisionsPath = path18.join(f.path, "decisions.md");
7548
+ const decisionsPath = path19.join(f.path, "decisions.md");
7327
7549
  if (await fs15.pathExists(decisionsPath)) {
7328
7550
  const content = await fs15.readFile(decisionsPath, "utf-8");
7329
7551
  const placeholders = detectPlaceholders(content);
@@ -7352,7 +7574,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7352
7574
  level: "warn",
7353
7575
  code: "spec_status_unset",
7354
7576
  message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
7355
- path: formatPath(cwd, path18.join(f.path, "spec.md"))
7577
+ path: formatPath(cwd, path19.join(f.path, "spec.md"))
7356
7578
  });
7357
7579
  }
7358
7580
  if (f.docs.planExists && !f.planStatus && !isInitialTemplateState) {
@@ -7360,7 +7582,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7360
7582
  level: "warn",
7361
7583
  code: "plan_status_unset",
7362
7584
  message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
7363
- path: formatPath(cwd, path18.join(f.path, "plan.md"))
7585
+ path: formatPath(cwd, path19.join(f.path, "plan.md"))
7364
7586
  });
7365
7587
  }
7366
7588
  if (f.docs.tasksExists && f.tasks.total === 0 && !isInitialTemplateState) {
@@ -7368,7 +7590,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7368
7590
  level: "warn",
7369
7591
  code: "tasks_empty",
7370
7592
  message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
7371
- path: formatPath(cwd, path18.join(f.path, "tasks.md"))
7593
+ path: formatPath(cwd, path19.join(f.path, "tasks.md"))
7372
7594
  });
7373
7595
  }
7374
7596
  if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists && !isInitialTemplateState) {
@@ -7376,7 +7598,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7376
7598
  level: "warn",
7377
7599
  code: "tasks_doc_status_missing",
7378
7600
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
7379
- path: formatPath(cwd, path18.join(f.path, "tasks.md"))
7601
+ path: formatPath(cwd, path19.join(f.path, "tasks.md"))
7380
7602
  });
7381
7603
  }
7382
7604
  if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus && !isInitialTemplateState) {
@@ -7384,7 +7606,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7384
7606
  level: "warn",
7385
7607
  code: "tasks_doc_status_unset",
7386
7608
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
7387
- path: formatPath(cwd, path18.join(f.path, "tasks.md"))
7609
+ path: formatPath(cwd, path19.join(f.path, "tasks.md"))
7388
7610
  });
7389
7611
  }
7390
7612
  }
@@ -7408,7 +7630,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7408
7630
  level: "warn",
7409
7631
  code: "missing_feature_id",
7410
7632
  message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
7411
- path: formatPath(cwd, path18.join(config.docsDir, p))
7633
+ path: formatPath(cwd, path19.join(config.docsDir, p))
7412
7634
  });
7413
7635
  }
7414
7636
  return issues;
@@ -7530,7 +7752,7 @@ function doctorCommand(program2) {
7530
7752
  }
7531
7753
  console.log();
7532
7754
  console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
7533
- console.log(chalk6.gray(`- Docs: ${path18.relative(cwd, docsDir)}`));
7755
+ console.log(chalk6.gray(`- Docs: ${path19.relative(cwd, docsDir)}`));
7534
7756
  console.log(chalk6.gray(`- Type: ${projectType}`));
7535
7757
  console.log(chalk6.gray(`- Lang: ${lang}`));
7536
7758
  console.log();
@@ -7703,7 +7925,7 @@ async function runView(featureName, options) {
7703
7925
  }
7704
7926
  console.log();
7705
7927
  console.log(chalk6.bold("\u{1F4CA} Workflow View"));
7706
- console.log(chalk6.gray(`- Docs: ${path18.relative(cwd, config.docsDir)}`));
7928
+ console.log(chalk6.gray(`- Docs: ${path19.relative(cwd, config.docsDir)}`));
7707
7929
  console.log(
7708
7930
  chalk6.gray(
7709
7931
  `- Features: ${state.features.length} (open ${state.openFeatures.length} / done ${state.doneFeatures.length})`
@@ -8076,25 +8298,25 @@ function tg(lang, key, vars = {}) {
8076
8298
  }
8077
8299
  function detectGithubCliLangSync(cwd) {
8078
8300
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
8079
- const startDirs = [explicitDocsDir ? path18.resolve(explicitDocsDir) : "", path18.resolve(cwd)].filter(Boolean);
8301
+ const startDirs = [explicitDocsDir ? path19.resolve(explicitDocsDir) : "", path19.resolve(cwd)].filter(Boolean);
8080
8302
  const scanOrder = [];
8081
8303
  const seen = /* @__PURE__ */ new Set();
8082
8304
  for (const start of startDirs) {
8083
8305
  let current = start;
8084
8306
  while (true) {
8085
- const abs = path18.resolve(current);
8307
+ const abs = path19.resolve(current);
8086
8308
  if (!seen.has(abs)) {
8087
8309
  scanOrder.push(abs);
8088
8310
  seen.add(abs);
8089
8311
  }
8090
- const parent = path18.dirname(abs);
8312
+ const parent = path19.dirname(abs);
8091
8313
  if (parent === abs) break;
8092
8314
  current = parent;
8093
8315
  }
8094
8316
  }
8095
8317
  for (const base of scanOrder) {
8096
- for (const docsDir of [path18.join(base, "docs"), base]) {
8097
- const configPath = path18.join(docsDir, ".lee-spec-kit.json");
8318
+ for (const docsDir of [path19.join(base, "docs"), base]) {
8319
+ const configPath = path19.join(docsDir, ".lee-spec-kit.json");
8098
8320
  if (fs15.existsSync(configPath)) {
8099
8321
  try {
8100
8322
  const parsed = fs15.readJsonSync(configPath);
@@ -8102,11 +8324,11 @@ function detectGithubCliLangSync(cwd) {
8102
8324
  } catch {
8103
8325
  }
8104
8326
  }
8105
- const agentsPath = path18.join(docsDir, "agents");
8106
- const featuresPath = path18.join(docsDir, "features");
8327
+ const agentsPath = path19.join(docsDir, "agents");
8328
+ const featuresPath = path19.join(docsDir, "features");
8107
8329
  if (!fs15.existsSync(agentsPath) || !fs15.existsSync(featuresPath)) continue;
8108
8330
  for (const probe of ["custom.md", "constitution.md", "agents.md"]) {
8109
- const file = path18.join(agentsPath, probe);
8331
+ const file = path19.join(agentsPath, probe);
8110
8332
  if (!fs15.existsSync(file)) continue;
8111
8333
  try {
8112
8334
  const content = fs15.readFileSync(file, "utf-8");
@@ -8204,7 +8426,7 @@ function ensureSections(body, sections, kind, lang) {
8204
8426
  }
8205
8427
  function ensureDocsExist(docsDir, relativePaths, lang) {
8206
8428
  const missing = relativePaths.filter(
8207
- (relativePath) => !fs15.existsSync(path18.join(docsDir, relativePath))
8429
+ (relativePath) => !fs15.existsSync(path19.join(docsDir, relativePath))
8208
8430
  );
8209
8431
  if (missing.length > 0) {
8210
8432
  throw createCliError(
@@ -8214,13 +8436,13 @@ function ensureDocsExist(docsDir, relativePaths, lang) {
8214
8436
  }
8215
8437
  }
8216
8438
  function buildDefaultBodyFileName(kind, docsDir, component) {
8217
- const key = `${path18.resolve(docsDir)}::${component.trim().toLowerCase()}`;
8439
+ const key = `${path19.resolve(docsDir)}::${component.trim().toLowerCase()}`;
8218
8440
  const digest = createHash("sha1").update(key).digest("hex").slice(0, 12);
8219
8441
  return `lee-spec-kit.${digest}.${kind}.md`;
8220
8442
  }
8221
8443
  function toBodyFilePath(raw, kind, docsDir, component) {
8222
- const selected = raw?.trim() || path18.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
8223
- return path18.resolve(selected);
8444
+ const selected = raw?.trim() || path19.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
8445
+ return path19.resolve(selected);
8224
8446
  }
8225
8447
  function toProjectRootDocsPath(relativePathFromDocs) {
8226
8448
  const normalized = relativePathFromDocs.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -9040,7 +9262,7 @@ function ensureCleanWorktree(cwd, lang) {
9040
9262
  }
9041
9263
  }
9042
9264
  function commitAndPushPath(cwd, absPath, message, lang) {
9043
- const relativePath = path18.relative(cwd, absPath) || absPath;
9265
+ const relativePath = path19.relative(cwd, absPath) || absPath;
9044
9266
  const status = runProcessOrThrow(
9045
9267
  "git",
9046
9268
  ["status", "--porcelain=v1", "--", relativePath],
@@ -9172,9 +9394,9 @@ function githubCommand(program2) {
9172
9394
  [paths.specPath, paths.planPath, paths.tasksPath],
9173
9395
  config.lang
9174
9396
  );
9175
- const specContent = await fs15.readFile(path18.join(config.docsDir, paths.specPath), "utf-8");
9176
- const planContent = await fs15.readFile(path18.join(config.docsDir, paths.planPath), "utf-8");
9177
- const tasksContent = await fs15.readFile(path18.join(config.docsDir, paths.tasksPath), "utf-8");
9397
+ const specContent = await fs15.readFile(path19.join(config.docsDir, paths.specPath), "utf-8");
9398
+ const planContent = await fs15.readFile(path19.join(config.docsDir, paths.planPath), "utf-8");
9399
+ const tasksContent = await fs15.readFile(path19.join(config.docsDir, paths.tasksPath), "utf-8");
9178
9400
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
9179
9401
  const title = options.title?.trim() || tg(config.lang, "issueDefaultTitle", {
9180
9402
  slug: feature.slug,
@@ -9212,7 +9434,7 @@ function githubCommand(program2) {
9212
9434
  config.lang
9213
9435
  );
9214
9436
  } else {
9215
- await fs15.ensureDir(path18.dirname(bodyFile));
9437
+ await fs15.ensureDir(path19.dirname(bodyFile));
9216
9438
  await fs15.writeFile(bodyFile, generatedBody, "utf-8");
9217
9439
  }
9218
9440
  let issueUrl;
@@ -9311,10 +9533,10 @@ function githubCommand(program2) {
9311
9533
  const labels = parseLabels(options.labels, config.lang);
9312
9534
  const paths = getFeatureDocPaths(feature);
9313
9535
  ensureDocsExist(config.docsDir, [paths.specPath, paths.tasksPath], config.lang);
9314
- const specContent = await fs15.readFile(path18.join(config.docsDir, paths.specPath), "utf-8");
9315
- const planPath = path18.join(config.docsDir, paths.planPath);
9536
+ const specContent = await fs15.readFile(path19.join(config.docsDir, paths.specPath), "utf-8");
9537
+ const planPath = path19.join(config.docsDir, paths.planPath);
9316
9538
  const planContent = await fs15.pathExists(planPath) ? await fs15.readFile(planPath, "utf-8") : "";
9317
- const tasksContent = await fs15.readFile(path18.join(config.docsDir, paths.tasksPath), "utf-8");
9539
+ const tasksContent = await fs15.readFile(path19.join(config.docsDir, paths.tasksPath), "utf-8");
9318
9540
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
9319
9541
  const defaultTitle = feature.issueNumber ? tg(config.lang, "prDefaultTitleWithIssue", {
9320
9542
  issue: feature.issueNumber,
@@ -9357,7 +9579,7 @@ function githubCommand(program2) {
9357
9579
  config.lang
9358
9580
  );
9359
9581
  } else {
9360
- await fs15.ensureDir(path18.dirname(bodyFile));
9582
+ await fs15.ensureDir(path19.dirname(bodyFile));
9361
9583
  await fs15.writeFile(bodyFile, generatedBody, "utf-8");
9362
9584
  }
9363
9585
  const retryCount = toRetryCount(options.retry, config.lang);
@@ -9411,7 +9633,7 @@ function githubCommand(program2) {
9411
9633
  }
9412
9634
  if (prUrl && options.syncTasks !== false) {
9413
9635
  const synced = syncTasksPrMetadata(
9414
- path18.join(config.docsDir, paths.tasksPath),
9636
+ path19.join(config.docsDir, paths.tasksPath),
9415
9637
  prUrl,
9416
9638
  "Review",
9417
9639
  config.lang
@@ -9458,7 +9680,7 @@ function githubCommand(program2) {
9458
9680
  );
9459
9681
  if (prUrl && options.syncTasks !== false) {
9460
9682
  const mergedSync = syncTasksPrMetadata(
9461
- path18.join(config.docsDir, paths.tasksPath),
9683
+ path19.join(config.docsDir, paths.tasksPath),
9462
9684
  prUrl,
9463
9685
  "Approved",
9464
9686
  config.lang
@@ -9663,7 +9885,7 @@ function docsCommand(program2) {
9663
9885
  );
9664
9886
  return;
9665
9887
  }
9666
- const relativeFromCwd = path18.relative(process.cwd(), loaded.entry.absolutePath);
9888
+ const relativeFromCwd = path19.relative(process.cwd(), loaded.entry.absolutePath);
9667
9889
  console.log();
9668
9890
  console.log(chalk6.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
9669
9891
  console.log(
@@ -9741,7 +9963,7 @@ function detectCommand(program2) {
9741
9963
  }
9742
9964
  async function runDetect(options) {
9743
9965
  const cwd = process.cwd();
9744
- const targetCwd = options.dir ? path18.resolve(cwd, options.dir) : cwd;
9966
+ const targetCwd = options.dir ? path19.resolve(cwd, options.dir) : cwd;
9745
9967
  const config = await getConfig(targetCwd);
9746
9968
  const detected = !!config;
9747
9969
  const reasonCode = detected ? "PROJECT_DETECTED" : "PROJECT_NOT_DETECTED";
@@ -9768,7 +9990,7 @@ async function runDetect(options) {
9768
9990
  );
9769
9991
  return;
9770
9992
  }
9771
- const configPath2 = path18.join(config.docsDir, ".lee-spec-kit.json");
9993
+ const configPath2 = path19.join(config.docsDir, ".lee-spec-kit.json");
9772
9994
  const configFilePresent2 = await fs15.pathExists(configPath2);
9773
9995
  const detectionSource2 = configFilePresent2 ? "config" : "heuristic";
9774
9996
  console.log(
@@ -9802,7 +10024,7 @@ async function runDetect(options) {
9802
10024
  console.log();
9803
10025
  return;
9804
10026
  }
9805
- const configPath = path18.join(config.docsDir, ".lee-spec-kit.json");
10027
+ const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
9806
10028
  const configFilePresent = await fs15.pathExists(configPath);
9807
10029
  const detectionSource = configFilePresent ? "config" : "heuristic";
9808
10030
  console.log(chalk6.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
@@ -9879,11 +10101,11 @@ ${version}
9879
10101
  }
9880
10102
  return `${ascii}${footer}`;
9881
10103
  }
9882
- var CACHE_FILE = path18.join(os.homedir(), ".lee-spec-kit-version-cache.json");
10104
+ var CACHE_FILE = path19.join(os.homedir(), ".lee-spec-kit-version-cache.json");
9883
10105
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
9884
10106
  function getCurrentVersion() {
9885
10107
  try {
9886
- const packageJsonPath = path18.join(__dirname$1, "..", "package.json");
10108
+ const packageJsonPath = path19.join(__dirname$1, "..", "package.json");
9887
10109
  if (fs15.existsSync(packageJsonPath)) {
9888
10110
  const pkg = fs15.readJsonSync(packageJsonPath);
9889
10111
  return pkg.version;
@@ -9987,7 +10209,7 @@ function shouldCheckForUpdates() {
9987
10209
  if (shouldCheckForUpdates()) checkForUpdates();
9988
10210
  function getCliVersion() {
9989
10211
  try {
9990
- const packageJsonPath = path18.join(__dirname$1, "..", "package.json");
10212
+ const packageJsonPath = path19.join(__dirname$1, "..", "package.json");
9991
10213
  if (fs15.existsSync(packageJsonPath)) {
9992
10214
  const pkg = fs15.readJsonSync(packageJsonPath);
9993
10215
  if (pkg?.version) return String(pkg.version);