lee-spec-kit 0.6.41 → 0.6.43

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
@@ -478,7 +478,7 @@ var koContext = {
478
478
  "context.commandDetail.codeReviewPushFix": "({scope}) \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 push\uD558\uC138\uC694",
479
479
  "context.commandDetail.prePrReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
480
480
  "context.commandDetail.prePrReviewRecord": "({scope}) Pre-PR \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
481
- "context.commandDetail.codeReviewRun": "({scope}) \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 evidence/\uC218\uC815 \uC694\uC57D\uC744 \uC900\uBE44\uD558\uC138\uC694",
481
+ "context.commandDetail.codeReviewRun": "({scope}) \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0, \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C \uC218\uC815 \uC791\uC5C5/evidence \uC815\uB9AC\uB97C \uC9C4\uD589\uD558\uC138\uC694",
482
482
  "context.actionSummary.runDocsCommand": "\uBB38\uC11C \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
483
483
  "context.actionSummary.runProjectCommand": "\uD504\uB85C\uC81D\uD2B8 \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
484
484
  "context.actionDetail.featureFolder": "Feature \uD3F4\uB354\uC640 \uAE30\uBCF8 \uBB38\uC11C \uACE8\uACA9\uC744 \uC900\uBE44\uD558\uC138\uC694",
@@ -496,12 +496,13 @@ var koContext = {
496
496
  "context.actionDetail.issueCreatePrepareFromDoc": "issue.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
497
497
  "context.actionDetail.issueCreateFromDoc": "Ready \uC0C1\uD0DC issue.md\uB85C \uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
498
498
  "context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
499
- "context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
500
- "context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uC774\uC5B4\uAC00\uC138\uC694",
499
+ "context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: {task}. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
500
+ "context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uB9C8\uBB34\uB9AC\uD558\uC138\uC694: {task}. (\uC644\uB8CC \uD6C4 \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 DONE\uC73C\uB85C \uBCC0\uACBD)",
501
+ "context.actionDetail.taskExecuteComplete": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC644\uB8CC \uCC98\uB9AC\uD558\uC138\uC694: {task}. (DOING\uC744 DONE\uC73C\uB85C \uBCC0\uACBD)",
501
502
  "context.actionDetail.reviewFixCommit": "\uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uB9CC\uB4DC\uC138\uC694",
502
503
  "context.actionDetail.prePrReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
503
504
  "context.actionDetail.prePrReviewRecord": "PR \uC804 \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
504
- "context.actionDetail.codeReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 evidence/\uC218\uC815 \uC694\uC57D\uC744 \uC900\uBE44\uD558\uC138\uC694",
505
+ "context.actionDetail.codeReviewRun": "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0, \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C \uC218\uC815 \uC791\uC5C5/evidence \uC815\uB9AC\uB97C \uC9C4\uD589\uD558\uC138\uC694",
505
506
  "context.actionDetail.prCreate": "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks \uAE30.md\uC758 PR \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
506
507
  "context.actionDetail.prCreateRequiredSequence": "PR 2\uB2E8\uACC4(\uCD08\uC548/\uC2B9\uC778 \uD6C4 \uC0DD\uC131/\uB3D9\uAE30\uD654)\uB97C \uC21C\uC11C\uB300\uB85C \uC644\uB8CC\uD558\uC138\uC694",
507
508
  "context.actionDetail.prCreatePrepareFromDoc": "pr.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
@@ -1030,7 +1031,7 @@ var enContext = {
1030
1031
  "context.commandDetail.codeReviewPushFix": "({scope}) push review-fix commits",
1031
1032
  "context.commandDetail.prePrReviewRun": "({scope}) run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
1032
1033
  "context.commandDetail.prePrReviewRecord": "({scope}) record pre-PR review evidence into decisions.md + tasks.md",
1033
- "context.commandDetail.codeReviewRun": "({scope}) run the PR review via a helper agent/sub-agent and prepare evidence/fix summary",
1034
+ "context.commandDetail.codeReviewRun": "({scope}) check PR review comments, then use a helper agent/sub-agent for the follow-up fixes and evidence summary",
1034
1035
  "context.actionSummary.runDocsCommand": "Run docs command",
1035
1036
  "context.actionSummary.runProjectCommand": "Run project command",
1036
1037
  "context.actionDetail.featureFolder": "Prepare feature folder and baseline docs",
@@ -1048,12 +1049,13 @@ var enContext = {
1048
1049
  "context.actionDetail.issueCreatePrepareFromDoc": "Refine issue.md draft and set Status to Ready",
1049
1050
  "context.actionDetail.issueCreateFromDoc": "Create GitHub Issue from ready issue.md and sync Issue",
1050
1051
  "context.actionDetail.taskExecute": "Proceed with the current task",
1051
- "context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task. (TODO becomes DOING)",
1052
- "context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and continue the in-progress task",
1052
+ "context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task: {task}. (TODO becomes DOING)",
1053
+ "context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and wrap up the in-progress task: {task}. (Share outcome/verification, then mark it DONE)",
1054
+ "context.actionDetail.taskExecuteComplete": "Mark the current task as complete: {task}. (Change DOING to DONE)",
1053
1055
  "context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
1054
1056
  "context.actionDetail.prePrReviewRun": "Run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
1055
1057
  "context.actionDetail.prePrReviewRecord": "Record pre-PR review evidence into decisions.md and tasks.md",
1056
- "context.actionDetail.codeReviewRun": "Run the PR review via a helper agent/sub-agent and prepare evidence/fix summary",
1058
+ "context.actionDetail.codeReviewRun": "Check PR review comments, then use a helper agent/sub-agent for the follow-up fixes and evidence summary",
1057
1059
  "context.actionDetail.prCreate": "Create PR and sync PR fields in tasks.md",
1058
1060
  "context.actionDetail.prCreateRequiredSequence": "Complete PR 2-step flow: prepare draft + OK, then create and sync",
1059
1061
  "context.actionDetail.prCreatePrepareFromDoc": "Refine pr.md draft and set Status to Ready",
@@ -3553,6 +3555,7 @@ function resolvePrePrReviewPolicy(workflow) {
3553
3555
  function getPrePrReviewPrompt(lang, skills, fallbackText) {
3554
3556
  if (lang === "ko") {
3555
3557
  return `PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694.
3558
+ 0. \uAC19\uC740 feature/pre-PR \uB9AC\uBDF0\uB97C \uB2F4\uB2F9\uD558\uB358 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC774\uBBF8 \uC788\uC73C\uBA74 \uC0C8\uB85C \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694. \uAE30\uBCF8\uC740 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 1\uAC1C\uC785\uB2C8\uB2E4.
3556
3559
  1. \`spec.md\`, \`plan.md\`, \`tasks.md\`\uB97C \uC77D\uACE0 feature \uBAA9\uD45C/\uBC94\uC704/\uC644\uB8CC \uAE30\uC900\uC744 \uBA3C\uC800 \uC694\uC57D\uD558\uC138\uC694.
3557
3560
  2. \uB9AC\uBDF0 \uBC94\uC704\uB97C \uBD84\uB9AC\uD574 \uD655\uC778\uD558\uC138\uC694.
3558
3561
  - main \uAE30\uC900: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
@@ -3561,11 +3564,14 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
3561
3564
  4. \uD655\uC778\uB41C \uAC01 \uD30C\uC77C\uC5D0 \uB300\uD574 risk, security, perf, maintainability \uD3C9\uAC00\uC640 \uAD6C\uCCB4\uC801\uC778 fileLine \uC704\uCE58\uAC00 \uD3EC\uD568\uB41C 'review-trace.json' \uC99D\uAC70 \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC138\uC694.
3562
3565
  5. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 '${fallbackText}'\uC774\uBA70, 'create-pr' \uBB38\uC11C\uC758 'Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8' \uC139\uC158\uC744 \uC218\uD589\uD558\uC138\uC694.
3563
3566
  6. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: ${skills.length > 0 ? skills.join(", ") : "\uC5C6\uC74C"} \uB85C \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694.
3564
- 7. \uCD94\uAC00 \uAC80\uC99D\uC774 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC audit/\uD0C0\uAE43 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uACE0, \uC2E4\uD589\uD588\uB2E4\uBA74 \`commandsExecuted\`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.
3565
- 8. \uC9C0\uC801\uC0AC\uD56D\uC774 \uB0A8\uC544 \uC788\uC73C\uBA74 \uBA3C\uC800 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested' \uB85C \uAE30\uB85D\uD558\uC138\uC694. \uB2E8, \`workflow.prePrReview.evidenceMode=any\` \uC774\uACE0 \uC2E4\uD589 \uC99D\uAC70 \uAC15\uC81C\uAC00 \uC5C6\uC73C\uBA74 \`--evidence\` \uC5C6\uC774 \uC9C1\uC811 \uAE30\uB85D\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3566
- 9. \uC218\uC815/\uC7AC\uAC80\uC99D \uD6C4 \uCD5C\uC885 \uC2B9\uC778 \uC2DC\uC810\uC5D0 'npx lee-spec-kit pre-pr-review <feature> --decision approve' \uB97C \uC2E4\uD589\uD558\uC138\uC694. \`path_required\` \uC815\uCC45\uC77C \uB54C\uB9CC \`--evidence review-trace.json\` \uC744 \uD568\uAED8 \uBD99\uC774\uC138\uC694.`;
3567
+ 7. \uCD94\uAC00 \uAC80\uC99D\uC774 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC audit/\uD0C0\uAE43 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694. \uBCC4\uB3C4 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uCD94\uAC00 \uC0DD\uC131\uB3C4 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC \uD558\uC138\uC694.
3568
+ 8. \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uACE0, \uC774\uBBF8 \uC218\uC9D1\uD55C \uACB0\uACFC\uB9CC \uC815\uB9AC\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3569
+ 9. \uC2E4\uD589\uD55C \uBA85\uB839\uC774 \uC788\uC73C\uBA74 \`commandsExecuted\`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.
3570
+ 10. \uC9C0\uC801\uC0AC\uD56D\uC774 \uB0A8\uC544 \uC788\uC73C\uBA74 \uBA3C\uC800 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested' \uB85C \uAE30\uB85D\uD558\uC138\uC694. \uB2E8, \`workflow.prePrReview.evidenceMode=any\` \uC774\uACE0 \uC2E4\uD589 \uC99D\uAC70 \uAC15\uC81C\uAC00 \uC5C6\uC73C\uBA74 \`--evidence\` \uC5C6\uC774 \uC9C1\uC811 \uAE30\uB85D\uD574\uB3C4 \uB429\uB2C8\uB2E4.
3571
+ 11. \uC218\uC815/\uC7AC\uAC80\uC99D \uD6C4 \uCD5C\uC885 \uC2B9\uC778 \uC2DC\uC810\uC5D0 'npx lee-spec-kit pre-pr-review <feature> --decision approve' \uB97C \uC2E4\uD589\uD558\uC138\uC694. \`path_required\` \uC815\uCC45\uC77C \uB54C\uB9CC \`--evidence review-trace.json\` \uC744 \uD568\uAED8 \uBD99\uC774\uC138\uC694.`;
3567
3572
  }
3568
3573
  return `Conduct a pre-PR code review.
3574
+ 0. Reuse the existing helper/sub-agent for this feature review if one already exists. Default to a single helper agent.
3569
3575
  1. Read \`spec.md\`, \`plan.md\`, and \`tasks.md\` first, then summarize the feature goal, scope, and done criteria.
3570
3576
  2. Split and check the review scope.
3571
3577
  - Main scope: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
@@ -3574,15 +3580,17 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
3574
3580
  4. Generate a 'review-trace.json' file for all changed files, including \`findingCount\`, \`blockingFindings\`, evaluations for risk, security, perf, maintainability, and specific fileLine locators.
3575
3581
  5. The baseline is '${fallbackText}'. Always perform the 'Pre-PR Core Checklist' section of the 'create-pr' document.
3576
3582
  6. Priority skills: ${skills.length > 0 ? skills.join(", ") : "None"} for deeper technical review.
3577
- 7. Run extra audit/targeted verification only when the review needs more evidence, and record those commands in \`commandsExecuted\` when used.
3578
- 8. If unresolved findings remain, first record them with 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested'. When \`workflow.prePrReview.evidenceMode=any\` and execution evidence is not enforced, direct record mode without \`--evidence\` is also valid.
3579
- 9. After fixes and re-validation, run 'npx lee-spec-kit pre-pr-review <feature> --decision approve' for final pre-PR approval. Add \`--evidence review-trace.json\` only when the active evidence policy requires a path.`;
3583
+ 7. Run extra audit/targeted verification only when the review truly needs more evidence. Spawn additional helper agents only when necessary.
3584
+ 8. If helper-agent quota is exhausted, continue the review in the main agent and just keep the evidence consistent.
3585
+ 9. Record commands in \`commandsExecuted\` only when you actually ran them.
3586
+ 10. If unresolved findings remain, first record them with 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested'. When \`workflow.prePrReview.evidenceMode=any\` and execution evidence is not enforced, direct record mode without \`--evidence\` is also valid.
3587
+ 11. After fixes and re-validation, run 'npx lee-spec-kit pre-pr-review <feature> --decision approve' for final pre-PR approval. Add \`--evidence review-trace.json\` only when the active evidence policy requires a path.`;
3580
3588
  }
3581
3589
  function getCodeReviewPrompt(lang) {
3582
3590
  if (lang === "ko") {
3583
- return `\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694. PR \uC0C1\uD0DC\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0 'PR \uB9AC\uBDF0 Evidence/Decision'\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. \uC6D0\uACA9 \uBC18\uC601(push)\uC740 \uBA85\uC2DC\uC801\uC778 \uBA38\uC9C0 \uC2B9\uC778(\uB77C\uBCA8) \uD6C4, \uB85C\uCEEC \uBE0C\uB79C\uCE58\uAC00 upstream\uBCF4\uB2E4 \uC55E\uC120 \uACBD\uC6B0\uC5D0\uB9CC \uC9C4\uD589\uD558\uC138\uC694.`;
3591
+ return `\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uAE30\uC874 review \uB2F4\uB2F9 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694. \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uC774\uC5B4\uAC00\uC138\uC694. PR \uC0C1\uD0DC\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0 'PR \uB9AC\uBDF0 Evidence/Decision'\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. \uC6D0\uACA9 \uBC18\uC601(push)\uC740 \uBA85\uC2DC\uC801\uC778 \uBA38\uC9C0 \uC2B9\uC778(\uB77C\uBCA8) \uD6C4, \uB85C\uCEEC \uBE0C\uB79C\uCE58\uAC00 upstream\uBCF4\uB2E4 \uC55E\uC120 \uACBD\uC6B0\uC5D0\uB9CC \uC9C4\uD589\uD558\uC138\uC694.`;
3584
3592
  }
3585
- return `Review and analyze comments, then make necessary fixes. Keep PR status as Review and record the latest 'PR Review Evidence/Decision'. Push changes only after explicit approval (label) and only if the local branch is ahead of upstream.`;
3593
+ return `Review and analyze comments, then make necessary fixes. Reuse the existing review helper agent if one already exists, and default to a single helper agent. If helper-agent quota is exhausted, continue in the main agent. Keep PR status as Review and record the latest 'PR Review Evidence/Decision'. Push changes only after explicit approval (label) and only if the local branch is ahead of upstream.`;
3586
3594
  }
3587
3595
 
3588
3596
  // src/utils/context/steps.ts
@@ -3694,6 +3702,13 @@ function buildTaskRunCommandArgs(feature, taskId) {
3694
3702
  }
3695
3703
  return commandArgs;
3696
3704
  }
3705
+ function buildTaskCompleteCommandArgs(feature, taskId) {
3706
+ const commandArgs = ["task-complete", feature.folderName, "--task", taskId];
3707
+ if (feature.type && feature.type !== "single") {
3708
+ commandArgs.push("--component", feature.type);
3709
+ }
3710
+ return commandArgs;
3711
+ }
3697
3712
  function buildCodeReviewRunCommandArgs(feature) {
3698
3713
  const commandArgs = ["code-review-run", feature.folderName];
3699
3714
  if (feature.type && feature.type !== "single") {
@@ -3769,6 +3784,14 @@ function resolveProjectCommitTopic(feature) {
3769
3784
  const topic = withoutTaskId || normalizeCommitTopicText(feature.folderName);
3770
3785
  return toShellSafeCommitTopic(topic);
3771
3786
  }
3787
+ function resolveTaskUiLabel(task) {
3788
+ if (!task) return "T-unknown task";
3789
+ const id = task.id?.trim();
3790
+ const title = task.title.trim();
3791
+ const normalizedTitle = id ? title.replace(new RegExp(`^${id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s+`), "") : title;
3792
+ if (id) return `${id} - ${normalizedTitle || title}`;
3793
+ return title || "T-unknown task";
3794
+ }
3772
3795
  function getReviewFixCommitGuidance(feature, lang, options) {
3773
3796
  const prePr = !!options?.prePr;
3774
3797
  if (prePr) {
@@ -3841,7 +3864,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
3841
3864
  if (!diff.trim()) return 0;
3842
3865
  const removedByTask = /* @__PURE__ */ new Map();
3843
3866
  const addedByTask = /* @__PURE__ */ new Map();
3844
- const parseTaskLine2 = (line) => {
3867
+ const parseTaskLine3 = (line) => {
3845
3868
  const match = line.match(
3846
3869
  /^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\s+(.+?)\s*$/i
3847
3870
  );
@@ -3856,7 +3879,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
3856
3879
  for (const line of diff.split("\n")) {
3857
3880
  if (line.startsWith("---") || line.startsWith("+++")) continue;
3858
3881
  if (line.startsWith("-")) {
3859
- const parsed = parseTaskLine2(line.slice(1));
3882
+ const parsed = parseTaskLine3(line.slice(1));
3860
3883
  if (!parsed) continue;
3861
3884
  const existing = removedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
3862
3885
  existing.add(parsed.status);
@@ -3864,7 +3887,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
3864
3887
  continue;
3865
3888
  }
3866
3889
  if (line.startsWith("+")) {
3867
- const parsed = parseTaskLine2(line.slice(1));
3890
+ const parsed = parseTaskLine3(line.slice(1));
3868
3891
  if (!parsed) continue;
3869
3892
  const existing = addedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
3870
3893
  existing.add(parsed.status);
@@ -4065,11 +4088,14 @@ function getStepDefinitions(ctx) {
4065
4088
  operationType: "local",
4066
4089
  requiresUserCheck: true,
4067
4090
  taskExecutePhase: "complete",
4068
- uiDetailKey: "context.actionDetail.taskExecuteContinue",
4091
+ uiDetailKey: "context.actionDetail.taskExecuteComplete",
4092
+ uiDetailParams: {
4093
+ task: resolveTaskUiLabel(f.activeTask)
4094
+ },
4069
4095
  scope: "docs",
4070
4096
  cwd: f.git.docsGitCwd,
4071
4097
  cmd: buildSelfCliCommand(
4072
- buildTaskRunCommandArgs(
4098
+ buildTaskCompleteCommandArgs(
4073
4099
  f,
4074
4100
  f.activeTask?.id || `T-${f.folderName}-active`
4075
4101
  )
@@ -4188,6 +4214,9 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4188
4214
  requiresUserCheck: true,
4189
4215
  taskExecutePhase: "start",
4190
4216
  uiDetailKey: "context.actionDetail.taskExecuteRun",
4217
+ uiDetailParams: {
4218
+ task: resolveTaskUiLabel(f.nextTodoTask)
4219
+ },
4191
4220
  scope: "docs",
4192
4221
  cwd: f.git.docsGitCwd,
4193
4222
  cmd: buildSelfCliCommand(
@@ -4348,7 +4377,7 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
4348
4377
  const isCodeReviewNeedEvidence = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided;
4349
4378
  const isCodeReviewNeedDecisionField = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && f.prReview.evidenceProvided && !f.docs.prReviewDecisionFieldExists;
4350
4379
  const isCodeReviewNeedDecision = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && f.prReview.evidenceProvided && !isCodeReviewNeedDecisionField(f) && !f.prReview.decisionProvided;
4351
- const isCodeReviewRun = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided && !f.prReview.decisionProvided;
4380
+ const isCodeReviewRun = (f) => isCodeReviewCurrent(f) && f.pr.status === "Review" && workflowPolicy.requireReview && (f.git.projectBranchAhead || 0) === 0 && !isCodeReviewNeedEvidenceField(f) && !f.prReview.evidenceProvided && !f.prReview.decisionProvided;
4352
4381
  const isCodeReviewFinalize = (f) => isCodeReviewCurrent(f) && !isCodeReviewSyncApproved(f) && (!workflowPolicy.requireReview || f.pr.status === "Review" && !isCodeReviewNeedEvidenceField(f) && !isCodeReviewNeedEvidence(f) && !isCodeReviewNeedDecisionField(f) && !isCodeReviewNeedDecision(f) && f.prReview.evidenceProvided && f.prReview.decisionProvided);
4353
4382
  const isCodeReviewRequestReview = (f) => isCodeReviewCurrent(f) && !!f.pr.status && f.pr.status !== "Review";
4354
4383
  const getCodeReviewRunActions = (f) => [
@@ -4733,9 +4762,9 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
4733
4762
  actions: (f) => getTaskExecuteFinalizeActions(f)
4734
4763
  },
4735
4764
  {
4736
- id: "task_running",
4737
- phase: "running",
4738
- owner: "subagent",
4765
+ id: "task_complete",
4766
+ phase: "finalize",
4767
+ owner: "main",
4739
4768
  category: "task_execute",
4740
4769
  when: (f) => isTaskExecuteCurrent(f) && !!f.activeTask,
4741
4770
  actions: (f) => getTaskExecuteRunningActions(f)
@@ -5192,7 +5221,7 @@ function applyApprovalPolicy(step, actions, approval, currentSubstatePhase) {
5192
5221
  function applyTaskExecutePhaseCheck(action, requiresUserCheck, policy, explicitlyRequired = false, currentSubstatePhase) {
5193
5222
  if (policy !== "start_only") return requiresUserCheck;
5194
5223
  if (action.category !== "task_execute") return requiresUserCheck;
5195
- const isCompletionPhase = currentSubstatePhase === "running" || !currentSubstatePhase && action.taskExecutePhase === "complete";
5224
+ const isCompletionPhase = currentSubstatePhase === "running" || currentSubstatePhase === "finalize" || !currentSubstatePhase && action.taskExecutePhase === "complete";
5196
5225
  if (!isCompletionPhase) return requiresUserCheck;
5197
5226
  if (explicitlyRequired) return requiresUserCheck;
5198
5227
  return false;
@@ -8130,11 +8159,11 @@ function annotateActions(actions) {
8130
8159
  }
8131
8160
  function getActionSummary(action, lang) {
8132
8161
  if (action.uiSummaryKey) {
8133
- const localized = tr(lang, "cli", action.uiSummaryKey);
8162
+ const localized = tr(lang, "cli", action.uiSummaryKey, action.uiDetailParams);
8134
8163
  if (localized !== `cli.${action.uiSummaryKey}`) return localized;
8135
8164
  }
8136
8165
  if (action.uiDetailKey) {
8137
- const localized = tr(lang, "cli", action.uiDetailKey);
8166
+ const localized = tr(lang, "cli", action.uiDetailKey, action.uiDetailParams);
8138
8167
  if (localized !== `cli.${action.uiDetailKey}`) return localized;
8139
8168
  }
8140
8169
  const detailKey = action.category ? ACTION_DETAIL_KEY_BY_CATEGORY[action.category] : void 0;
@@ -8159,7 +8188,7 @@ function toOneLine(text) {
8159
8188
  }
8160
8189
  function buildActionDetail(action, lang) {
8161
8190
  if (action.uiDetailKey) {
8162
- const localized = tr(lang, "cli", action.uiDetailKey);
8191
+ const localized = tr(lang, "cli", action.uiDetailKey, action.uiDetailParams);
8163
8192
  if (localized !== `cli.${action.uiDetailKey}`) return localized;
8164
8193
  }
8165
8194
  const formatBranchCreateDetail = (command) => {
@@ -8257,7 +8286,7 @@ function toActionOptions(actions, lang) {
8257
8286
  const summary = getActionSummary(action, lang);
8258
8287
  const detail = buildActionDetail(action, lang);
8259
8288
  const requiresRequestText = action.category === "user_request_replan";
8260
- const replyExample = requiresRequestText ? `${label}, <your request>` : `${label} OK`;
8289
+ const replyExample = requiresRequestText ? `${label}, <your request>` : label;
8261
8290
  return {
8262
8291
  label,
8263
8292
  summary,
@@ -8282,7 +8311,8 @@ function buildActionSnapshot(actionOptions) {
8282
8311
  operationType: action.operationType,
8283
8312
  requiresUserCheck: !!action.requiresUserCheck,
8284
8313
  uiSummaryKey: action.uiSummaryKey,
8285
- uiDetailKey: action.uiDetailKey
8314
+ uiDetailKey: action.uiDetailKey,
8315
+ uiDetailParams: action.uiDetailParams ? JSON.stringify(action.uiDetailParams) : void 0
8286
8316
  };
8287
8317
  }
8288
8318
  return {
@@ -8293,7 +8323,8 @@ function buildActionSnapshot(actionOptions) {
8293
8323
  operationType: action.operationType,
8294
8324
  requiresUserCheck: !!action.requiresUserCheck,
8295
8325
  uiSummaryKey: action.uiSummaryKey,
8296
- uiDetailKey: action.uiDetailKey
8326
+ uiDetailKey: action.uiDetailKey,
8327
+ uiDetailParams: action.uiDetailParams ? JSON.stringify(action.uiDetailParams) : void 0
8297
8328
  };
8298
8329
  });
8299
8330
  }
@@ -8915,6 +8946,9 @@ function toCompactActionOption(option) {
8915
8946
  if (option.action.taskExecutePhase) {
8916
8947
  base.taskExecutePhase = option.action.taskExecutePhase;
8917
8948
  }
8949
+ if (option.action.uiDetailParams) {
8950
+ base.uiDetailParams = option.action.uiDetailParams;
8951
+ }
8918
8952
  if (option.action.type === "command") {
8919
8953
  base.scope = option.action.scope;
8920
8954
  base.cwd = option.action.cwd;
@@ -9205,7 +9239,11 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9205
9239
  approval,
9206
9240
  state.actionOptions.map((o) => o.label)
9207
9241
  );
9208
- parsedLabel = parsedApproval?.label ?? null;
9242
+ const replanOptions = state.actionOptions.filter(
9243
+ (option) => option.action.category === "user_request_replan"
9244
+ );
9245
+ const implicitReplanRequest = approval.trim();
9246
+ parsedLabel = parsedApproval?.label ?? (replanOptions.length > 0 && implicitReplanRequest ? replanOptions[0].label : null);
9209
9247
  if (!parsedLabel) {
9210
9248
  throw createCliError(
9211
9249
  "INVALID_APPROVAL",
@@ -9249,7 +9287,7 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
9249
9287
  }
9250
9288
  const selectedAction = freshSelected.action;
9251
9289
  if (selectedAction.category === "user_request_replan") {
9252
- const requestText = parsedApproval?.requestText?.trim();
9290
+ const requestText = (parsedApproval?.requestText?.trim() || (parsedApproval ? "" : implicitReplanRequest)).trim();
9253
9291
  if (!requestText) {
9254
9292
  throw createCliError(
9255
9293
  "INVALID_APPROVAL",
@@ -12409,6 +12447,12 @@ function sanitizeDraftMetadataValue(raw) {
12409
12447
  if (/^\(.+\)$/.test(value)) return void 0;
12410
12448
  return value;
12411
12449
  }
12450
+ function sanitizeDraftTitleValue(raw) {
12451
+ const value = sanitizeDraftMetadataValue(raw);
12452
+ if (!value) return void 0;
12453
+ const normalized = value.replace(/`/g, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\[(.*?)\]\((.*?)\)/g, "$1").replace(/\s+/g, " ").trim();
12454
+ return normalized || void 0;
12455
+ }
12412
12456
  function parseWorkflowDraftStatus(raw) {
12413
12457
  const value = (raw || "").trim();
12414
12458
  if (!value) return void 0;
@@ -12420,7 +12464,7 @@ function parseWorkflowDraftMetadata(content) {
12420
12464
  const status = parseWorkflowDraftStatus(
12421
12465
  extractDraftMetadataValue(content, ["Status", "\uC0C1\uD0DC"])
12422
12466
  );
12423
- const title = sanitizeDraftMetadataValue(
12467
+ const title = sanitizeDraftTitleValue(
12424
12468
  extractDraftMetadataValue(content, ["Title", "\uC81C\uBAA9", "PR Title", "PR \uC81C\uBAA9"])
12425
12469
  );
12426
12470
  const labels = sanitizeDraftMetadataValue(
@@ -15899,6 +15943,9 @@ async function runPrePrReviewRun(featureName, options) {
15899
15943
  fallback: policy.fallback,
15900
15944
  handoffOnly: true,
15901
15945
  advancesWorkflow: false,
15946
+ reuseKey: `pre-pr:${featureRef}`,
15947
+ suggestedParallelism: 1,
15948
+ fallbackToMainAgentWhenQuotaExceeded: true,
15902
15949
  nextStepRequirement: "generate_review_trace_then_record",
15903
15950
  evidenceFile: "review-trace.json",
15904
15951
  prompt,
@@ -15920,6 +15967,18 @@ async function runPrePrReviewRun(featureName, options) {
15920
15967
  config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. review-trace.json\uC744 \uC9C1\uC811 \uC0DD\uC131\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the review handoff. It does not generate review-trace.json or advance workflow state by itself."
15921
15968
  )
15922
15969
  );
15970
+ console.log(
15971
+ chalk8.gray(
15972
+ config.lang === "ko" ? "- \uAE30\uC874 pre-PR \uB9AC\uBDF0 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694." : "- Reuse the existing pre-PR helper agent if one already exists; default to a single helper agent."
15973
+ )
15974
+ );
15975
+ console.log(
15976
+ chalk8.gray(
15977
+ config.lang === "ko" ? "- \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uC138\uC694." : "- If helper-agent quota is exhausted, continue the review in the main agent."
15978
+ )
15979
+ );
15980
+ console.log(`Reuse key: pre-pr:${featureRef}`);
15981
+ console.log(`Suggested parallelism: 1`);
15923
15982
  console.log(`Evidence file: review-trace.json`);
15924
15983
  console.log(`Record changes requested: ${changesRequestedCommand}`);
15925
15984
  console.log(`Record approval: ${approveCommand}`);
@@ -16103,18 +16162,20 @@ async function runPrePrReview(featureName, options) {
16103
16162
  function buildCodeReviewRunPrompt(input) {
16104
16163
  if (input.lang === "ko") {
16105
16164
  return [
16106
- "PR \uB9AC\uBDF0 \uC2E4\uD589\uC744 \uC2DC\uC791\uD558\uC138\uC694.",
16165
+ "PR \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778\uD558\uACE0 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uB85C \uC218\uC815 \uC791\uC5C5\uC744 \uC9C4\uD589\uD558\uC138\uC694.",
16107
16166
  `- Feature: ${input.featureRef}`,
16108
16167
  `- ${input.basePrompt}`,
16109
- "- \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uBC18\uC601 \uD6C4 `tasks.md`\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence/Decision`\uC774 \uC544\uB2C8\uB77C `PR Review Evidence/Decision`\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694.",
16168
+ "- \uC0AC\uB78C/CodeRabbit\uC774 \uB0A8\uAE34 \uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uAC80\uD1A0\uD558\uACE0 \uD544\uC694\uD55C \uCF54\uB4DC/\uBB38\uC11C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694.",
16169
+ "- \uC218\uC815 \uB0B4\uC6A9\uACFC \uAC80\uD1A0 \uACB0\uACFC\uB97C \uBC18\uC601\uD55C \uB4A4 `tasks.md`\uC758 `PR Review Evidence/Decision`\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694.",
16110
16170
  "- \uAD00\uB828 \uC218\uC815\uC774 \uC0DD\uAE30\uBA74 \uCF54\uB4DC/\uBB38\uC11C \uBCC0\uACBD\uC744 \uC815\uB9AC\uD558\uACE0, push/merge\uB294 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8 \uCD5C\uC885 \uC0C1\uD0DC\uC5D0\uC11C\uB9CC \uC9C4\uD589\uD558\uC138\uC694."
16111
16171
  ].join("\n");
16112
16172
  }
16113
16173
  return [
16114
- "Start the PR review execution.",
16174
+ "Review PR comments and use a helper agent/sub-agent for the follow-up fixes.",
16115
16175
  `- Feature: ${input.featureRef}`,
16116
16176
  `- ${input.basePrompt}`,
16117
- "- Update `PR Review Evidence` and `PR Review Decision` in `tasks.md` after reviewing comments and applying fixes.",
16177
+ "- Check human/CodeRabbit review comments and make the required code/docs changes.",
16178
+ "- Update `PR Review Evidence` and `PR Review Decision` in `tasks.md` after applying the fixes and summarizing the outcome.",
16118
16179
  "- If review fixes are needed, keep code/docs changes ready for the main-agent finalize state. Push/merge stays in the main agent."
16119
16180
  ].join("\n");
16120
16181
  }
@@ -16150,6 +16211,9 @@ async function runCodeReviewRun(featureName, options) {
16150
16211
  owner: "subagent",
16151
16212
  handoffOnly: true,
16152
16213
  advancesWorkflow: false,
16214
+ reuseKey: `code-review:${feature.folderName}`,
16215
+ suggestedParallelism: 1,
16216
+ fallbackToMainAgentWhenQuotaExceeded: true,
16153
16217
  nextMainState: "code_review_finalize",
16154
16218
  tasksPath: path12.join(feature.path, "tasks.md"),
16155
16219
  decisionsPath: path12.join(feature.path, "decisions.md"),
@@ -16164,11 +16228,18 @@ async function runCodeReviewRun(featureName, options) {
16164
16228
  console.log();
16165
16229
  console.log(
16166
16230
  chalk8.yellow(
16167
- config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \uB9AC\uBDF0 evidence/decision\uC744 \uC9C1\uC811 \uAE30\uB85D\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the PR review handoff. It does not record review evidence/decision or advance workflow state by itself."
16231
+ config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 PR \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uB300\uC751\uC6A9 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. \uCF54\uBA58\uD2B8\uB97C \uC9C1\uC811 \uC77D\uC5B4\uC624\uAC70\uB098 evidence/decision\uC744 \uC790\uB3D9 \uAE30\uB85D\uD558\uC9C0 \uC54A\uC73C\uBA70, \uC0C1\uD0DC\uB3C4 \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares a handoff for addressing PR review comments. It does not fetch comments automatically, record review evidence/decision, or advance workflow state by itself."
16168
16232
  )
16169
16233
  );
16170
16234
  console.log(chalk8.gray(`- substate: ${payload.substateId}`));
16171
16235
  console.log(chalk8.gray(`- owner: ${payload.owner}`));
16236
+ console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
16237
+ console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
16238
+ console.log(
16239
+ chalk8.gray(
16240
+ `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
16241
+ )
16242
+ );
16172
16243
  console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
16173
16244
  console.log(chalk8.gray(`- tasks.md: ${payload.tasksPath}`));
16174
16245
  console.log(chalk8.gray(`- decisions.md: ${payload.decisionsPath}`));
@@ -16420,9 +16491,10 @@ function parseTaskLine(line) {
16420
16491
  function buildTaskRunPrompt(input) {
16421
16492
  const shared = [
16422
16493
  "Read `spec.md`, `plan.md`, and `tasks.md` before editing code.",
16423
- "Use sub-agents by default for code analysis and discovery work.",
16424
- "Parallelize impact analysis, test-location search, and existing-pattern discovery when those can be done independently.",
16494
+ "Reuse the existing helper/sub-agent for this task if one already exists. Default to a single helper agent.",
16495
+ "Use additional helper agents only when parallel analysis is clearly worth the extra slot cost.",
16425
16496
  "Keep one writer for overlapping files; do not let multiple sub-agents edit the same files concurrently.",
16497
+ "If helper-agent quota is exhausted, continue the task in the main agent instead of blocking progress.",
16426
16498
  "Update the assigned task status and verification notes in `tasks.md` before leaving this task.",
16427
16499
  "Mark the task `DONE` only after code changes and verification are complete."
16428
16500
  ];
@@ -16433,9 +16505,10 @@ function buildTaskRunPrompt(input) {
16433
16505
  `- Task: ${input.taskId} ${input.title}`,
16434
16506
  input.mode === "start" ? "- \uC774 \uBA85\uB839\uC740 `tasks.md`\uC758 \uD604\uC7AC task\uB97C `DOING`\uC73C\uB85C \uBC14\uAFB8\uACE0, \uC774\uD6C4 \uAD6C\uD604 handoff prompt\uB97C \uC900\uBE44\uD569\uB2C8\uB2E4." : "- \uC774 \uBA85\uB839\uC740 \uC9C4\uD589 \uC911 task\uC758 \uAD6C\uD604 handoff prompt\uB97C \uB2E4\uC2DC \uC900\uBE44\uD569\uB2C8\uB2E4.",
16435
16507
  "- \uBA3C\uC800 `spec.md`, `plan.md`, `tasks.md`\uB97C \uC77D\uACE0 \uBC94\uC704\uC640 \uC644\uB8CC \uAE30\uC900\uC744 \uC815\uB9AC\uD558\uC138\uC694.",
16436
- "- \uCF54\uB4DC \uBD84\uC11D\uACFC \uD0D0\uC0C9 \uC791\uC5C5\uC740 \uAE30\uBCF8\uC801\uC73C\uB85C \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
16437
- "- \uC601\uD5A5 \uBC94\uC704 \uBD84\uC11D, \uD14C\uC2A4\uD2B8 \uC704\uCE58 \uD0D0\uC0C9, \uAE30\uC874 \uD328\uD134 \uC870\uC0AC\uCC98\uB7FC \uB3C5\uB9BD\uC801\uC778 \uBD84\uC11D\uC740 \uBCD1\uB82C\uB85C \uC218\uD589\uD558\uC138\uC694.",
16508
+ "- \uAE30\uC874\uC5D0 \uC774 task\uB97C \uB9E1\uB358 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694.",
16509
+ "- \uC601\uD5A5 \uBC94\uC704 \uBD84\uC11D, \uD14C\uC2A4\uD2B8 \uC704\uCE58 \uD0D0\uC0C9, \uAE30\uC874 \uD328\uD134 \uC870\uC0AC\uAC00 \uC815\uB9D0 \uB3C5\uB9BD\uC801\uC77C \uB54C\uB9CC \uCD94\uAC00 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
16438
16510
  "- \uAC19\uC740 \uD30C\uC77C\uAD70\uC744 \uC218\uC815\uD558\uB294 \uC791\uC131\uC790\uB294 \uD55C \uBA85\uB9CC \uB450\uC138\uC694.",
16511
+ "- \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uAD6C\uD604\uC744 \uC774\uC5B4\uAC00\uC138\uC694.",
16439
16512
  "- \uC774 task\uB97C \uB9C8\uCE58\uAE30 \uC804 `tasks.md`\uC5D0 \uC0C1\uD0DC\uC640 \uAC80\uC99D \uBA54\uBAA8\uB97C \uBC18\uC601\uD558\uC138\uC694.",
16440
16513
  "- \uCF54\uB4DC \uBCC0\uACBD\uACFC \uAC80\uC99D\uC774 \uB05D\uB0AC\uC744 \uB54C\uB9CC task\uB97C `DONE`\uC73C\uB85C \uD45C\uC2DC\uD558\uC138\uC694."
16441
16514
  ].join("\n");
@@ -16534,7 +16607,11 @@ async function runTaskRun(featureName, options) {
16534
16607
  mode,
16535
16608
  substateId: mode === "start" ? "task_run" : "task_running",
16536
16609
  owner: "subagent",
16537
- nextMainState: "task_finalize",
16610
+ handoffOnly: true,
16611
+ reuseKey: `task:${feature.folderName}:${resolvedTask.taskId}`,
16612
+ suggestedParallelism: 1,
16613
+ fallbackToMainAgentWhenQuotaExceeded: true,
16614
+ nextMainState: "task_complete",
16538
16615
  tasksUpdated,
16539
16616
  tasksPath,
16540
16617
  prompt,
@@ -16548,6 +16625,13 @@ async function runTaskRun(featureName, options) {
16548
16625
  console.log();
16549
16626
  console.log(chalk8.gray(`- substate: ${payload.substateId}`));
16550
16627
  console.log(chalk8.gray(`- owner: ${payload.owner}`));
16628
+ console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
16629
+ console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
16630
+ console.log(
16631
+ chalk8.gray(
16632
+ `- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
16633
+ )
16634
+ );
16551
16635
  console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
16552
16636
  if (tasksUpdated) {
16553
16637
  console.log();
@@ -16583,6 +16667,146 @@ function taskRunCommand(program2) {
16583
16667
  }
16584
16668
  });
16585
16669
  }
16670
+ function parseTaskLine2(line) {
16671
+ const match = line.match(
16672
+ /^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\[[^\]]+\](?:\[[^\]]+\])*\s+(T-[A-Za-z0-9-]+)\s+(.+?)\s*$/
16673
+ );
16674
+ if (!match) return null;
16675
+ return {
16676
+ index: -1,
16677
+ raw: line,
16678
+ status: match[1],
16679
+ taskId: match[2],
16680
+ title: match[3]
16681
+ };
16682
+ }
16683
+ function setTaskStatus2(line, nextStatus) {
16684
+ return line.raw.replace(
16685
+ /^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]/,
16686
+ `- [${nextStatus}]`
16687
+ );
16688
+ }
16689
+ async function resolveTaskCompleteContext(featureName, options) {
16690
+ const config = await getConfig(process.cwd());
16691
+ if (!config) {
16692
+ throw createCliError(
16693
+ "CONFIG_NOT_FOUND",
16694
+ "No lee-spec-kit config found in this workspace."
16695
+ );
16696
+ }
16697
+ const ctx = await createCliContext({ cwd: process.cwd() });
16698
+ const state = await resolveContextSelection(ctx, featureName, {
16699
+ component: resolveComponentOption(options.component)
16700
+ });
16701
+ if (state.status !== "single_matched" || !state.matchedFeature) {
16702
+ throw createCliError(
16703
+ "CONTEXT_SELECTION_REQUIRED",
16704
+ "task-complete requires a single matched feature. Pass <feature-name> explicitly."
16705
+ );
16706
+ }
16707
+ return {
16708
+ config,
16709
+ feature: state.matchedFeature
16710
+ };
16711
+ }
16712
+ async function runTaskComplete(featureName, options) {
16713
+ const { feature } = await resolveTaskCompleteContext(featureName, options);
16714
+ const tasksPath = path12.join(feature.path, "tasks.md");
16715
+ if (!await fs.pathExists(tasksPath)) {
16716
+ throw createCliError(
16717
+ "PRECONDITION_FAILED",
16718
+ `tasks.md not found for feature: ${feature.folderName}`
16719
+ );
16720
+ }
16721
+ const content = await fs.readFile(tasksPath, "utf-8");
16722
+ const lines = content.split("\n");
16723
+ const requestedTaskId = options.task?.trim() || feature.activeTask?.id || feature.nextTodoTask?.id;
16724
+ if (!requestedTaskId) {
16725
+ throw createCliError(
16726
+ "PRECONDITION_FAILED",
16727
+ "No active task is available for task-complete."
16728
+ );
16729
+ }
16730
+ const resolvedTask = lines.map((line, index) => {
16731
+ const parsed = parseTaskLine2(line);
16732
+ return parsed ? { ...parsed, index } : null;
16733
+ }).find((entry) => entry?.taskId === requestedTaskId);
16734
+ if (!resolvedTask) {
16735
+ throw createCliError(
16736
+ "INVALID_ARGUMENT",
16737
+ `Task "${requestedTaskId}" was not found in tasks.md.`
16738
+ );
16739
+ }
16740
+ if (resolvedTask.status === "DONE") {
16741
+ throw createCliError(
16742
+ "PRECONDITION_FAILED",
16743
+ `Task "${requestedTaskId}" is already DONE.`
16744
+ );
16745
+ }
16746
+ if (resolvedTask.status !== "DOING" && resolvedTask.status !== "REVIEW") {
16747
+ throw createCliError(
16748
+ "PRECONDITION_FAILED",
16749
+ `Task "${requestedTaskId}" must be DOING/REVIEW before marking it DONE.`
16750
+ );
16751
+ }
16752
+ lines[resolvedTask.index] = setTaskStatus2(resolvedTask, "DONE");
16753
+ await fs.writeFile(tasksPath, lines.join("\n"), "utf-8");
16754
+ const payload = {
16755
+ status: "ok",
16756
+ reasonCode: "TASK_COMPLETED",
16757
+ feature: feature.folderName,
16758
+ taskId: resolvedTask.taskId,
16759
+ title: resolvedTask.title,
16760
+ previousStatus: resolvedTask.status,
16761
+ nextStatus: "DONE",
16762
+ substateId: "task_complete",
16763
+ owner: "main",
16764
+ nextMainState: "task_finalize",
16765
+ tasksUpdated: true,
16766
+ tasksPath,
16767
+ recordedAt: getLocalDateString()
16768
+ };
16769
+ if (options.json) {
16770
+ console.log(JSON.stringify(payload, null, 2));
16771
+ return;
16772
+ }
16773
+ console.log(
16774
+ chalk8.green(
16775
+ `Marked task ${resolvedTask.taskId} as DONE for ${feature.folderName}.`
16776
+ )
16777
+ );
16778
+ console.log(chalk8.gray(`- tasks.md updated: ${tasksPath}`));
16779
+ console.log(chalk8.gray(`- status: ${resolvedTask.status} -> DONE`));
16780
+ console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
16781
+ }
16782
+ function taskCompleteCommand(program2) {
16783
+ program2.command("task-complete [feature-name]").description("Mark the active DOING/REVIEW task as DONE").option("--component <component>", "Component name for multi projects").option("--task <task-id>", "Explicit task id to mark DONE").option("--json", "Output JSON").action(
16784
+ async (featureName, options) => {
16785
+ try {
16786
+ await runTaskComplete(featureName, options);
16787
+ } catch (error) {
16788
+ const config = await getConfig(process.cwd());
16789
+ const lang = config?.lang ?? DEFAULT_LANG;
16790
+ const cliError = toCliError(error);
16791
+ const suggestions = getCliErrorSuggestions(cliError.code, lang);
16792
+ if (options.json) {
16793
+ console.log(
16794
+ JSON.stringify({
16795
+ status: "error",
16796
+ reasonCode: cliError.code,
16797
+ error: cliError.message,
16798
+ suggestions
16799
+ })
16800
+ );
16801
+ } else {
16802
+ console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
16803
+ printCliErrorSuggestions(suggestions, lang);
16804
+ }
16805
+ process.exitCode = 1;
16806
+ }
16807
+ }
16808
+ );
16809
+ }
16586
16810
  function isBannerDisabled() {
16587
16811
  const v = (process.env.LEE_SPEC_KIT_NO_BANNER || "").trim();
16588
16812
  return v === "1";
@@ -16766,6 +16990,7 @@ onboardCommand(program);
16766
16990
  prePrReviewCommand(program);
16767
16991
  codeReviewRunCommand(program);
16768
16992
  taskRunCommand(program);
16993
+ taskCompleteCommand(program);
16769
16994
  requirementsCommand(program);
16770
16995
  await program.parseAsync();
16771
16996
  //# sourceMappingURL=index.js.map