lee-spec-kit 0.6.17 → 0.6.19

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 path19 from 'path';
2
+ import path20 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 = () => path19.dirname(getFilename());
14
+ var getDirname = () => path20.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 = path19.dirname(__filename2);
45
+ var __dirname2 = path20.dirname(__filename2);
46
46
  function getTemplatesDir() {
47
- const rootDir = path19.resolve(__dirname2, "..");
48
- return path19.join(rootDir, "templates");
47
+ const rootDir = path20.resolve(__dirname2, "..");
48
+ return path20.join(rootDir, "templates");
49
49
  }
50
50
 
51
51
  // src/utils/i18n.ts
@@ -118,7 +118,7 @@ var I18N = {
118
118
  "doctor.issue.planStatusUnset": "plan.md\uC758 Status(\uC0C1\uD0DC)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uD15C\uD50C\uB9BF \uADF8\uB300\uB85C\uC77C \uC218 \uC788\uC74C)",
119
119
  "doctor.issue.tasksEmpty": "tasks.md\uC5D0 \uD0DC\uC2A4\uD06C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
120
120
  "doctor.issue.tasksDocStatusUnset": "tasks.md\uC758 \uBB38\uC11C \uC0C1\uD0DC(Doc Status)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (Draft/Review/Approved \uC911 \uD558\uB098\uB85C \uC124\uC815\uD558\uC138\uC694.)",
121
- "doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: Draft | Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
121
+ "doctor.issue.tasksDocStatusMissing": "tasks.md\uC5D0 \uBB38\uC11C \uC0C1\uD0DC(Doc Status) \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **\uBB38\uC11C \uC0C1\uD0DC**: -`\uC640 `\uAC12: Draft | Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
122
122
  "doctor.issue.duplicateFeatureId": "\uC911\uBCF5 Feature ID \uAC10\uC9C0: {id} ({count}\uAC1C)",
123
123
  "doctor.issue.missingFeatureId": "Feature \uD3F4\uB354\uBA85\uC774 F001-... \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4. (ID\uB97C \uCD94\uCD9C\uD560 \uC218 \uC5C6\uC74C)",
124
124
  "context.noActiveFeatures": "\u26A0\uFE0F \uC9C4\uD589 \uC911\uC778 Feature\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
@@ -276,7 +276,7 @@ var I18N = {
276
276
  "github.operationPrMerge": "GitHub PR merge",
277
277
  "github.createIssueFailed": "GitHub issue \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
278
278
  "github.createPrFailed": "GitHub PR \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
279
- "github.mergeRequiresPr": "`--merge`\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 `--create` \uB610\uB294 `--pr <url|number>`\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
279
+ "github.mergeRequiresPr": "`--merge`\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 `--create`, `--pr <url|number>`, \uB610\uB294 tasks.md\uC758 PR \uB9C1\uD06C\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.",
280
280
  "github.checkoutBaseAfterMergeFailed": "merge \uD6C4 {base} \uBE0C\uB79C\uCE58 checkout\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
281
281
  "github.pullBaseAfterMergeFailed": "merge \uD6C4 {base} \uBE0C\uB79C\uCE58 \uCD5C\uC2E0\uD654\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
282
282
  "github.issueDefaultTitle": "{slug} ({summary})",
@@ -433,7 +433,7 @@ var I18N = {
433
433
  reviewFixCommitIssueGuidance: 'PR \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D\uC744 \uC694\uC57D\uD574\uC57C \uD558\uBA70, \uD0DC\uC2A4\uD06C \uC81C\uBAA9\uC744 \uC7AC\uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694. \uC608: `cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uB9AC\uBDF0 \uC218\uC815 \uBC18\uC601 \uD30C\uC77C\uB9CC git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "fix(#{issueNumber}): <review-fix-summary>")` (`<review-fix-summary>`\uB294 \uC774\uBC88 \uCEE4\uBC0B\uC5D0\uC11C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9\uC73C\uB85C \uC9C1\uC811 \uC791\uC131)',
434
434
  reviewFixCommitGuidance: 'PR \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D\uC744 \uC694\uC57D\uD574\uC57C \uD558\uBA70, \uD0DC\uC2A4\uD06C \uC81C\uBAA9\uC744 \uC7AC\uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694. \uC608: `cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uB9AC\uBDF0 \uC218\uC815 \uBC18\uC601 \uD30C\uC77C\uB9CC git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "fix(review): <review-fix-summary>")` (`<review-fix-summary>`\uB294 \uC774\uBC88 \uCEE4\uBC0B\uC5D0\uC11C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9\uC73C\uB85C \uC9C1\uC811 \uC791\uC131)',
435
435
  standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
436
- createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
436
+ createBranch: 'cd "{projectGitCwd}" && mkdir -p .worktrees && (git worktree add ".worktrees/feat-{issueNumber}-{slug}" "feat/{issueNumber}-{slug}" || git worktree add -b "feat/{issueNumber}-{slug}" ".worktrees/feat-{issueNumber}-{slug}") && echo "worktree: {projectGitCwd}/.worktrees/feat-{issueNumber}-{slug}"',
437
437
  tasksAllDoneButNoChecklist: '\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uB97C \uC791\uC131\uD558\uC138\uC694. tasks.md\uC758 "\uC644\uB8CC \uC870\uAC74" \uC139\uC158\uC5D0 \uAC80\uC99D \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0, \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uC138\uC694. \uCD5C\uC885 \uC2B9\uC778(OK)\uB3C4 \uBC18\uC601\uD558\uC138\uC694.',
438
438
  tasksAllDoneButChecklist: "\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uC758 \uB0A8\uC740 \uD56D\uBAA9\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uD604\uC7AC \uC9C4\uD589: ({checked}/{total}) \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uACE0 \uCD5C\uC885 \uC2B9\uC778(OK)\uC744 \uBC18\uC601\uD558\uC138\uC694.",
439
439
  finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC644\uB8CC\uD569\uB2C8\uB2E4: "{title}" ({done}/{total}) \uACB0\uACFC/\uAC80\uC99D \uACF5\uC720 + \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD) \uD6C4 DONE \uCC98\uB9AC',
@@ -443,7 +443,7 @@ var I18N = {
443
443
  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.",
444
444
  taskCommitGateReasonNoTasksCommit: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
445
445
  taskCommitGateReasonTasksFileUnavailable: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B \uC774\uB825\uC744 \uD310\uB3C5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
446
- taskCommitGateReasonDoneCount: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B \uC810\uAC80 \uACB0\uACFC\uAC00 \uC608\uC0C1\uACFC \uB2E4\uB985\uB2C8\uB2E4 ({count})",
446
+ taskCommitGateReasonDoneCount: "\uCD5C\uC2E0 tasks.md \uCEE4\uBC0B\uC5D0\uC11C DONE \uC804\uD658\uC774 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
447
447
  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",
448
448
  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)",
449
449
  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)",
@@ -467,16 +467,21 @@ var I18N = {
467
467
  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.",
468
468
  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.",
469
469
  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.)",
470
+ prReviewMergedSyncStatus: "\uC6D0\uACA9 PR\uC774 \uC774\uBBF8 \uBA38\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. (PR/\uB9AC\uBDF0 \uADFC\uAC70 \uD544\uB4DC\uB3C4 \uCD5C\uC2E0 \uC0C1\uD0DC\uB85C \uD655\uC778)",
470
471
  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.)",
471
472
  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.",
472
- 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.',
473
+ prReviewPush: 'cd "{projectGitCwd}" && git push',
473
474
  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.",
474
475
  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",
476
+ prReviewRemoteReasonClosed: "PR\uC774 \uBA38\uC9C0\uB418\uC9C0 \uC54A\uC740 \uCC44 \uB2EB\uD600 \uC788\uC2B5\uB2C8\uB2E4 (reopen \uB610\uB294 \uC0C8 PR \uD544\uC694)",
475
477
  prReviewRemoteReasonChecksFailing: "\uC2E4\uD328\uD55C \uCCB4\uD06C\uAC00 {count}\uAC74 \uC788\uC2B5\uB2C8\uB2E4",
476
478
  prReviewRemoteReasonChecksPending: "\uB300\uAE30 \uC911\uC778 \uCCB4\uD06C\uAC00 {count}\uAC74 \uC788\uC2B5\uB2C8\uB2E4",
477
479
  prReviewRemoteReasonMergeBlocked: "\uBA38\uC9C0 \uC0C1\uD0DC\uAC00 `{status}`\uB85C \uCC28\uB2E8\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4",
480
+ prReviewRemoteReasonUnavailable: "\uC6D0\uACA9 PR \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4 (gh \uC778\uC99D/\uB124\uD2B8\uC6CC\uD06C/\uAD8C\uD55C \uD655\uC778 \uD544\uC694)",
478
481
  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.)",
482
+ prReviewMergeCommand: "npx lee-spec-kit github pr {featureRef} --merge --confirm OK",
479
483
  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.",
484
+ userRequestReplan: "\uD604\uC7AC \uB2E8\uACC4\uC640 \uBCC4\uAC1C\uB85C \uC0AC\uC6A9\uC790\uAC00 \uC81C\uC548\uD55C \uC0C8 \uC694\uAD6C\uB97C \uBA3C\uC800 \uBC18\uC601\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC694\uAD6C\uC0AC\uD56D\uC744 \uC694\uC57D\uD574 tasks.md\uC5D0 \uCD94\uAC00\uD558\uAC70\uB098 \uBCC4\uB3C4 Feature\uB85C \uBD84\uB9AC\uD55C \uB4A4, \uBB38\uC11C \uC0C1\uD0DC\uB97C \uB9DE\uCD94\uACE0 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.",
480
485
  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.",
481
486
  fallbackRerunContext: "\uC0C1\uD0DC\uB97C \uD310\uBCC4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694."
482
487
  },
@@ -570,7 +575,7 @@ var I18N = {
570
575
  "doctor.issue.planStatusUnset": "plan.md Status is not set. (May still be a template)",
571
576
  "doctor.issue.tasksEmpty": "tasks.md has no tasks.",
572
577
  "doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Draft, Review, or Approved.)",
573
- "doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: Draft | Review | Approved`.",
578
+ "doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: -` and `Values: Draft | Review | Approved`.",
574
579
  "doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
575
580
  "doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
576
581
  "context.noActiveFeatures": "\u26A0\uFE0F No active features found.",
@@ -728,7 +733,7 @@ var I18N = {
728
733
  "github.operationPrMerge": "GitHub PR merge",
729
734
  "github.createIssueFailed": "Failed to create GitHub issue",
730
735
  "github.createPrFailed": "Failed to create GitHub PR",
731
- "github.mergeRequiresPr": "`--merge` requires `--create` or `--pr <url|number>`.",
736
+ "github.mergeRequiresPr": "`--merge` requires `--create`, `--pr <url|number>`, or a PR link in tasks.md.",
732
737
  "github.checkoutBaseAfterMergeFailed": "Failed to checkout {base} after merge",
733
738
  "github.pullBaseAfterMergeFailed": "Failed to update {base} after merge",
734
739
  "github.issueDefaultTitle": "{slug} ({summary})",
@@ -885,7 +890,7 @@ var I18N = {
885
890
  reviewFixCommitIssueGuidance: 'Commit PR review fixes. The commit message must summarize review comments resolved in this commit, not reuse a task title. Example: `cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files that implement review fixes with git add [files], then run again." && exit 1 || git commit -m "fix(#{issueNumber}): <review-fix-summary>")` (replace `<review-fix-summary>` with what this commit actually resolves).',
886
891
  reviewFixCommitGuidance: 'Commit PR review fixes. The commit message must summarize review comments resolved in this commit, not reuse a task title. Example: `cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files that implement review fixes with git add [files], then run again." && exit 1 || git commit -m "fix(review): <review-fix-summary>")` (replace `<review-fix-summary>` with what this commit actually resolves).',
887
892
  standaloneNeedsProjectRoot: "Standalone mode requires projectRoot. (npx lee-spec-kit config --project-root ...)",
888
- createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
893
+ createBranch: 'cd "{projectGitCwd}" && mkdir -p .worktrees && (git worktree add ".worktrees/feat-{issueNumber}-{slug}" "feat/{issueNumber}-{slug}" || git worktree add -b "feat/{issueNumber}-{slug}" ".worktrees/feat-{issueNumber}-{slug}") && echo "worktree: {projectGitCwd}/.worktrees/feat-{issueNumber}-{slug}"',
889
894
  tasksAllDoneButNoChecklist: 'Create the completion checklist. Add verification items to the tasks.md "Completion Criteria" section, then mark satisfied items as [x] after user confirmation. Record final approval (OK) as well.',
890
895
  tasksAllDoneButChecklist: "Proceed with remaining completion checklist items. Current progress: ({checked}/{total}) Mark items as [x] only after user confirmation and real verification. Record final approval (OK) as well.",
891
896
  finishDoingTask: 'Finish the current DOING/REVIEW task: "{title}" ({done}/{total}) Share outcome/verification + get OK before marking DONE',
@@ -895,7 +900,7 @@ var I18N = {
895
900
  taskCommitGateWarnProceed: "\u26A0\uFE0F Task commit boundary warning: {reason}. You may continue, but `1 task = 1 commit` is recommended.",
896
901
  taskCommitGateReasonNoTasksCommit: "No recent project code commit was found",
897
902
  taskCommitGateReasonTasksFileUnavailable: "Cannot read recent project code commit history",
898
- taskCommitGateReasonDoneCount: "Project commit gate check result is unexpected ({count})",
903
+ taskCommitGateReasonDoneCount: "DONE transitions detected in the latest tasks.md commit ({count})",
899
904
  taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
900
905
  prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
901
906
  prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
@@ -919,16 +924,21 @@ var I18N = {
919
924
  prCreateExecute: "Create the PR with the finalized body, then record the created PR link in tasks.md.",
920
925
  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.",
921
926
  prFillStatus: "Set PR Status in tasks.md to Review. (Keep Review during PR creation/review stages.)",
927
+ prReviewMergedSyncStatus: "The remote PR is already merged. Update PR Status in tasks.md to Approved. (Also verify PR/review evidence fields are up to date.)",
922
928
  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.)",
923
929
  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.",
924
- prReviewPush: 'To reflect review-fix commits on the PR head branch, get explicit user OK and run `cd "{projectGitCwd}" && git push`.',
930
+ prReviewPush: 'cd "{projectGitCwd}" && git push',
925
931
  prReviewRemoteBlocked: "Remote PR checks indicate this PR is not ready to merge yet: {reasons}. Resolve review comments/check statuses, then re-check.",
926
932
  prReviewRemoteReasonChangesRequested: "review decision is changes requested or additional review required",
933
+ prReviewRemoteReasonClosed: "PR is closed without merge (reopen or create a new PR)",
927
934
  prReviewRemoteReasonChecksFailing: "{count} failing check(s) detected",
928
935
  prReviewRemoteReasonChecksPending: "{count} pending check(s) detected",
929
936
  prReviewRemoteReasonMergeBlocked: "merge state is blocked (`{status}`)",
937
+ prReviewRemoteReasonUnavailable: "remote PR status could not be verified (check gh auth/network/permissions)",
930
938
  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.)",
939
+ prReviewMergeCommand: "npx lee-spec-kit github pr {featureRef} --merge --confirm OK",
931
940
  prRequestReview: "Request review and set/keep PR Status as Review.",
941
+ userRequestReplan: "You can pause this step and handle a newly requested user requirement first. Summarize it, add it to tasks.md or split it into a separate Feature, then align document statuses and rerun context.",
932
942
  featureDone: "Workflow requirements and all tasks/completion criteria are satisfied. This feature is done.",
933
943
  fallbackRerunContext: "Cannot determine status. Check the docs and run context again."
934
944
  },
@@ -1349,10 +1359,10 @@ function sleep(ms) {
1349
1359
  return new Promise((resolve) => globalThis.setTimeout(resolve, ms));
1350
1360
  }
1351
1361
  function toScopeKey(value) {
1352
- return createHash("sha1").update(path19.resolve(value)).digest("hex").slice(0, 16);
1362
+ return createHash("sha1").update(path20.resolve(value)).digest("hex").slice(0, 16);
1353
1363
  }
1354
1364
  function getTempRuntimeDir(scopePath) {
1355
- return path19.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1365
+ return path20.join(os.tmpdir(), RUNTIME_TEMP_DIRNAME, toScopeKey(scopePath));
1356
1366
  }
1357
1367
  function resolveGitRuntimeDir(cwd) {
1358
1368
  try {
@@ -1366,38 +1376,38 @@ function resolveGitRuntimeDir(cwd) {
1366
1376
  }
1367
1377
  ).trim();
1368
1378
  if (!out) return null;
1369
- return path19.isAbsolute(out) ? out : path19.resolve(cwd, out);
1379
+ return path20.isAbsolute(out) ? out : path20.resolve(cwd, out);
1370
1380
  } catch {
1371
1381
  return null;
1372
1382
  }
1373
1383
  }
1374
1384
  function getRuntimeStateDir(cwd) {
1375
- const resolved = path19.resolve(cwd);
1385
+ const resolved = path20.resolve(cwd);
1376
1386
  return resolveGitRuntimeDir(resolved) ?? getTempRuntimeDir(resolved);
1377
1387
  }
1378
1388
  function getDocsLockPath(docsDir) {
1379
- return path19.join(
1389
+ return path20.join(
1380
1390
  getRuntimeStateDir(docsDir),
1381
1391
  "locks",
1382
1392
  `docs-${toScopeKey(docsDir)}.lock`
1383
1393
  );
1384
1394
  }
1385
1395
  function getInitLockPath(targetDir) {
1386
- return path19.join(
1387
- getRuntimeStateDir(path19.dirname(path19.resolve(targetDir))),
1396
+ return path20.join(
1397
+ getRuntimeStateDir(path20.dirname(path20.resolve(targetDir))),
1388
1398
  "locks",
1389
1399
  `init-${toScopeKey(targetDir)}.lock`
1390
1400
  );
1391
1401
  }
1392
1402
  function getApprovalTicketStorePath(docsDir) {
1393
- return path19.join(
1403
+ return path20.join(
1394
1404
  getRuntimeStateDir(docsDir),
1395
1405
  "tickets",
1396
1406
  `approval-${toScopeKey(docsDir)}.json`
1397
1407
  );
1398
1408
  }
1399
1409
  function getProjectExecutionLockPath(cwd) {
1400
- return path19.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1410
+ return path20.join(getRuntimeStateDir(cwd), "locks", "project.lock");
1401
1411
  }
1402
1412
  async function isStaleLock(lockPath, staleMs) {
1403
1413
  try {
@@ -1438,7 +1448,7 @@ function isProcessAlive(pid) {
1438
1448
  }
1439
1449
  }
1440
1450
  async function tryAcquire(lockPath, owner) {
1441
- await fs15.ensureDir(path19.dirname(lockPath));
1451
+ await fs15.ensureDir(path20.dirname(lockPath));
1442
1452
  try {
1443
1453
  const fd = await fs15.open(lockPath, "wx");
1444
1454
  const payload = JSON.stringify(
@@ -1515,30 +1525,30 @@ var ENGINE_MANAGED_AGENT_FILES = [
1515
1525
  "pr-template.md"
1516
1526
  ];
1517
1527
  var ENGINE_MANAGED_AGENT_DIRS = ["skills"];
1518
- var ENGINE_MANAGED_FEATURE_PATH = path19.join(
1528
+ var ENGINE_MANAGED_FEATURE_PATH = path20.join(
1519
1529
  "features",
1520
1530
  "feature-base"
1521
1531
  );
1522
1532
  async function pruneEngineManagedDocs(docsDir) {
1523
1533
  const removed = [];
1524
1534
  for (const file of ENGINE_MANAGED_AGENT_FILES) {
1525
- const target = path19.join(docsDir, "agents", file);
1535
+ const target = path20.join(docsDir, "agents", file);
1526
1536
  if (await fs15.pathExists(target)) {
1527
1537
  await fs15.remove(target);
1528
- removed.push(path19.relative(docsDir, target));
1538
+ removed.push(path20.relative(docsDir, target));
1529
1539
  }
1530
1540
  }
1531
1541
  for (const dir of ENGINE_MANAGED_AGENT_DIRS) {
1532
- const target = path19.join(docsDir, "agents", dir);
1542
+ const target = path20.join(docsDir, "agents", dir);
1533
1543
  if (await fs15.pathExists(target)) {
1534
1544
  await fs15.remove(target);
1535
- removed.push(path19.relative(docsDir, target));
1545
+ removed.push(path20.relative(docsDir, target));
1536
1546
  }
1537
1547
  }
1538
- const featureBasePath = path19.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1548
+ const featureBasePath = path20.join(docsDir, ENGINE_MANAGED_FEATURE_PATH);
1539
1549
  if (await fs15.pathExists(featureBasePath)) {
1540
1550
  await fs15.remove(featureBasePath);
1541
- removed.push(path19.relative(docsDir, featureBasePath));
1551
+ removed.push(path20.relative(docsDir, featureBasePath));
1542
1552
  }
1543
1553
  return removed;
1544
1554
  }
@@ -1679,7 +1689,7 @@ ${tr(lang2, "cli", "common.canceled")}`)
1679
1689
  }
1680
1690
  async function runInit(options) {
1681
1691
  const cwd = process.cwd();
1682
- const defaultName = path19.basename(cwd);
1692
+ const defaultName = path20.basename(cwd);
1683
1693
  let projectName = options.name || defaultName;
1684
1694
  let projectType = options.type;
1685
1695
  let components = parseComponentsOption(options.components);
@@ -1692,7 +1702,7 @@ async function runInit(options) {
1692
1702
  const componentProjectRoots = parseComponentProjectRootsOption(
1693
1703
  options.componentProjectRoots
1694
1704
  );
1695
- const targetDir = path19.resolve(cwd, options.dir || "./docs");
1705
+ const targetDir = path20.resolve(cwd, options.dir || "./docs");
1696
1706
  const skipPrompts = !!options.yes || !!options.nonInteractive;
1697
1707
  if (options.docsRepo && !["embedded", "standalone"].includes(options.docsRepo)) {
1698
1708
  throw createCliError(
@@ -2081,7 +2091,7 @@ async function runInit(options) {
2081
2091
  );
2082
2092
  console.log();
2083
2093
  const templatesDir = getTemplatesDir();
2084
- const commonPath = path19.join(templatesDir, lang, "common");
2094
+ const commonPath = path20.join(templatesDir, lang, "common");
2085
2095
  if (!await fs15.pathExists(commonPath)) {
2086
2096
  throw new Error(
2087
2097
  tr(lang, "cli", "init.error.templateNotFound", { path: commonPath })
@@ -2089,11 +2099,11 @@ async function runInit(options) {
2089
2099
  }
2090
2100
  await copyTemplates(commonPath, targetDir);
2091
2101
  if (projectType === "multi") {
2092
- const featuresRoot = path19.join(targetDir, "features");
2102
+ const featuresRoot = path20.join(targetDir, "features");
2093
2103
  for (const component of components) {
2094
- const componentDir = path19.join(featuresRoot, component);
2104
+ const componentDir = path20.join(featuresRoot, component);
2095
2105
  await fs15.ensureDir(componentDir);
2096
- const readmePath = path19.join(componentDir, "README.md");
2106
+ const readmePath = path20.join(componentDir, "README.md");
2097
2107
  if (!await fs15.pathExists(readmePath)) {
2098
2108
  await fs15.writeFile(
2099
2109
  readmePath,
@@ -2122,7 +2132,7 @@ async function runInit(options) {
2122
2132
  workflow: {
2123
2133
  mode: workflowMode,
2124
2134
  codeDirtyScope: "auto",
2125
- taskCommitGate: "strict",
2135
+ taskCommitGate: "warn",
2126
2136
  prePrReview: {
2127
2137
  skills: ["code-review-excellence"],
2128
2138
  minorPolicy: "warn"
@@ -2146,7 +2156,7 @@ async function runInit(options) {
2146
2156
  config.projectRoot = projectRoot;
2147
2157
  }
2148
2158
  }
2149
- const configPath = path19.join(targetDir, ".lee-spec-kit.json");
2159
+ const configPath = path20.join(targetDir, ".lee-spec-kit.json");
2150
2160
  await fs15.writeJson(configPath, config, { spaces: 2 });
2151
2161
  console.log(chalk6.green(tr(lang, "cli", "init.log.docsCreated")));
2152
2162
  console.log();
@@ -2217,7 +2227,7 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2217
2227
  console.log(chalk6.blue(tr(lang, "cli", "init.log.gitInit")));
2218
2228
  runGit2(["init"], gitWorkdir);
2219
2229
  }
2220
- const relativePath = docsRepo === "standalone" ? "." : path19.relative(cwd, targetDir);
2230
+ const relativePath = docsRepo === "standalone" ? "." : path20.relative(cwd, targetDir);
2221
2231
  const stagedBeforeAdd = getCachedStagedFiles(gitWorkdir);
2222
2232
  if (relativePath === "." && stagedBeforeAdd && stagedBeforeAdd.length > 0) {
2223
2233
  console.log(
@@ -2274,17 +2284,17 @@ async function initGit(cwd, targetDir, docsRepo, lang, pushDocs, docsRemote) {
2274
2284
  }
2275
2285
  function getAncestorDirs(startDir) {
2276
2286
  const dirs = [];
2277
- let current = path19.resolve(startDir);
2287
+ let current = path20.resolve(startDir);
2278
2288
  while (true) {
2279
2289
  dirs.push(current);
2280
- const parent = path19.dirname(current);
2290
+ const parent = path20.dirname(current);
2281
2291
  if (parent === current) break;
2282
2292
  current = parent;
2283
2293
  }
2284
2294
  return dirs;
2285
2295
  }
2286
2296
  function hasWorkspaceBoundary(dir) {
2287
- return fs15.existsSync(path19.join(dir, "package.json")) || fs15.existsSync(path19.join(dir, ".git"));
2297
+ return fs15.existsSync(path20.join(dir, "package.json")) || fs15.existsSync(path20.join(dir, ".git"));
2288
2298
  }
2289
2299
  function getSearchBaseDirs(cwd) {
2290
2300
  const ancestors = getAncestorDirs(cwd);
@@ -2300,7 +2310,7 @@ function normalizeComponentKeys(value) {
2300
2310
  return Object.keys(value).map((key) => key.trim().toLowerCase()).filter(Boolean);
2301
2311
  }
2302
2312
  async function inferComponentsFromFeaturesDir(docsDir) {
2303
- const featuresPath = path19.join(docsDir, "features");
2313
+ const featuresPath = path20.join(docsDir, "features");
2304
2314
  if (!await fs15.pathExists(featuresPath)) return [];
2305
2315
  const entries = await fs15.readdir(featuresPath, { withFileTypes: true });
2306
2316
  const inferred = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name.trim().toLowerCase()).filter(
@@ -2311,21 +2321,21 @@ async function inferComponentsFromFeaturesDir(docsDir) {
2311
2321
  async function getConfig(cwd) {
2312
2322
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2313
2323
  const baseDirs = [
2314
- ...explicitDocsDir ? [path19.resolve(explicitDocsDir)] : [],
2324
+ ...explicitDocsDir ? [path20.resolve(explicitDocsDir)] : [],
2315
2325
  ...getSearchBaseDirs(cwd)
2316
2326
  ];
2317
2327
  const visitedBaseDirs = /* @__PURE__ */ new Set();
2318
2328
  const visitedDocsDirs = /* @__PURE__ */ new Set();
2319
2329
  for (const baseDir of baseDirs) {
2320
- const resolvedBaseDir = path19.resolve(baseDir);
2330
+ const resolvedBaseDir = path20.resolve(baseDir);
2321
2331
  if (visitedBaseDirs.has(resolvedBaseDir)) continue;
2322
2332
  visitedBaseDirs.add(resolvedBaseDir);
2323
- const possibleDocsDirs = [path19.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2333
+ const possibleDocsDirs = [path20.join(resolvedBaseDir, "docs"), resolvedBaseDir];
2324
2334
  for (const docsDir of possibleDocsDirs) {
2325
- const resolvedDocsDir = path19.resolve(docsDir);
2335
+ const resolvedDocsDir = path20.resolve(docsDir);
2326
2336
  if (visitedDocsDirs.has(resolvedDocsDir)) continue;
2327
2337
  visitedDocsDirs.add(resolvedDocsDir);
2328
- const configPath = path19.join(resolvedDocsDir, ".lee-spec-kit.json");
2338
+ const configPath = path20.join(resolvedDocsDir, ".lee-spec-kit.json");
2329
2339
  if (await fs15.pathExists(configPath)) {
2330
2340
  try {
2331
2341
  const configFile = await fs15.readJson(configPath);
@@ -2355,16 +2365,16 @@ async function getConfig(cwd) {
2355
2365
  } catch {
2356
2366
  }
2357
2367
  }
2358
- const agentsPath = path19.join(resolvedDocsDir, "agents");
2359
- const featuresPath = path19.join(resolvedDocsDir, "features");
2368
+ const agentsPath = path20.join(resolvedDocsDir, "agents");
2369
+ const featuresPath = path20.join(resolvedDocsDir, "features");
2360
2370
  if (await fs15.pathExists(agentsPath) && await fs15.pathExists(featuresPath)) {
2361
2371
  const inferredComponents = await inferComponentsFromFeaturesDir(resolvedDocsDir);
2362
2372
  const projectType = inferredComponents.length > 0 ? "multi" : "single";
2363
2373
  const components = projectType === "multi" ? resolveProjectComponents("multi", inferredComponents) : void 0;
2364
2374
  const langProbeCandidates = [
2365
- path19.join(agentsPath, "custom.md"),
2366
- path19.join(agentsPath, "constitution.md"),
2367
- path19.join(agentsPath, "agents.md")
2375
+ path20.join(agentsPath, "custom.md"),
2376
+ path20.join(agentsPath, "constitution.md"),
2377
+ path20.join(agentsPath, "agents.md")
2368
2378
  ];
2369
2379
  let lang = "en";
2370
2380
  for (const candidate of langProbeCandidates) {
@@ -2430,13 +2440,13 @@ async function patchMarkdownIfExists(filePath, transform) {
2430
2440
  await fs15.writeFile(filePath, transform(content), "utf-8");
2431
2441
  }
2432
2442
  async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
2433
- await patchMarkdownIfExists(path19.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2443
+ await patchMarkdownIfExists(path20.join(featureDir, "spec.md"), sanitizeSpecForLocal);
2434
2444
  await patchMarkdownIfExists(
2435
- path19.join(featureDir, "tasks.md"),
2445
+ path20.join(featureDir, "tasks.md"),
2436
2446
  (content) => sanitizeTasksForLocal(content, lang)
2437
2447
  );
2438
- await fs15.remove(path19.join(featureDir, "issue.md"));
2439
- await fs15.remove(path19.join(featureDir, "pr.md"));
2448
+ await fs15.remove(path20.join(featureDir, "issue.md"));
2449
+ await fs15.remove(path20.join(featureDir, "pr.md"));
2440
2450
  }
2441
2451
 
2442
2452
  // src/commands/feature.ts
@@ -2581,19 +2591,19 @@ async function runFeature(name, options) {
2581
2591
  }
2582
2592
  let featuresDir;
2583
2593
  if (projectType === "multi") {
2584
- featuresDir = path19.join(docsDir, "features", component);
2594
+ featuresDir = path20.join(docsDir, "features", component);
2585
2595
  } else {
2586
- featuresDir = path19.join(docsDir, "features");
2596
+ featuresDir = path20.join(docsDir, "features");
2587
2597
  }
2588
2598
  const featureFolderName = `${featureId}-${name}`;
2589
- const featureDir = path19.join(featuresDir, featureFolderName);
2599
+ const featureDir = path20.join(featuresDir, featureFolderName);
2590
2600
  if (await fs15.pathExists(featureDir)) {
2591
2601
  throw createCliError(
2592
2602
  "INVALID_ARGUMENT",
2593
2603
  tr(lang, "cli", "feature.folderExists", { path: featureDir })
2594
2604
  );
2595
2605
  }
2596
- const featureBasePath = path19.join(
2606
+ const featureBasePath = path20.join(
2597
2607
  getTemplatesDir(),
2598
2608
  lang,
2599
2609
  "common",
@@ -2652,7 +2662,7 @@ async function runFeature(name, options) {
2652
2662
  featureName: name,
2653
2663
  component: projectType === "multi" ? component : void 0,
2654
2664
  featurePath: featureDir,
2655
- featurePathFromDocs: path19.relative(docsDir, featureDir)
2665
+ featurePathFromDocs: path20.relative(docsDir, featureDir)
2656
2666
  };
2657
2667
  },
2658
2668
  { owner: "feature" }
@@ -2664,9 +2674,9 @@ function sleep2(ms) {
2664
2674
  async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2665
2675
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
2666
2676
  const candidates = [
2667
- ...explicitDocsDir ? [path19.resolve(explicitDocsDir)] : [],
2668
- path19.resolve(cwd, "docs"),
2669
- path19.resolve(cwd)
2677
+ ...explicitDocsDir ? [path20.resolve(explicitDocsDir)] : [],
2678
+ path20.resolve(cwd, "docs"),
2679
+ path20.resolve(cwd)
2670
2680
  ];
2671
2681
  const endAt = Date.now() + timeoutMs;
2672
2682
  while (Date.now() < endAt) {
@@ -2693,11 +2703,11 @@ async function waitForConfigAfterInit(cwd, timeoutMs = 8e3) {
2693
2703
  return getConfig(cwd);
2694
2704
  }
2695
2705
  async function getNextFeatureId(docsDir, projectType, components) {
2696
- const featuresDir = path19.join(docsDir, "features");
2706
+ const featuresDir = path20.join(docsDir, "features");
2697
2707
  let max = 0;
2698
2708
  const scanDirs = [];
2699
2709
  if (projectType === "multi") {
2700
- scanDirs.push(...components.map((component) => path19.join(featuresDir, component)));
2710
+ scanDirs.push(...components.map((component) => path20.join(featuresDir, component)));
2701
2711
  } else {
2702
2712
  scanDirs.push(featuresDir);
2703
2713
  }
@@ -2846,6 +2856,9 @@ function getPrReviewRemoteBlockReasons(feature, lang) {
2846
2856
  const remote = feature.pr.remote;
2847
2857
  if (!remote || !remote.available) return [];
2848
2858
  const reasons = [];
2859
+ if (remote.state === "CLOSED" && !remote.isMerged) {
2860
+ reasons.push(tr(lang, "messages", "prReviewRemoteReasonClosed"));
2861
+ }
2849
2862
  if (remote.hasBlockingReview) {
2850
2863
  reasons.push(tr(lang, "messages", "prReviewRemoteReasonChangesRequested"));
2851
2864
  }
@@ -2911,14 +2924,90 @@ function normalizeTaskTopic(value) {
2911
2924
  function normalizeCommitSubjectForGate(value) {
2912
2925
  return normalizeCommitTopicText(value).replace(/^[a-z]+(?:\([^)]*\))?!?:\s*/i, "").toLowerCase();
2913
2926
  }
2927
+ function toTaskKey(rawTitle) {
2928
+ const trimmed = normalizeCommitTopicText(rawTitle);
2929
+ if (!trimmed) return "";
2930
+ const idMatch = trimmed.match(/^(T-[A-Za-z0-9-]+)/i);
2931
+ if (idMatch) return idMatch[1].toUpperCase();
2932
+ return normalizeTaskTopic(trimmed).toLowerCase();
2933
+ }
2934
+ function countDoneTransitionsInLatestTasksCommit(feature) {
2935
+ const docsGitCwd = feature.git.docsGitCwd;
2936
+ const tasksRelativePath = normalizeGitRelativePath(
2937
+ path20.join(feature.docs.featurePathFromDocs, "tasks.md")
2938
+ );
2939
+ const diff = readGitText(docsGitCwd, [
2940
+ "diff",
2941
+ "--unified=0",
2942
+ "--no-color",
2943
+ "HEAD~1",
2944
+ "HEAD",
2945
+ "--",
2946
+ tasksRelativePath
2947
+ ]);
2948
+ if (diff === void 0) return 0;
2949
+ if (!diff.trim()) return 0;
2950
+ const removedByTask = /* @__PURE__ */ new Map();
2951
+ const addedByTask = /* @__PURE__ */ new Map();
2952
+ const parseTaskLine = (line) => {
2953
+ const match = line.match(/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\s+(.+?)\s*$/i);
2954
+ if (!match) return null;
2955
+ const key = toTaskKey(match[2]);
2956
+ if (!key) return null;
2957
+ return {
2958
+ key,
2959
+ status: match[1].toUpperCase()
2960
+ };
2961
+ };
2962
+ for (const line of diff.split("\n")) {
2963
+ if (line.startsWith("---") || line.startsWith("+++")) continue;
2964
+ if (line.startsWith("-")) {
2965
+ const parsed = parseTaskLine(line.slice(1));
2966
+ if (!parsed) continue;
2967
+ const existing = removedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
2968
+ existing.add(parsed.status);
2969
+ removedByTask.set(parsed.key, existing);
2970
+ continue;
2971
+ }
2972
+ if (line.startsWith("+")) {
2973
+ const parsed = parseTaskLine(line.slice(1));
2974
+ if (!parsed) continue;
2975
+ const existing = addedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
2976
+ existing.add(parsed.status);
2977
+ addedByTask.set(parsed.key, existing);
2978
+ }
2979
+ }
2980
+ let doneTransitions = 0;
2981
+ for (const [taskKey, addedStatuses] of addedByTask.entries()) {
2982
+ if (!addedStatuses.has("DONE")) continue;
2983
+ const removedStatuses = removedByTask.get(taskKey);
2984
+ if (!removedStatuses) continue;
2985
+ const transitionedFromOpen = removedStatuses.has("TODO") || removedStatuses.has("DOING") || removedStatuses.has("REVIEW");
2986
+ if (transitionedFromOpen) {
2987
+ doneTransitions += 1;
2988
+ }
2989
+ }
2990
+ return doneTransitions;
2991
+ }
2914
2992
  function checkTaskCommitGate(feature) {
2993
+ const doneTransitions = countDoneTransitionsInLatestTasksCommit(feature);
2994
+ if (doneTransitions === 0) {
2995
+ return { pass: true, doneTransitions };
2996
+ }
2997
+ if (typeof doneTransitions === "number" && doneTransitions > 1) {
2998
+ return {
2999
+ pass: false,
3000
+ reason: "DONE_TRANSITIONS_COUNT",
3001
+ doneTransitions
3002
+ };
3003
+ }
2915
3004
  const projectGitCwd = feature.git.projectGitCwd;
2916
3005
  const lastDoneTopic = normalizeTaskTopic(feature.lastDoneTask?.title || "");
2917
3006
  if (!projectGitCwd || !lastDoneTopic) {
2918
3007
  return { pass: true };
2919
3008
  }
2920
3009
  const args = ["log", "-n", "1", "--pretty=%s", "--", "."];
2921
- const relativeDocsDir = path19.relative(projectGitCwd, feature.git.docsGitCwd);
3010
+ const relativeDocsDir = path20.relative(projectGitCwd, feature.git.docsGitCwd);
2922
3011
  const normalizedDocsDir = normalizeGitRelativePath(relativeDocsDir);
2923
3012
  if (normalizedDocsDir && normalizedDocsDir !== "." && normalizedDocsDir !== ".." && !normalizedDocsDir.startsWith("../")) {
2924
3013
  args.push(`:(exclude)${normalizedDocsDir}/**`);
@@ -2939,6 +3028,10 @@ function checkTaskCommitGate(feature) {
2939
3028
  }
2940
3029
  function getTaskCommitGateReasonText(lang, check) {
2941
3030
  switch (check.reason) {
3031
+ case "DONE_TRANSITIONS_COUNT":
3032
+ return tr(lang, "messages", "taskCommitGateReasonDoneCount", {
3033
+ count: check.doneTransitions || 0
3034
+ });
2942
3035
  case "NO_PROJECT_COMMIT":
2943
3036
  return tr(lang, "messages", "taskCommitGateReasonNoTasksCommit");
2944
3037
  case "PROJECT_LOG_UNAVAILABLE":
@@ -3752,6 +3845,16 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3752
3845
  ];
3753
3846
  }
3754
3847
  if (f.pr.status === "Review") {
3848
+ if (f.pr.remote?.available && f.pr.remote.isMerged) {
3849
+ return [
3850
+ {
3851
+ type: "instruction",
3852
+ category: "pr_status_update",
3853
+ requiresUserCheck: true,
3854
+ message: tr(lang, "messages", "prReviewMergedSyncStatus")
3855
+ }
3856
+ ];
3857
+ }
3755
3858
  if (!f.docs.prReviewFindingsFieldExists) {
3756
3859
  return [
3757
3860
  {
@@ -3793,6 +3896,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3793
3896
  ];
3794
3897
  }
3795
3898
  const remoteBlockReasons = getPrReviewRemoteBlockReasons(f, lang);
3899
+ const remoteUnavailable = workflowPolicy.mode === "github" && !!f.pr.link && (!f.pr.remote || !f.pr.remote.available);
3796
3900
  const actions = [
3797
3901
  {
3798
3902
  type: "instruction",
@@ -3820,16 +3924,41 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3820
3924
  })
3821
3925
  });
3822
3926
  }
3823
- actions.push({
3824
- type: "instruction",
3825
- category: "code_review",
3826
- requiresUserCheck: true,
3827
- message: remoteBlockReasons.length > 0 ? tr(lang, "messages", "prReviewRemoteBlocked", {
3828
- reasons: remoteBlockReasons.join("; ")
3829
- }) : tr(lang, "messages", "prReviewMerge", {
3830
- featureRef: f.id || f.folderName
3831
- })
3832
- });
3927
+ if (remoteBlockReasons.length > 0 || remoteUnavailable) {
3928
+ const reasons = [...remoteBlockReasons];
3929
+ if (remoteUnavailable) {
3930
+ reasons.push(tr(lang, "messages", "prReviewRemoteReasonUnavailable"));
3931
+ }
3932
+ actions.push({
3933
+ type: "instruction",
3934
+ category: "code_review",
3935
+ requiresUserCheck: true,
3936
+ message: tr(lang, "messages", "prReviewRemoteBlocked", {
3937
+ reasons: reasons.join("; ")
3938
+ })
3939
+ });
3940
+ } else if (f.git.docsGitCwd) {
3941
+ actions.push({
3942
+ type: "command",
3943
+ category: "code_review",
3944
+ requiresUserCheck: true,
3945
+ operationType: "remote",
3946
+ scope: "docs",
3947
+ cwd: f.git.docsGitCwd,
3948
+ cmd: tr(lang, "messages", "prReviewMergeCommand", {
3949
+ featureRef: f.id || f.folderName
3950
+ })
3951
+ });
3952
+ } else {
3953
+ actions.push({
3954
+ type: "instruction",
3955
+ category: "code_review",
3956
+ requiresUserCheck: true,
3957
+ message: tr(lang, "messages", "prReviewMerge", {
3958
+ featureRef: f.id || f.folderName
3959
+ })
3960
+ });
3961
+ }
3833
3962
  return actions;
3834
3963
  }
3835
3964
  return [
@@ -3907,14 +4036,32 @@ function applyApprovalPolicy(step, actions, approval) {
3907
4036
  return { ...a, requiresUserCheck };
3908
4037
  });
3909
4038
  }
4039
+ function withUserRequestReplanOption(actions, lang) {
4040
+ if (actions.some((action) => action.category === "user_request_replan")) {
4041
+ return actions;
4042
+ }
4043
+ return [
4044
+ ...actions,
4045
+ {
4046
+ type: "instruction",
4047
+ category: "user_request_replan",
4048
+ requiresUserCheck: true,
4049
+ message: tr(lang, "messages", "userRequestReplan")
4050
+ }
4051
+ ];
4052
+ }
3910
4053
  function resolveFeatureProgress(feature, stepDefinitions, lang, approval) {
3911
4054
  const ordered = [...stepDefinitions].sort((a, b) => a.step - b.step);
3912
4055
  for (const definition of ordered) {
3913
4056
  if (!definition.current) continue;
3914
4057
  if (definition.current.when(feature)) {
4058
+ const currentActions = withUserRequestReplanOption(
4059
+ definition.current.actions(feature),
4060
+ lang
4061
+ );
3915
4062
  const actions = applyApprovalPolicy(
3916
4063
  definition.step,
3917
- definition.current.actions(feature),
4064
+ currentActions,
3918
4065
  approval
3919
4066
  );
3920
4067
  return {
@@ -4040,6 +4187,10 @@ function isGitPathIgnored(cwd, relativePath) {
4040
4187
  return void 0;
4041
4188
  }
4042
4189
  }
4190
+ var GIT_WORKTREE_CACHE = /* @__PURE__ */ new Map();
4191
+ function resetContextGitCaches() {
4192
+ GIT_WORKTREE_CACHE.clear();
4193
+ }
4043
4194
  function getGitTopLevel(cwd) {
4044
4195
  try {
4045
4196
  return execSync("git rev-parse --show-toplevel", {
@@ -4051,6 +4202,52 @@ function getGitTopLevel(cwd) {
4051
4202
  return null;
4052
4203
  }
4053
4204
  }
4205
+ function listGitWorktrees(cwd) {
4206
+ const topLevel = getGitTopLevel(cwd) || cwd;
4207
+ const cacheKey = path20.resolve(topLevel);
4208
+ const cached = GIT_WORKTREE_CACHE.get(cacheKey);
4209
+ if (cached) return cached;
4210
+ try {
4211
+ const out = execFileSync("git", ["worktree", "list", "--porcelain"], {
4212
+ cwd: topLevel,
4213
+ encoding: "utf-8",
4214
+ stdio: ["ignore", "pipe", "pipe"]
4215
+ });
4216
+ const entries = [];
4217
+ let current = null;
4218
+ for (const rawLine of out.split("\n")) {
4219
+ const line = rawLine.trim();
4220
+ if (!line) {
4221
+ if (current?.path) entries.push(current);
4222
+ current = null;
4223
+ continue;
4224
+ }
4225
+ if (line.startsWith("worktree ")) {
4226
+ if (current?.path) entries.push(current);
4227
+ current = { path: line.slice("worktree ".length).trim() };
4228
+ continue;
4229
+ }
4230
+ if (line.startsWith("branch ")) {
4231
+ if (!current) continue;
4232
+ const fullRef = line.slice("branch ".length).trim();
4233
+ current.branch = fullRef.replace(/^refs\/heads\//, "");
4234
+ }
4235
+ }
4236
+ if (current?.path) entries.push(current);
4237
+ GIT_WORKTREE_CACHE.set(cacheKey, entries);
4238
+ return entries;
4239
+ } catch {
4240
+ return void 0;
4241
+ }
4242
+ }
4243
+ function findWorktreePathForBranch(cwd, branchName) {
4244
+ const target = branchName.trim();
4245
+ if (!target) return void 0;
4246
+ const entries = listGitWorktrees(cwd);
4247
+ if (!entries) return void 0;
4248
+ const match = entries.find((entry) => entry.branch === target);
4249
+ return match?.path;
4250
+ }
4054
4251
  function resolveProjectGitCwd(config, repo, lang = config.lang ?? DEFAULT_LANG) {
4055
4252
  const docsRepo = config.docsRepo;
4056
4253
  if (docsRepo !== "standalone") {
@@ -4204,13 +4401,13 @@ function parsePrLink(value) {
4204
4401
  return trimmed;
4205
4402
  }
4206
4403
  function normalizeGitPath(value) {
4207
- return value.split(path19.sep).join("/");
4404
+ return value.split(path20.sep).join("/");
4208
4405
  }
4209
4406
  function resolveProjectStatusPaths(projectGitCwd, docsDir) {
4210
- const relativeDocsDir = path19.relative(projectGitCwd, docsDir);
4407
+ const relativeDocsDir = path20.relative(projectGitCwd, docsDir);
4211
4408
  if (!relativeDocsDir) return [];
4212
- if (path19.isAbsolute(relativeDocsDir)) return [];
4213
- if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path19.sep}`)) {
4409
+ if (path20.isAbsolute(relativeDocsDir)) return [];
4410
+ if (relativeDocsDir === ".." || relativeDocsDir.startsWith(`..${path20.sep}`)) {
4214
4411
  return [];
4215
4412
  }
4216
4413
  const normalizedDocsDir = normalizeGitPath(relativeDocsDir).replace(/\/+$/, "");
@@ -4232,6 +4429,33 @@ function uniqueNormalizedPaths(values) {
4232
4429
  var PROJECT_DIRTY_STATUS_CACHE = /* @__PURE__ */ new Map();
4233
4430
  var COMPONENT_STATUS_PATH_CACHE = /* @__PURE__ */ new Map();
4234
4431
  var PR_REMOTE_STATUS_CACHE = /* @__PURE__ */ new Map();
4432
+ var FEATURE_WORKTREE_CACHE = /* @__PURE__ */ new Map();
4433
+ function resetContextParseCaches() {
4434
+ PROJECT_DIRTY_STATUS_CACHE.clear();
4435
+ COMPONENT_STATUS_PATH_CACHE.clear();
4436
+ PR_REMOTE_STATUS_CACHE.clear();
4437
+ FEATURE_WORKTREE_CACHE.clear();
4438
+ }
4439
+ function resolveFeatureWorktreePath(projectGitCwd, issueNumber, slug, folderName) {
4440
+ const expectedBranches = [
4441
+ `feat/${issueNumber}-${slug}`,
4442
+ `feat/${issueNumber}-${folderName}`
4443
+ ];
4444
+ for (const branchName of expectedBranches) {
4445
+ const cacheKey = `${projectGitCwd}::${branchName}`;
4446
+ let foundPath = FEATURE_WORKTREE_CACHE.get(cacheKey);
4447
+ if (typeof foundPath === "undefined") {
4448
+ foundPath = findWorktreePathForBranch(projectGitCwd, branchName) || null;
4449
+ FEATURE_WORKTREE_CACHE.set(cacheKey, foundPath);
4450
+ }
4451
+ if (!foundPath) continue;
4452
+ return {
4453
+ cwd: foundPath,
4454
+ branch: getCurrentBranch(foundPath) || branchName
4455
+ };
4456
+ }
4457
+ return void 0;
4458
+ }
4235
4459
  function toUpperToken(value) {
4236
4460
  if (typeof value !== "string") return void 0;
4237
4461
  const normalized = value.trim().toUpperCase();
@@ -4274,7 +4498,7 @@ function resolvePrRemoteStatus(prRef, projectGitCwd) {
4274
4498
  "view",
4275
4499
  prRef,
4276
4500
  "--json",
4277
- "reviewDecision,mergeStateStatus,isDraft,statusCheckRollup"
4501
+ "state,mergedAt,reviewDecision,mergeStateStatus,isDraft,statusCheckRollup"
4278
4502
  ],
4279
4503
  {
4280
4504
  cwd: projectGitCwd,
@@ -4289,6 +4513,9 @@ function resolvePrRemoteStatus(prRef, projectGitCwd) {
4289
4513
  return null;
4290
4514
  }
4291
4515
  const parsed = JSON.parse(raw);
4516
+ const state = toUpperToken(parsed.state);
4517
+ const mergedAt = typeof parsed.mergedAt === "string" && parsed.mergedAt.trim().length > 0 ? parsed.mergedAt.trim() : void 0;
4518
+ const isMerged = state === "MERGED" || !!mergedAt;
4292
4519
  const reviewDecision = toUpperToken(parsed.reviewDecision);
4293
4520
  const mergeStateStatus = toUpperToken(parsed.mergeStateStatus);
4294
4521
  const isDraft = parsed.isDraft === true;
@@ -4303,11 +4530,14 @@ function resolvePrRemoteStatus(prRef, projectGitCwd) {
4303
4530
  const remote = {
4304
4531
  source: "gh",
4305
4532
  available: true,
4533
+ state,
4534
+ mergedAt,
4535
+ isMerged,
4306
4536
  reviewDecision,
4307
4537
  mergeStateStatus,
4308
4538
  isDraft,
4309
4539
  hasBlockingReview: reviewDecision === "CHANGES_REQUESTED" || reviewDecision === "REVIEW_REQUIRED",
4310
- mergeBlocked: isDraft || isMergeBlockedState(mergeStateStatus),
4540
+ mergeBlocked: !isMerged && (isDraft || isMergeBlockedState(mergeStateStatus)),
4311
4541
  failingChecks,
4312
4542
  pendingChecks
4313
4543
  };
@@ -4331,10 +4561,10 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4331
4561
  const normalizedCandidates = uniqueNormalizedPaths(
4332
4562
  candidates.map((candidate) => {
4333
4563
  if (!candidate) return "";
4334
- if (!path19.isAbsolute(candidate)) return candidate;
4335
- const relative = path19.relative(projectGitCwd, candidate);
4564
+ if (!path20.isAbsolute(candidate)) return candidate;
4565
+ const relative = path20.relative(projectGitCwd, candidate);
4336
4566
  if (!relative) return "";
4337
- if (relative === ".." || relative.startsWith(`..${path19.sep}`)) return "";
4567
+ if (relative === ".." || relative.startsWith(`..${path20.sep}`)) return "";
4338
4568
  return relative;
4339
4569
  }).filter(Boolean)
4340
4570
  );
@@ -4347,7 +4577,7 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4347
4577
  if (cached) return [...cached];
4348
4578
  const existing = [];
4349
4579
  for (const candidate of normalizedCandidates) {
4350
- if (await fs15.pathExists(path19.join(projectGitCwd, candidate))) {
4580
+ if (await fs15.pathExists(path20.join(projectGitCwd, candidate))) {
4351
4581
  existing.push(candidate);
4352
4582
  }
4353
4583
  }
@@ -4436,15 +4666,15 @@ async function parseFeature(featurePath, type, context, options) {
4436
4666
  const lang = options.lang;
4437
4667
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
4438
4668
  const prePrReviewPolicy = resolvePrePrReviewPolicy(options.workflow);
4439
- const folderName = path19.basename(featurePath);
4669
+ const folderName = path20.basename(featurePath);
4440
4670
  const match = folderName.match(/^(F\d+)-(.+)$/);
4441
4671
  const id = match?.[1];
4442
4672
  const slug = match?.[2] || folderName;
4443
- const specPath = path19.join(featurePath, "spec.md");
4444
- const planPath = path19.join(featurePath, "plan.md");
4445
- const tasksPath = path19.join(featurePath, "tasks.md");
4446
- const issueDocPath = path19.join(featurePath, "issue.md");
4447
- const prDocPath = path19.join(featurePath, "pr.md");
4673
+ const specPath = path20.join(featurePath, "spec.md");
4674
+ const planPath = path20.join(featurePath, "plan.md");
4675
+ const tasksPath = path20.join(featurePath, "tasks.md");
4676
+ const issueDocPath = path20.join(featurePath, "issue.md");
4677
+ const prDocPath = path20.join(featurePath, "pr.md");
4448
4678
  let specStatus;
4449
4679
  let issueNumber;
4450
4680
  const specExists = await fs15.pathExists(specPath);
@@ -4455,6 +4685,30 @@ async function parseFeature(featurePath, type, context, options) {
4455
4685
  const issueValue = extractFirstSpecValue(content, ["\uC774\uC288 \uBC88\uD638", "Issue Number", "Issue"]);
4456
4686
  issueNumber = parseIssueNumber(issueValue);
4457
4687
  }
4688
+ let effectiveProjectGitCwd = context.projectGitCwd;
4689
+ let effectiveProjectBranch = context.projectBranch;
4690
+ let effectiveProjectBranchAvailable = context.projectBranchAvailable;
4691
+ if (effectiveProjectGitCwd && issueNumber) {
4692
+ const alreadyExpected = isExpectedFeatureBranch(
4693
+ effectiveProjectBranch,
4694
+ issueNumber,
4695
+ slug,
4696
+ folderName
4697
+ );
4698
+ if (!alreadyExpected) {
4699
+ const worktree = resolveFeatureWorktreePath(
4700
+ effectiveProjectGitCwd,
4701
+ issueNumber,
4702
+ slug,
4703
+ folderName
4704
+ );
4705
+ if (worktree) {
4706
+ effectiveProjectGitCwd = worktree.cwd;
4707
+ effectiveProjectBranch = worktree.branch;
4708
+ effectiveProjectBranchAvailable = true;
4709
+ }
4710
+ }
4711
+ }
4458
4712
  let planStatus;
4459
4713
  const planExists = await fs15.pathExists(planPath);
4460
4714
  if (planExists) {
@@ -4573,6 +4827,27 @@ async function parseFeature(featurePath, type, context, options) {
4573
4827
  prReviewEvidence = prReviewEvidenceValue?.trim();
4574
4828
  prReviewEvidenceProvided = !isPlaceholderReviewEvidence(prReviewEvidenceValue);
4575
4829
  }
4830
+ if (effectiveProjectGitCwd && issueNumber) {
4831
+ const alreadyExpected = isExpectedFeatureBranch(
4832
+ effectiveProjectBranch,
4833
+ issueNumber,
4834
+ slug,
4835
+ folderName
4836
+ );
4837
+ if (!alreadyExpected) {
4838
+ const worktree = resolveFeatureWorktreePath(
4839
+ effectiveProjectGitCwd,
4840
+ issueNumber,
4841
+ slug,
4842
+ folderName
4843
+ );
4844
+ if (worktree) {
4845
+ effectiveProjectGitCwd = worktree.cwd;
4846
+ effectiveProjectBranch = worktree.branch;
4847
+ effectiveProjectBranchAvailable = true;
4848
+ }
4849
+ }
4850
+ }
4576
4851
  const issueDocExists = await fs15.pathExists(issueDocPath);
4577
4852
  if (issueDocExists) {
4578
4853
  const content = await fs15.readFile(issueDocPath, "utf-8");
@@ -4594,20 +4869,20 @@ async function parseFeature(featurePath, type, context, options) {
4594
4869
  prDocPrFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
4595
4870
  prDocReviewStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
4596
4871
  }
4597
- if (workflowPolicy.requireReview && prStatus === "Review" && prLink && context.projectGitCwd) {
4598
- prRemote = resolvePrRemoteStatus(prLink, context.projectGitCwd) || void 0;
4872
+ if (workflowPolicy.requireReview && prStatus === "Review" && prLink && effectiveProjectGitCwd) {
4873
+ prRemote = resolvePrRemoteStatus(prLink, effectiveProjectGitCwd) || void 0;
4599
4874
  }
4600
4875
  const warnings = [];
4601
- if (context.projectBranchAvailable === false) {
4876
+ if (effectiveProjectBranchAvailable === false) {
4602
4877
  warnings.push(tr(lang, "warnings", "projectBranchUnavailable"));
4603
4878
  }
4604
4879
  const onExpectedBranch = isExpectedFeatureBranch(
4605
- context.projectBranch,
4880
+ effectiveProjectBranch,
4606
4881
  issueNumber,
4607
4882
  slug,
4608
4883
  folderName
4609
4884
  );
4610
- const relativeFeaturePathFromDocs = path19.relative(context.docsDir, featurePath);
4885
+ const relativeFeaturePathFromDocs = path20.relative(context.docsDir, featurePath);
4611
4886
  const normalizedFeaturePathFromDocs = normalizeGitPath(relativeFeaturePathFromDocs);
4612
4887
  const docsPathIgnored = typeof context.docsPathIgnored === "boolean" ? context.docsPathIgnored : isGitPathIgnored(context.docsGitCwd, normalizedFeaturePathFromDocs);
4613
4888
  let docsHasUncommittedChanges = typeof context.docsHasUncommittedChanges === "boolean" ? context.docsHasUncommittedChanges : false;
@@ -4631,10 +4906,10 @@ async function parseFeature(featurePath, type, context, options) {
4631
4906
  }
4632
4907
  let projectHasUncommittedChanges = typeof context.projectHasUncommittedChanges === "boolean" ? context.projectHasUncommittedChanges : false;
4633
4908
  let projectStatusUnavailable = !!context.projectStatusUnavailable;
4634
- if (typeof context.projectHasUncommittedChanges !== "boolean" && context.projectGitCwd) {
4909
+ if (typeof context.projectHasUncommittedChanges !== "boolean" && effectiveProjectGitCwd) {
4635
4910
  const dirtyScopePolicy = resolveCodeDirtyScopePolicy(options.workflow, options.projectType);
4636
4911
  const projectCacheKey = JSON.stringify({
4637
- projectGitCwd: context.projectGitCwd,
4912
+ projectGitCwd: effectiveProjectGitCwd,
4638
4913
  docsDir: context.docsDir,
4639
4914
  type,
4640
4915
  dirtyScopePolicy,
@@ -4648,19 +4923,19 @@ async function parseFeature(featurePath, type, context, options) {
4648
4923
  let projectStatusPaths = [];
4649
4924
  if (dirtyScopePolicy === "component" && type !== "single") {
4650
4925
  const componentStatusPaths = await resolveComponentStatusPaths(
4651
- context.projectGitCwd,
4926
+ effectiveProjectGitCwd,
4652
4927
  type,
4653
4928
  options.workflow
4654
4929
  );
4655
- projectStatusPaths = componentStatusPaths.length > 0 ? componentStatusPaths : resolveProjectStatusPaths(context.projectGitCwd, context.docsDir);
4930
+ projectStatusPaths = componentStatusPaths.length > 0 ? componentStatusPaths : resolveProjectStatusPaths(effectiveProjectGitCwd, context.docsDir);
4656
4931
  } else {
4657
4932
  projectStatusPaths = resolveProjectStatusPaths(
4658
- context.projectGitCwd,
4933
+ effectiveProjectGitCwd,
4659
4934
  context.docsDir
4660
4935
  );
4661
4936
  }
4662
4937
  const projectStatus = getGitStatusPorcelain(
4663
- context.projectGitCwd,
4938
+ effectiveProjectGitCwd,
4664
4939
  projectStatusPaths
4665
4940
  );
4666
4941
  projectStatusUnavailable = projectStatus === void 0;
@@ -4829,10 +5104,10 @@ async function parseFeature(featurePath, type, context, options) {
4829
5104
  pr: { link: prLink, status: prStatus, remote: prRemote },
4830
5105
  git: {
4831
5106
  docsBranch: context.docsBranch,
4832
- projectBranch: context.projectBranch,
4833
- projectBranchAvailable: context.projectBranchAvailable,
5107
+ projectBranch: effectiveProjectBranch,
5108
+ projectBranchAvailable: effectiveProjectBranchAvailable,
4834
5109
  docsGitCwd: context.docsGitCwd,
4835
- projectGitCwd: context.projectGitCwd,
5110
+ projectGitCwd: effectiveProjectGitCwd,
4836
5111
  onExpectedBranch,
4837
5112
  docsEverCommitted,
4838
5113
  docsHasUncommittedChanges,
@@ -4962,6 +5237,8 @@ function buildDocsFeatureGitMeta(docsGitCwd, relativeFeaturePaths) {
4962
5237
  return map;
4963
5238
  }
4964
5239
  async function scanFeatures(config) {
5240
+ resetContextGitCaches();
5241
+ resetContextParseCaches();
4965
5242
  const features = [];
4966
5243
  const warnings = [];
4967
5244
  const stepDefinitions = getStepDefinitions(config.lang, config.workflow);
@@ -5005,7 +5282,7 @@ async function scanFeatures(config) {
5005
5282
  }
5006
5283
  }
5007
5284
  const relativeFeaturePaths = allFeatureDirs.map(
5008
- (dir) => normalizeRelPath(path19.relative(config.docsDir, dir))
5285
+ (dir) => normalizeRelPath(path20.relative(config.docsDir, dir))
5009
5286
  );
5010
5287
  const docsGitMeta = buildDocsFeatureGitMeta(config.docsDir, relativeFeaturePaths);
5011
5288
  const parseTargets = config.projectType === "single" ? [{ type: "single", dirs: componentFeatureDirs.get("single") || [] }] : resolveProjectComponents(config.projectType, config.components).map((component) => ({
@@ -5016,7 +5293,7 @@ async function scanFeatures(config) {
5016
5293
  const parsed = await Promise.all(
5017
5294
  target.dirs.map(async (dir) => {
5018
5295
  const relativeFeaturePathFromDocs = normalizeRelPath(
5019
- path19.relative(config.docsDir, dir)
5296
+ path20.relative(config.docsDir, dir)
5020
5297
  );
5021
5298
  const docsMeta = docsGitMeta.get(relativeFeaturePathFromDocs);
5022
5299
  return parseFeature(
@@ -5085,13 +5362,13 @@ async function runStatus(options) {
5085
5362
  );
5086
5363
  }
5087
5364
  const { docsDir, projectType, projectName, lang } = config;
5088
- const featuresDir = path19.join(docsDir, "features");
5365
+ const featuresDir = path20.join(docsDir, "features");
5089
5366
  const scan = await scanFeatures(config);
5090
5367
  const features = [];
5091
5368
  const idMap = /* @__PURE__ */ new Map();
5092
5369
  for (const f of scan.features) {
5093
5370
  const id = f.id || "UNKNOWN";
5094
- const relPath = path19.relative(docsDir, f.path);
5371
+ const relPath = path20.relative(docsDir, f.path);
5095
5372
  if (!idMap.has(id)) idMap.set(id, []);
5096
5373
  idMap.get(id).push(relPath);
5097
5374
  if (!f.docs.specExists || !f.docs.tasksExists) continue;
@@ -5172,7 +5449,7 @@ async function runStatus(options) {
5172
5449
  }
5173
5450
  console.log();
5174
5451
  if (options.write) {
5175
- const outputPath = path19.join(featuresDir, "status.md");
5452
+ const outputPath = path20.join(featuresDir, "status.md");
5176
5453
  const date = getLocalDateString();
5177
5454
  const content = [
5178
5455
  "# Feature Status",
@@ -5200,7 +5477,7 @@ function escapeRegExp2(value) {
5200
5477
  }
5201
5478
  async function getFeatureNameFromSpec(featureDir, fallbackSlug, fallbackFolderName) {
5202
5479
  try {
5203
- const specPath = path19.join(featureDir, "spec.md");
5480
+ const specPath = path20.join(featureDir, "spec.md");
5204
5481
  if (!await fs15.pathExists(specPath)) return fallbackSlug;
5205
5482
  const content = await fs15.readFile(specPath, "utf-8");
5206
5483
  const keys = ["\uAE30\uB2A5\uBA85", "Feature Name"];
@@ -5282,10 +5559,10 @@ async function runUpdate(options) {
5282
5559
  console.log(chalk6.blue(tr(lang, "cli", "update.updatingAgents")));
5283
5560
  }
5284
5561
  if (agentsMode === "all") {
5285
- const commonAgentsBase = path19.join(templatesDir, lang, "common", "agents");
5286
- const targetAgentsBase = path19.join(docsDir, "agents");
5287
- const commonAgents = agentsMode === "skills" ? path19.join(commonAgentsBase, "skills") : commonAgentsBase;
5288
- const targetAgents = agentsMode === "skills" ? path19.join(targetAgentsBase, "skills") : targetAgentsBase;
5562
+ const commonAgentsBase = path20.join(templatesDir, lang, "common", "agents");
5563
+ const targetAgentsBase = path20.join(docsDir, "agents");
5564
+ const commonAgents = commonAgentsBase;
5565
+ const targetAgents = targetAgentsBase;
5289
5566
  const featurePath = projectType === "multi" ? "docs/features/{component}" : "docs/features";
5290
5567
  const projectName = config.projectName ?? "{{projectName}}";
5291
5568
  const commonReplacements = {
@@ -5312,7 +5589,7 @@ async function runUpdate(options) {
5312
5589
  }
5313
5590
  console.log(
5314
5591
  chalk6.green(
5315
- ` \u2705 ${agentsMode === "skills" ? tr(lang, "cli", "update.skillsUpdated") : tr(lang, "cli", "update.agentsUpdated")}`
5592
+ ` \u2705 ${tr(lang, "cli", "update.agentsUpdated")}`
5316
5593
  )
5317
5594
  );
5318
5595
  }
@@ -5365,7 +5642,7 @@ function normalizeSkillList2(raw) {
5365
5642
  return [...deduped];
5366
5643
  }
5367
5644
  async function backfillMissingConfigDefaults(docsDir) {
5368
- const configPath = path19.join(docsDir, ".lee-spec-kit.json");
5645
+ const configPath = path20.join(docsDir, ".lee-spec-kit.json");
5369
5646
  if (!await fs15.pathExists(configPath)) {
5370
5647
  return { changed: false, changedPaths: [] };
5371
5648
  }
@@ -5386,7 +5663,7 @@ async function backfillMissingConfigDefaults(docsDir) {
5386
5663
  const workflow = raw.workflow;
5387
5664
  setIfMissing(workflow, "mode", "github", "workflow.mode");
5388
5665
  setIfMissing(workflow, "codeDirtyScope", "auto", "workflow.codeDirtyScope");
5389
- setIfMissing(workflow, "taskCommitGate", "strict", "workflow.taskCommitGate");
5666
+ setIfMissing(workflow, "taskCommitGate", "warn", "workflow.taskCommitGate");
5390
5667
  if (!isPlainObject(workflow.prePrReview)) {
5391
5668
  workflow.prePrReview = {};
5392
5669
  changedPaths.push("workflow.prePrReview");
@@ -5438,8 +5715,8 @@ async function updateFolder(sourceDir, targetDir, force, replacements, lang = DE
5438
5715
  const files = await fs15.readdir(sourceDir);
5439
5716
  let updatedCount = 0;
5440
5717
  for (const file of files) {
5441
- const sourcePath = path19.join(sourceDir, file);
5442
- const targetPath = path19.join(targetDir, file);
5718
+ const sourcePath = path20.join(sourceDir, file);
5719
+ const targetPath = path20.join(targetDir, file);
5443
5720
  const stat = await fs15.stat(sourcePath);
5444
5721
  if (stat.isFile()) {
5445
5722
  if (protectedFiles.has(file)) {
@@ -5522,7 +5799,7 @@ function extractPorcelainPaths(line) {
5522
5799
  function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
5523
5800
  const top = getGitTopLevel2(docsDir);
5524
5801
  if (!top) return null;
5525
- const rel = path19.relative(top, docsDir) || ".";
5802
+ const rel = path20.relative(top, docsDir) || ".";
5526
5803
  try {
5527
5804
  const output = execFileSync("git", ["status", "--porcelain=v1", "--", rel], {
5528
5805
  cwd: top,
@@ -5534,7 +5811,7 @@ function getDocsPorcelainStatus(docsDir, ignoredAbsPaths = []) {
5534
5811
  }
5535
5812
  const ignoredRelPaths = new Set(
5536
5813
  ignoredAbsPaths.map(
5537
- (absPath) => normalizeGitPath2(path19.relative(top, absPath) || ".")
5814
+ (absPath) => normalizeGitPath2(path20.relative(top, absPath) || ".")
5538
5815
  )
5539
5816
  );
5540
5817
  const filtered = output.split("\n").filter((line) => {
@@ -5591,7 +5868,7 @@ ${tr(lang2, "cli", "common.canceled")}`));
5591
5868
  }
5592
5869
  async function runConfig(options) {
5593
5870
  const cwd = process.cwd();
5594
- const targetCwd = options.dir ? path19.resolve(cwd, options.dir) : cwd;
5871
+ const targetCwd = options.dir ? path20.resolve(cwd, options.dir) : cwd;
5595
5872
  const config = await getConfig(targetCwd);
5596
5873
  if (!config) {
5597
5874
  throw createCliError(
@@ -5599,7 +5876,7 @@ async function runConfig(options) {
5599
5876
  tr(DEFAULT_LANG, "cli", "common.configNotFound")
5600
5877
  );
5601
5878
  }
5602
- const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
5879
+ const configPath = path20.join(config.docsDir, ".lee-spec-kit.json");
5603
5880
  if (!options.projectRoot) {
5604
5881
  console.log();
5605
5882
  console.log(chalk6.blue(tr(config.lang, "cli", "config.currentTitle")));
@@ -5615,6 +5892,7 @@ async function runConfig(options) {
5615
5892
  console.log();
5616
5893
  return;
5617
5894
  }
5895
+ const projectRoot = options.projectRoot;
5618
5896
  await withFileLock(
5619
5897
  getDocsLockPath(config.docsDir),
5620
5898
  async () => {
@@ -5668,13 +5946,13 @@ async function runConfig(options) {
5668
5946
  }
5669
5947
  assertAllowedComponent(targetComponent, components);
5670
5948
  const currentRoot = typeof configFile.projectRoot === "object" && configFile.projectRoot ? configFile.projectRoot : {};
5671
- currentRoot[targetComponent] = options.projectRoot;
5949
+ currentRoot[targetComponent] = projectRoot;
5672
5950
  configFile.projectRoot = currentRoot;
5673
5951
  console.log(
5674
5952
  chalk6.green(
5675
5953
  tr(config.lang, "cli", "config.projectRootSet", {
5676
5954
  repo: targetComponent.toUpperCase(),
5677
- path: options.projectRoot
5955
+ path: projectRoot
5678
5956
  })
5679
5957
  )
5680
5958
  );
@@ -5685,11 +5963,11 @@ async function runConfig(options) {
5685
5963
  "`--component` is only valid for multi projectRoot updates."
5686
5964
  );
5687
5965
  }
5688
- configFile.projectRoot = options.projectRoot;
5966
+ configFile.projectRoot = projectRoot;
5689
5967
  console.log(
5690
5968
  chalk6.green(
5691
5969
  tr(config.lang, "cli", "config.projectRootSetSingle", {
5692
- path: options.projectRoot
5970
+ path: projectRoot
5693
5971
  })
5694
5972
  )
5695
5973
  );
@@ -5758,6 +6036,7 @@ function getActionSummary(action) {
5758
6036
  if (action.category === "pre_pr_review") return "Run pre-PR self review";
5759
6037
  if (action.category === "pr_status_update") return "Update PR status";
5760
6038
  if (action.category === "code_review") return "Process code review feedback";
6039
+ if (action.category === "user_request_replan") return "Handle a new user request first";
5761
6040
  if (action.category === "task_execute") return "Proceed with task execution";
5762
6041
  if (action.category === "review_fix_commit") return "Commit review feedback fixes";
5763
6042
  if (action.category === "feature_done") return "Feature is complete";
@@ -5772,6 +6051,19 @@ function getActionSummary(action) {
5772
6051
  return action.message;
5773
6052
  }
5774
6053
  function formatActionSummary(action) {
6054
+ const formatBranchCreateDetail = (command) => {
6055
+ const worktreeMatch = command.match(/\.worktrees\/([A-Za-z0-9._-]+)/);
6056
+ const branchMatch = command.match(/\bfeat\/([A-Za-z0-9._-]+)/);
6057
+ const worktree = worktreeMatch ? `.worktrees/${worktreeMatch[1]}` : null;
6058
+ const branch = branchMatch ? `feat/${branchMatch[1]}` : null;
6059
+ if (worktree && branch) {
6060
+ return `(${action.scope}) create or reuse worktree ${worktree} for branch ${branch}`;
6061
+ }
6062
+ if (branch) {
6063
+ return `(${action.scope}) create or reuse worktree for branch ${branch}`;
6064
+ }
6065
+ return `(${action.scope}) create or reuse feature branch worktree`;
6066
+ };
5775
6067
  const extractCommitMessage = (command) => {
5776
6068
  const doubleQuoted = command.match(/git\s+commit\s+-m\s+"((?:\\"|[^"])*)"/);
5777
6069
  if (doubleQuoted) {
@@ -5784,6 +6076,9 @@ function formatActionSummary(action) {
5784
6076
  return null;
5785
6077
  };
5786
6078
  if (action.type === "command") {
6079
+ if (action.category === "branch_create") {
6080
+ return formatBranchCreateDetail(action.cmd);
6081
+ }
5787
6082
  const commitMessage = extractCommitMessage(action.cmd);
5788
6083
  if (commitMessage) {
5789
6084
  return `(${action.scope}) commit: ${commitMessage}`;
@@ -5965,42 +6260,42 @@ var BUILTIN_DOC_DEFINITIONS = [
5965
6260
  {
5966
6261
  id: "agents",
5967
6262
  title: { ko: "\uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uADDC\uCE59", en: "Agent Operating Rules" },
5968
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "agents.md")
6263
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "agents.md")
5969
6264
  },
5970
6265
  {
5971
6266
  id: "git-workflow",
5972
6267
  title: { ko: "Git \uC6CC\uD06C\uD50C\uB85C\uC6B0", en: "Git Workflow" },
5973
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "git-workflow.md")
6268
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "git-workflow.md")
5974
6269
  },
5975
6270
  {
5976
6271
  id: "issue-doc",
5977
6272
  title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
5978
- relativePath: (_, lang) => path19.join(lang, "common", "features", "feature-base", "issue.md")
6273
+ relativePath: (_, lang) => path20.join(lang, "common", "features", "feature-base", "issue.md")
5979
6274
  },
5980
6275
  {
5981
6276
  id: "pr-doc",
5982
6277
  title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
5983
- relativePath: (_, lang) => path19.join(lang, "common", "features", "feature-base", "pr.md")
6278
+ relativePath: (_, lang) => path20.join(lang, "common", "features", "feature-base", "pr.md")
5984
6279
  },
5985
6280
  {
5986
6281
  id: "create-feature",
5987
6282
  title: { ko: "create-feature \uC2A4\uD0AC", en: "create-feature skill" },
5988
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-feature.md")
6283
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "skills", "create-feature.md")
5989
6284
  },
5990
6285
  {
5991
6286
  id: "execute-task",
5992
6287
  title: { ko: "execute-task \uC2A4\uD0AC", en: "execute-task skill" },
5993
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "execute-task.md")
6288
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "skills", "execute-task.md")
5994
6289
  },
5995
6290
  {
5996
6291
  id: "create-issue",
5997
6292
  title: { ko: "create-issue \uC2A4\uD0AC", en: "create-issue skill" },
5998
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-issue.md")
6293
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "skills", "create-issue.md")
5999
6294
  },
6000
6295
  {
6001
6296
  id: "create-pr",
6002
6297
  title: { ko: "create-pr \uC2A4\uD0AC", en: "create-pr skill" },
6003
- relativePath: (_, lang) => path19.join(lang, "common", "agents", "skills", "create-pr.md")
6298
+ relativePath: (_, lang) => path20.join(lang, "common", "agents", "skills", "create-pr.md")
6004
6299
  }
6005
6300
  ];
6006
6301
  var DOC_FOLLOWUPS = {
@@ -6036,7 +6331,8 @@ var CATEGORY_DOC_MAP = {
6036
6331
  pre_pr_review: ["create-pr"],
6037
6332
  pr_create: ["create-pr", "pr-doc", "git-workflow"],
6038
6333
  pr_status_update: ["create-pr"],
6039
- code_review: ["create-pr"]
6334
+ code_review: ["create-pr"],
6335
+ user_request_replan: ["agents", "execute-task"]
6040
6336
  };
6041
6337
  function getBuiltinDocIds() {
6042
6338
  return BUILTIN_DOC_DEFINITIONS.map((doc) => doc.id);
@@ -6087,7 +6383,7 @@ function listBuiltinDocs(projectType, lang) {
6087
6383
  id: doc.id,
6088
6384
  title: doc.title[lang],
6089
6385
  relativePath,
6090
- absolutePath: path19.join(templatesDir, relativePath)
6386
+ absolutePath: path20.join(templatesDir, relativePath)
6091
6387
  };
6092
6388
  });
6093
6389
  }
@@ -6136,7 +6432,7 @@ function parseApprovalLabel(input, validLabels) {
6136
6432
  function getApprovalTicketPaths(config) {
6137
6433
  return {
6138
6434
  runtimePath: getApprovalTicketStorePath(config.docsDir),
6139
- legacyPath: path19.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
6435
+ legacyPath: path20.join(config.docsDir, LEGACY_APPROVAL_TICKET_FILENAME)
6140
6436
  };
6141
6437
  }
6142
6438
  function getApprovalSessionId() {
@@ -6164,7 +6460,7 @@ async function loadApprovalTicketStore(storePath) {
6164
6460
  }
6165
6461
  }
6166
6462
  async function saveApprovalTicketStore(storePath, payload) {
6167
- await fs15.ensureDir(path19.dirname(storePath));
6463
+ await fs15.ensureDir(path20.dirname(storePath));
6168
6464
  await fs15.writeJson(storePath, payload, { spaces: 2 });
6169
6465
  }
6170
6466
  async function resolveApprovalTicketStoreAndPath(config, nowMs) {
@@ -7130,7 +7426,7 @@ async function runContext(featureName, options) {
7130
7426
  if (f.issueNumber) {
7131
7427
  console.log(` \u2022 Issue: #${f.issueNumber}`);
7132
7428
  }
7133
- console.log(` \u2022 Path: ${path19.relative(cwd, f.path)}`);
7429
+ console.log(` \u2022 Path: ${path20.relative(cwd, f.path)}`);
7134
7430
  if (f.git.projectBranch) {
7135
7431
  console.log(` \u2022 Project Branch: ${f.git.projectBranch}`);
7136
7432
  }
@@ -7460,7 +7756,7 @@ var FIXABLE_ISSUE_CODES = /* @__PURE__ */ new Set([
7460
7756
  ]);
7461
7757
  function formatPath(cwd, p) {
7462
7758
  if (!p) return "";
7463
- return path19.isAbsolute(p) ? path19.relative(cwd, p) : p;
7759
+ return path20.isAbsolute(p) ? path20.relative(cwd, p) : p;
7464
7760
  }
7465
7761
  function detectPlaceholders(content) {
7466
7762
  const patterns = [
@@ -7609,7 +7905,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
7609
7905
  const placeholderContext = {
7610
7906
  projectName: config.projectName,
7611
7907
  featureName: f.slug,
7612
- featurePath: f.docs.featurePathFromDocs || path19.relative(config.docsDir, f.path),
7908
+ featurePath: f.docs.featurePathFromDocs || path20.relative(config.docsDir, f.path),
7613
7909
  repoType: f.type,
7614
7910
  featureNumber
7615
7911
  };
@@ -7619,7 +7915,7 @@ async function applyDoctorFixes(config, cwd, features, dryRun) {
7619
7915
  "tasks.md"
7620
7916
  ];
7621
7917
  for (const file of files) {
7622
- const fullPath = path19.join(f.path, file);
7918
+ const fullPath = path20.join(f.path, file);
7623
7919
  if (!await fs15.pathExists(fullPath)) continue;
7624
7920
  const original = await fs15.readFile(fullPath, "utf-8");
7625
7921
  let next = original;
@@ -7664,7 +7960,7 @@ async function checkDocsStructure(config, cwd) {
7664
7960
  const issues = [];
7665
7961
  const requiredDirs = ["agents", "features", "prd", "designs", "ideas"];
7666
7962
  for (const dir of requiredDirs) {
7667
- const p = path19.join(config.docsDir, dir);
7963
+ const p = path20.join(config.docsDir, dir);
7668
7964
  if (!await fs15.pathExists(p)) {
7669
7965
  issues.push({
7670
7966
  level: "error",
@@ -7674,7 +7970,7 @@ async function checkDocsStructure(config, cwd) {
7674
7970
  });
7675
7971
  }
7676
7972
  }
7677
- const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
7973
+ const configPath = path20.join(config.docsDir, ".lee-spec-kit.json");
7678
7974
  if (!await fs15.pathExists(configPath)) {
7679
7975
  issues.push({
7680
7976
  level: "warn",
@@ -7697,7 +7993,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7697
7993
  }
7698
7994
  const idMap = /* @__PURE__ */ new Map();
7699
7995
  for (const f of features) {
7700
- const rel = f.docs.featurePathFromDocs || path19.relative(config.docsDir, f.path);
7996
+ const rel = f.docs.featurePathFromDocs || path20.relative(config.docsDir, f.path);
7701
7997
  const id = f.id || "UNKNOWN";
7702
7998
  if (!idMap.has(id)) idMap.set(id, []);
7703
7999
  idMap.get(id).push(rel);
@@ -7705,7 +8001,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7705
8001
  if (!isInitialTemplateState) {
7706
8002
  const featureDocs = ["spec.md", "plan.md", "tasks.md"];
7707
8003
  for (const file of featureDocs) {
7708
- const p = path19.join(f.path, file);
8004
+ const p = path20.join(f.path, file);
7709
8005
  if (!await fs15.pathExists(p)) continue;
7710
8006
  const content = await fs15.readFile(p, "utf-8");
7711
8007
  const placeholders = detectPlaceholders(content);
@@ -7720,7 +8016,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7720
8016
  });
7721
8017
  }
7722
8018
  if (decisionsPlaceholderMode !== "off") {
7723
- const decisionsPath = path19.join(f.path, "decisions.md");
8019
+ const decisionsPath = path20.join(f.path, "decisions.md");
7724
8020
  if (await fs15.pathExists(decisionsPath)) {
7725
8021
  const content = await fs15.readFile(decisionsPath, "utf-8");
7726
8022
  const placeholders = detectPlaceholders(content);
@@ -7749,7 +8045,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7749
8045
  level: "warn",
7750
8046
  code: "spec_status_unset",
7751
8047
  message: tr(config.lang, "cli", "doctor.issue.specStatusUnset"),
7752
- path: formatPath(cwd, path19.join(f.path, "spec.md"))
8048
+ path: formatPath(cwd, path20.join(f.path, "spec.md"))
7753
8049
  });
7754
8050
  }
7755
8051
  if (f.docs.planExists && !f.planStatus && !isInitialTemplateState) {
@@ -7757,7 +8053,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7757
8053
  level: "warn",
7758
8054
  code: "plan_status_unset",
7759
8055
  message: tr(config.lang, "cli", "doctor.issue.planStatusUnset"),
7760
- path: formatPath(cwd, path19.join(f.path, "plan.md"))
8056
+ path: formatPath(cwd, path20.join(f.path, "plan.md"))
7761
8057
  });
7762
8058
  }
7763
8059
  if (f.docs.tasksExists && f.tasks.total === 0 && !isInitialTemplateState) {
@@ -7765,7 +8061,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7765
8061
  level: "warn",
7766
8062
  code: "tasks_empty",
7767
8063
  message: tr(config.lang, "cli", "doctor.issue.tasksEmpty"),
7768
- path: formatPath(cwd, path19.join(f.path, "tasks.md"))
8064
+ path: formatPath(cwd, path20.join(f.path, "tasks.md"))
7769
8065
  });
7770
8066
  }
7771
8067
  if (f.docs.tasksExists && !f.docs.tasksDocStatusFieldExists && !isInitialTemplateState) {
@@ -7773,7 +8069,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7773
8069
  level: "warn",
7774
8070
  code: "tasks_doc_status_missing",
7775
8071
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusMissing"),
7776
- path: formatPath(cwd, path19.join(f.path, "tasks.md"))
8072
+ path: formatPath(cwd, path20.join(f.path, "tasks.md"))
7777
8073
  });
7778
8074
  }
7779
8075
  if (f.docs.tasksExists && f.docs.tasksDocStatusFieldExists && !f.tasksDocStatus && !isInitialTemplateState) {
@@ -7781,7 +8077,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7781
8077
  level: "warn",
7782
8078
  code: "tasks_doc_status_unset",
7783
8079
  message: tr(config.lang, "cli", "doctor.issue.tasksDocStatusUnset"),
7784
- path: formatPath(cwd, path19.join(f.path, "tasks.md"))
8080
+ path: formatPath(cwd, path20.join(f.path, "tasks.md"))
7785
8081
  });
7786
8082
  }
7787
8083
  }
@@ -7805,7 +8101,7 @@ async function checkFeatures(config, cwd, features, decisionsPlaceholderMode) {
7805
8101
  level: "warn",
7806
8102
  code: "missing_feature_id",
7807
8103
  message: tr(config.lang, "cli", "doctor.issue.missingFeatureId"),
7808
- path: formatPath(cwd, path19.join(config.docsDir, p))
8104
+ path: formatPath(cwd, path20.join(config.docsDir, p))
7809
8105
  });
7810
8106
  }
7811
8107
  return issues;
@@ -7927,7 +8223,7 @@ function doctorCommand(program2) {
7927
8223
  }
7928
8224
  console.log();
7929
8225
  console.log(chalk6.bold(tr(lang, "cli", "doctor.title")));
7930
- console.log(chalk6.gray(`- Docs: ${path19.relative(cwd, docsDir)}`));
8226
+ console.log(chalk6.gray(`- Docs: ${path20.relative(cwd, docsDir)}`));
7931
8227
  console.log(chalk6.gray(`- Type: ${projectType}`));
7932
8228
  console.log(chalk6.gray(`- Lang: ${lang}`));
7933
8229
  console.log();
@@ -8100,7 +8396,7 @@ async function runView(featureName, options) {
8100
8396
  }
8101
8397
  console.log();
8102
8398
  console.log(chalk6.bold("\u{1F4CA} Workflow View"));
8103
- console.log(chalk6.gray(`- Docs: ${path19.relative(cwd, config.docsDir)}`));
8399
+ console.log(chalk6.gray(`- Docs: ${path20.relative(cwd, config.docsDir)}`));
8104
8400
  console.log(
8105
8401
  chalk6.gray(
8106
8402
  `- Features: ${state.features.length} (open ${state.openFeatures.length} / done ${state.doneFeatures.length})`
@@ -8473,25 +8769,25 @@ function tg(lang, key, vars = {}) {
8473
8769
  }
8474
8770
  function detectGithubCliLangSync(cwd) {
8475
8771
  const explicitDocsDir = (process.env.LEE_SPEC_KIT_DOCS_DIR || "").trim();
8476
- const startDirs = [explicitDocsDir ? path19.resolve(explicitDocsDir) : "", path19.resolve(cwd)].filter(Boolean);
8772
+ const startDirs = [explicitDocsDir ? path20.resolve(explicitDocsDir) : "", path20.resolve(cwd)].filter(Boolean);
8477
8773
  const scanOrder = [];
8478
8774
  const seen = /* @__PURE__ */ new Set();
8479
8775
  for (const start of startDirs) {
8480
8776
  let current = start;
8481
8777
  while (true) {
8482
- const abs = path19.resolve(current);
8778
+ const abs = path20.resolve(current);
8483
8779
  if (!seen.has(abs)) {
8484
8780
  scanOrder.push(abs);
8485
8781
  seen.add(abs);
8486
8782
  }
8487
- const parent = path19.dirname(abs);
8783
+ const parent = path20.dirname(abs);
8488
8784
  if (parent === abs) break;
8489
8785
  current = parent;
8490
8786
  }
8491
8787
  }
8492
8788
  for (const base of scanOrder) {
8493
- for (const docsDir of [path19.join(base, "docs"), base]) {
8494
- const configPath = path19.join(docsDir, ".lee-spec-kit.json");
8789
+ for (const docsDir of [path20.join(base, "docs"), base]) {
8790
+ const configPath = path20.join(docsDir, ".lee-spec-kit.json");
8495
8791
  if (fs15.existsSync(configPath)) {
8496
8792
  try {
8497
8793
  const parsed = fs15.readJsonSync(configPath);
@@ -8499,11 +8795,11 @@ function detectGithubCliLangSync(cwd) {
8499
8795
  } catch {
8500
8796
  }
8501
8797
  }
8502
- const agentsPath = path19.join(docsDir, "agents");
8503
- const featuresPath = path19.join(docsDir, "features");
8798
+ const agentsPath = path20.join(docsDir, "agents");
8799
+ const featuresPath = path20.join(docsDir, "features");
8504
8800
  if (!fs15.existsSync(agentsPath) || !fs15.existsSync(featuresPath)) continue;
8505
8801
  for (const probe of ["custom.md", "constitution.md", "agents.md"]) {
8506
- const file = path19.join(agentsPath, probe);
8802
+ const file = path20.join(agentsPath, probe);
8507
8803
  if (!fs15.existsSync(file)) continue;
8508
8804
  try {
8509
8805
  const content = fs15.readFileSync(file, "utf-8");
@@ -8601,7 +8897,7 @@ function ensureSections(body, sections, kind, lang) {
8601
8897
  }
8602
8898
  function ensureDocsExist(docsDir, relativePaths, lang) {
8603
8899
  const missing = relativePaths.filter(
8604
- (relativePath) => !fs15.existsSync(path19.join(docsDir, relativePath))
8900
+ (relativePath) => !fs15.existsSync(path20.join(docsDir, relativePath))
8605
8901
  );
8606
8902
  if (missing.length > 0) {
8607
8903
  throw createCliError(
@@ -8611,13 +8907,13 @@ function ensureDocsExist(docsDir, relativePaths, lang) {
8611
8907
  }
8612
8908
  }
8613
8909
  function buildDefaultBodyFileName(kind, docsDir, component) {
8614
- const key = `${path19.resolve(docsDir)}::${component.trim().toLowerCase()}`;
8910
+ const key = `${path20.resolve(docsDir)}::${component.trim().toLowerCase()}`;
8615
8911
  const digest = createHash("sha1").update(key).digest("hex").slice(0, 12);
8616
8912
  return `lee-spec-kit.${digest}.${kind}.md`;
8617
8913
  }
8618
8914
  function toBodyFilePath(raw, kind, docsDir, component) {
8619
- const selected = raw?.trim() || path19.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
8620
- return path19.resolve(selected);
8915
+ const selected = raw?.trim() || path20.join(os.tmpdir(), buildDefaultBodyFileName(kind, docsDir, component));
8916
+ return path20.resolve(selected);
8621
8917
  }
8622
8918
  function toProjectRootDocsPath(relativePathFromDocs) {
8623
8919
  const normalized = relativePathFromDocs.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
@@ -8710,6 +9006,10 @@ function resolveGithubDocsCwd(config, feature) {
8710
9006
  if (docsGitCwd) return docsGitCwd;
8711
9007
  return config.docsDir;
8712
9008
  }
9009
+ function shouldPushDocsSync(config) {
9010
+ if (config.docsRepo !== "standalone") return true;
9011
+ return config.pushDocs === true;
9012
+ }
8713
9013
  function getFeatureDocPaths(feature) {
8714
9014
  const featurePathFromDocs = feature.docs.featurePathFromDocs;
8715
9015
  return {
@@ -9432,8 +9732,8 @@ function ensureCleanWorktree(cwd, lang) {
9432
9732
  );
9433
9733
  }
9434
9734
  }
9435
- function commitAndPushPath(cwd, absPath, message, lang) {
9436
- const relativePath = path19.relative(cwd, absPath) || absPath;
9735
+ function commitAndPushPath(cwd, absPath, message, lang, options) {
9736
+ const relativePath = path20.relative(cwd, absPath) || absPath;
9437
9737
  const status = runProcessOrThrow(
9438
9738
  "git",
9439
9739
  ["status", "--porcelain=v1", "--", relativePath],
@@ -9443,6 +9743,7 @@ function commitAndPushPath(cwd, absPath, message, lang) {
9443
9743
  if (status.stdout.trim().length === 0) return;
9444
9744
  runProcessOrThrow("git", ["add", "--", relativePath], cwd, tg(lang, "stageFileFailed"));
9445
9745
  runProcessOrThrow("git", ["commit", "-m", message], cwd, tg(lang, "commitSyncFailed"));
9746
+ if (options?.pushToOrigin === false) return;
9446
9747
  const branch = gitCurrentBranch(cwd, lang);
9447
9748
  runProcessOrThrow(
9448
9749
  "git",
@@ -9565,9 +9866,9 @@ function githubCommand(program2) {
9565
9866
  [paths.specPath, paths.planPath, paths.tasksPath],
9566
9867
  config.lang
9567
9868
  );
9568
- const specContent = await fs15.readFile(path19.join(config.docsDir, paths.specPath), "utf-8");
9569
- const planContent = await fs15.readFile(path19.join(config.docsDir, paths.planPath), "utf-8");
9570
- const tasksContent = await fs15.readFile(path19.join(config.docsDir, paths.tasksPath), "utf-8");
9869
+ const specContent = await fs15.readFile(path20.join(config.docsDir, paths.specPath), "utf-8");
9870
+ const planContent = await fs15.readFile(path20.join(config.docsDir, paths.planPath), "utf-8");
9871
+ const tasksContent = await fs15.readFile(path20.join(config.docsDir, paths.tasksPath), "utf-8");
9571
9872
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
9572
9873
  const title = options.title?.trim() || tg(config.lang, "issueDefaultTitle", {
9573
9874
  slug: feature.slug,
@@ -9605,7 +9906,7 @@ function githubCommand(program2) {
9605
9906
  config.lang
9606
9907
  );
9607
9908
  } else {
9608
- await fs15.ensureDir(path19.dirname(bodyFile));
9909
+ await fs15.ensureDir(path20.dirname(bodyFile));
9609
9910
  await fs15.writeFile(bodyFile, generatedBody, "utf-8");
9610
9911
  }
9611
9912
  let issueUrl;
@@ -9704,10 +10005,10 @@ function githubCommand(program2) {
9704
10005
  const labels = parseLabels(options.labels, config.lang);
9705
10006
  const paths = getFeatureDocPaths(feature);
9706
10007
  ensureDocsExist(config.docsDir, [paths.specPath, paths.tasksPath], config.lang);
9707
- const specContent = await fs15.readFile(path19.join(config.docsDir, paths.specPath), "utf-8");
9708
- const planPath = path19.join(config.docsDir, paths.planPath);
10008
+ const specContent = await fs15.readFile(path20.join(config.docsDir, paths.specPath), "utf-8");
10009
+ const planPath = path20.join(config.docsDir, paths.planPath);
9709
10010
  const planContent = await fs15.pathExists(planPath) ? await fs15.readFile(planPath, "utf-8") : "";
9710
- const tasksContent = await fs15.readFile(path19.join(config.docsDir, paths.tasksPath), "utf-8");
10011
+ const tasksContent = await fs15.readFile(path20.join(config.docsDir, paths.tasksPath), "utf-8");
9711
10012
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
9712
10013
  const defaultTitle = feature.issueNumber ? tg(config.lang, "prDefaultTitleWithIssue", {
9713
10014
  issue: feature.issueNumber,
@@ -9750,13 +10051,14 @@ function githubCommand(program2) {
9750
10051
  config.lang
9751
10052
  );
9752
10053
  } else {
9753
- await fs15.ensureDir(path19.dirname(bodyFile));
10054
+ await fs15.ensureDir(path20.dirname(bodyFile));
9754
10055
  await fs15.writeFile(bodyFile, generatedBody, "utf-8");
9755
10056
  }
9756
10057
  const retryCount = toRetryCount(options.retry, config.lang);
9757
10058
  let prUrl = options.pr?.trim() || "";
9758
10059
  let mergedAttempts;
9759
10060
  let syncChanged = false;
10061
+ const pushDocsSync = shouldPushDocsSync(config);
9760
10062
  if (options.create) {
9761
10063
  const projectGitCwd = resolveGithubProjectCwd(config, feature);
9762
10064
  ensureNoTodoPlaceholders(body, tg(config.lang, "kindPr"), config.lang);
@@ -9789,6 +10091,9 @@ function githubCommand(program2) {
9789
10091
  );
9790
10092
  prUrl = created.stdout.trim();
9791
10093
  }
10094
+ if (!prUrl && options.merge) {
10095
+ prUrl = (feature.pr.link || "").trim();
10096
+ }
9792
10097
  if (!prUrl && options.merge) {
9793
10098
  throw createCliError(
9794
10099
  "INVALID_ARGUMENT",
@@ -9804,7 +10109,7 @@ function githubCommand(program2) {
9804
10109
  }
9805
10110
  if (prUrl && options.syncTasks !== false) {
9806
10111
  const synced = syncTasksPrMetadata(
9807
- path19.join(config.docsDir, paths.tasksPath),
10112
+ path20.join(config.docsDir, paths.tasksPath),
9808
10113
  prUrl,
9809
10114
  "Review",
9810
10115
  config.lang
@@ -9823,7 +10128,8 @@ function githubCommand(program2) {
9823
10128
  docsGitCwd,
9824
10129
  synced.path,
9825
10130
  message,
9826
- config.lang
10131
+ config.lang,
10132
+ { pushToOrigin: pushDocsSync }
9827
10133
  );
9828
10134
  }
9829
10135
  }
@@ -9851,7 +10157,7 @@ function githubCommand(program2) {
9851
10157
  );
9852
10158
  if (prUrl && options.syncTasks !== false) {
9853
10159
  const mergedSync = syncTasksPrMetadata(
9854
- path19.join(config.docsDir, paths.tasksPath),
10160
+ path20.join(config.docsDir, paths.tasksPath),
9855
10161
  prUrl,
9856
10162
  "Approved",
9857
10163
  config.lang
@@ -9869,7 +10175,8 @@ function githubCommand(program2) {
9869
10175
  docsGitCwd,
9870
10176
  mergedSync.path,
9871
10177
  message,
9872
- config.lang
10178
+ config.lang,
10179
+ { pushToOrigin: pushDocsSync }
9873
10180
  );
9874
10181
  }
9875
10182
  }
@@ -10056,7 +10363,7 @@ function docsCommand(program2) {
10056
10363
  );
10057
10364
  return;
10058
10365
  }
10059
- const relativeFromCwd = path19.relative(process.cwd(), loaded.entry.absolutePath);
10366
+ const relativeFromCwd = path20.relative(process.cwd(), loaded.entry.absolutePath);
10060
10367
  console.log();
10061
10368
  console.log(chalk6.bold(`\u{1F4C4} ${loaded.entry.id}: ${loaded.entry.title}`));
10062
10369
  console.log(
@@ -10134,7 +10441,7 @@ function detectCommand(program2) {
10134
10441
  }
10135
10442
  async function runDetect(options) {
10136
10443
  const cwd = process.cwd();
10137
- const targetCwd = options.dir ? path19.resolve(cwd, options.dir) : cwd;
10444
+ const targetCwd = options.dir ? path20.resolve(cwd, options.dir) : cwd;
10138
10445
  const config = await getConfig(targetCwd);
10139
10446
  const detected = !!config;
10140
10447
  const reasonCode = detected ? "PROJECT_DETECTED" : "PROJECT_NOT_DETECTED";
@@ -10161,7 +10468,7 @@ async function runDetect(options) {
10161
10468
  );
10162
10469
  return;
10163
10470
  }
10164
- const configPath2 = path19.join(config.docsDir, ".lee-spec-kit.json");
10471
+ const configPath2 = path20.join(config.docsDir, ".lee-spec-kit.json");
10165
10472
  const configFilePresent2 = await fs15.pathExists(configPath2);
10166
10473
  const detectionSource2 = configFilePresent2 ? "config" : "heuristic";
10167
10474
  console.log(
@@ -10195,7 +10502,7 @@ async function runDetect(options) {
10195
10502
  console.log();
10196
10503
  return;
10197
10504
  }
10198
- const configPath = path19.join(config.docsDir, ".lee-spec-kit.json");
10505
+ const configPath = path20.join(config.docsDir, ".lee-spec-kit.json");
10199
10506
  const configFilePresent = await fs15.pathExists(configPath);
10200
10507
  const detectionSource = configFilePresent ? "config" : "heuristic";
10201
10508
  console.log(chalk6.green(`- ${tr(lang, "cli", "detect.resultDetected")}`));
@@ -10290,7 +10597,7 @@ async function countFeatureDirs(docsDir, projectType) {
10290
10597
  ignore: ["**/feature-base/**"]
10291
10598
  });
10292
10599
  return dirs.map((value) => value.replace(/\\/g, "/").replace(/\/+$/, "")).filter((value) => {
10293
- const base = path19.posix.basename(value);
10600
+ const base = path20.posix.basename(value);
10294
10601
  return !!base && base !== "feature-base";
10295
10602
  }).length;
10296
10603
  }
@@ -10302,7 +10609,7 @@ async function hasUserPrdFile(prdDir) {
10302
10609
  absolute: false,
10303
10610
  ignore: ["**/node_modules/**"]
10304
10611
  });
10305
- return files.some((relativePath) => path19.basename(relativePath).toLowerCase() !== "readme.md");
10612
+ return files.some((relativePath) => path20.basename(relativePath).toLowerCase() !== "readme.md");
10306
10613
  }
10307
10614
  function finalizeChecks(checks) {
10308
10615
  const summary = checks.reduce(
@@ -10431,7 +10738,7 @@ async function runOnboardChecks(config) {
10431
10738
  });
10432
10739
  }
10433
10740
  }
10434
- const constitutionPath = path19.join(docsDir, "agents", "constitution.md");
10741
+ const constitutionPath = path20.join(docsDir, "agents", "constitution.md");
10435
10742
  if (!await fs15.pathExists(constitutionPath)) {
10436
10743
  checks.push({
10437
10744
  id: "constitution_exists",
@@ -10469,7 +10776,7 @@ async function runOnboardChecks(config) {
10469
10776
  });
10470
10777
  }
10471
10778
  }
10472
- const customPath = path19.join(docsDir, "agents", "custom.md");
10779
+ const customPath = path20.join(docsDir, "agents", "custom.md");
10473
10780
  if (await fs15.pathExists(customPath)) {
10474
10781
  const content = await fs15.readFile(customPath, "utf-8");
10475
10782
  if (hasTemplateMarkers(content)) {
@@ -10494,7 +10801,7 @@ async function runOnboardChecks(config) {
10494
10801
  });
10495
10802
  }
10496
10803
  }
10497
- const prdDir = path19.join(docsDir, "prd");
10804
+ const prdDir = path20.join(docsDir, "prd");
10498
10805
  const featureCount = await countFeatureDirs(docsDir, config.projectType);
10499
10806
  const prdReady = await hasUserPrdFile(prdDir);
10500
10807
  if (!prdReady) {
@@ -10512,7 +10819,7 @@ async function runOnboardChecks(config) {
10512
10819
  "PRD is empty. If features already exist, fill PRD as soon as possible."
10513
10820
  ),
10514
10821
  path: prdDir,
10515
- suggestedCommand: `touch ${quotePath(path19.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
10822
+ suggestedCommand: `touch ${quotePath(path20.join(prdDir, `${toSlug(config.projectName || "project")}-prd.md`))}`
10516
10823
  });
10517
10824
  } else {
10518
10825
  checks.push({
@@ -10725,11 +11032,11 @@ ${version}
10725
11032
  }
10726
11033
  return `${ascii}${footer}`;
10727
11034
  }
10728
- var CACHE_FILE = path19.join(os.homedir(), ".lee-spec-kit-version-cache.json");
11035
+ var CACHE_FILE = path20.join(os.homedir(), ".lee-spec-kit-version-cache.json");
10729
11036
  var CHECK_INTERVAL = 24 * 60 * 60 * 1e3;
10730
11037
  function getCurrentVersion() {
10731
11038
  try {
10732
- const packageJsonPath = path19.join(__dirname$1, "..", "package.json");
11039
+ const packageJsonPath = path20.join(__dirname$1, "..", "package.json");
10733
11040
  if (fs15.existsSync(packageJsonPath)) {
10734
11041
  const pkg = fs15.readJsonSync(packageJsonPath);
10735
11042
  return pkg.version;
@@ -10833,7 +11140,7 @@ function shouldCheckForUpdates() {
10833
11140
  if (shouldCheckForUpdates()) checkForUpdates();
10834
11141
  function getCliVersion() {
10835
11142
  try {
10836
- const packageJsonPath = path19.join(__dirname$1, "..", "package.json");
11143
+ const packageJsonPath = path20.join(__dirname$1, "..", "package.json");
10837
11144
  if (fs15.existsSync(packageJsonPath)) {
10838
11145
  const pkg = fs15.readJsonSync(packageJsonPath);
10839
11146
  if (pkg?.version) return String(pkg.version);