lee-spec-kit 0.6.12 → 0.6.14

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.
Files changed (32) hide show
  1. package/README.en.md +9 -6
  2. package/README.md +8 -5
  3. package/dist/index.js +709 -51
  4. package/package.json +1 -1
  5. package/templates/en/common/agents/agents.md +5 -3
  6. package/templates/en/common/agents/issue-template.md +1 -0
  7. package/templates/en/common/agents/pr-template.md +1 -0
  8. package/templates/en/common/agents/skills/create-feature.md +1 -0
  9. package/templates/en/common/agents/skills/create-issue.md +17 -10
  10. package/templates/en/common/agents/skills/create-pr.md +17 -9
  11. package/templates/en/common/agents/skills/execute-task.md +23 -11
  12. package/templates/en/common/features/README.md +17 -1
  13. package/templates/en/common/features/feature-base/decisions.md +18 -0
  14. package/templates/en/common/features/feature-base/issue.md +34 -0
  15. package/templates/en/common/features/feature-base/plan.md +1 -1
  16. package/templates/en/common/features/feature-base/pr.md +35 -0
  17. package/templates/en/common/features/feature-base/spec.md +1 -1
  18. package/templates/en/common/features/feature-base/tasks.md +8 -3
  19. package/templates/ko/common/agents/agents.md +5 -3
  20. package/templates/ko/common/agents/issue-template.md +1 -0
  21. package/templates/ko/common/agents/pr-template.md +1 -0
  22. package/templates/ko/common/agents/skills/create-feature.md +1 -0
  23. package/templates/ko/common/agents/skills/create-issue.md +17 -10
  24. package/templates/ko/common/agents/skills/create-pr.md +17 -9
  25. package/templates/ko/common/agents/skills/execute-task.md +14 -2
  26. package/templates/ko/common/features/README.md +17 -1
  27. package/templates/ko/common/features/feature-base/decisions.md +18 -0
  28. package/templates/ko/common/features/feature-base/issue.md +34 -0
  29. package/templates/ko/common/features/feature-base/plan.md +1 -1
  30. package/templates/ko/common/features/feature-base/pr.md +35 -0
  31. package/templates/ko/common/features/feature-base/spec.md +1 -1
  32. package/templates/ko/common/features/feature-base/tasks.md +8 -3
package/dist/index.js CHANGED
@@ -117,8 +117,8 @@ var I18N = {
117
117
  "doctor.issue.specStatusUnset": "spec.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)",
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
- "doctor.issue.tasksDocStatusUnset": "tasks.md\uC758 \uBB38\uC11C \uC0C1\uD0DC(Doc Status)\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (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**: Review | Approved`\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
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.",
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.",
@@ -134,7 +134,15 @@ var I18N = {
134
134
  "context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uC815\uCC45\uC740 \uC138\uC158 \uC2DC\uC791(\uB610\uB294 context \uC555\uCD95/\uB9AC\uC14B \uC9C1\uD6C4)\uC5D0 1\uD68C \uD655\uC778\uD558\uACE0, \uC774\uD6C4\uC5D0\uB294 \uC815\uCC45/\uC124\uC815 \uBCC0\uACBD \uB610\uB294 \uC0AC\uC6A9\uC790 \uC0C8\uB85C\uACE0\uCE68 \uC694\uCCAD \uC2DC\uC5D0\uB9CC \uC7AC\uD655\uC778\uD558\uC138\uC694. (git push/merge/merge commit \uD3EC\uD568) [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` (\uC608: `A`, `A OK`) \uC751\uB2F5\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589 (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
135
135
  "context.actionOptionHint": "\uC2B9\uC778 \uC751\uB2F5 \uD615\uC2DD: \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 (\uC608: `A`, `A OK`, `A \uC9C4\uD589\uD574`)",
136
136
  "context.actionExplainHint": "\uC2B9\uC778 \uC694\uCCAD \uC804, \uAC01 \uB77C\uBCA8\uC774 \uBB34\uC5C7\uC744 \uC2E4\uD589/\uBCC0\uACBD\uD558\uB294\uC9C0 \uD55C \uC904 \uC694\uC57D\uACFC \uD568\uAED8 \uC124\uBA85\uD558\uC138\uC694.",
137
- "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB9C8\uC9C0\uB9C9 \uC751\uB2F5\uC740 `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` \uD615\uC2DD\uC73C\uB85C \uBC1B\uC73C\uC138\uC694. (\uC608: {example})",
137
+ "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example})",
138
+ "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
139
+ "context.suggestionCommandHint": "\uB77C\uBCA8 \uCC38\uACE0 \uBA85\uB839: {command}",
140
+ "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 `<\uB77C\uBCA8>` \uB610\uB294 `<\uB77C\uBCA8> OK` \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example})",
141
+ "context.suggestion.createFeature": "\uC0C8 Feature\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4",
142
+ "context.suggestion.showDone": "\uC644\uB8CC\uB41C Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
143
+ "context.suggestion.showAll": "\uC804\uCCB4 Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
144
+ "context.suggestion.selectFeature": "\uC9C4\uD589\uD560 Feature\uB97C \uC120\uD0DD\uD574 \uC0C1\uC138 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uC5FD\uB2C8\uB2E4",
145
+ "context.suggestion.showOpen": "\uC9C4\uD589 \uC911 Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
138
146
  "context.finalLabelCommandHint": "\uB77C\uBCA8\uC744 \uBC1B\uC73C\uBA74 \uC2B9\uC778 \uC120\uD0DD \uC2E4\uD589: {command}",
139
147
  "context.finalTicketCommandHint": "\uBA85\uB839 \uC2E4\uD589\uC740 \uC2B9\uC778 \uACB0\uACFC\uC758 \uD2F0\uCF13\uC73C\uB85C \uC2E4\uD589: {command}",
140
148
  "context.readBuiltinDocFirst": "\uC774\uBC88 \uC138\uC158\uC5D0 \uC544\uC9C1 \uC77D\uC9C0 \uC54A\uC558\uAC70\uB098 \uBCC0\uACBD \uAC00\uB2A5\uC131\uC774 \uC788\uC744 \uB54C\uB9CC \uD544\uC694\uD55C \uB0B4\uC7A5 \uBB38\uC11C\uB97C \uD655\uC778\uD558\uC138\uC694.",
@@ -146,6 +154,10 @@ var I18N = {
146
154
  "context.list.recordPrLink": "PR \uB9C1\uD06C \uAE30\uB85D",
147
155
  "context.list.addPrePrReviewField": "Pre-PR Review \uD544\uB4DC \uCD94\uAC00",
148
156
  "context.list.completePrePrReview": "Pre-PR \uB9AC\uBDF0 \uC644\uB8CC \uCC98\uB9AC",
157
+ "context.list.addPrePrFindings": "Pre-PR Findings \uD544\uB4DC/\uAC12 \uBCF4\uC644",
158
+ "context.list.addPrePrEvidence": "Pre-PR Evidence \uADFC\uAC70 \uCD94\uAC00",
159
+ "context.list.resolvePrePrMajorFindings": "Pre-PR \uC8FC\uC694 Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
160
+ "context.list.resolvePrePrMinorFindings": "Pre-PR minor Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
149
161
  "context.list.setPrStatus": "PR \uC0C1\uD0DC \uC124\uC815",
150
162
  "context.list.prStatusToApproved": "PR \uBA38\uC9C0 \uD544\uC694 (\uD604\uC7AC PR \uC0C1\uD0DC: {status} \u2192 Approved)",
151
163
  "context.list.approveSpec": "spec \uC2B9\uC778 \uD544\uC694",
@@ -408,10 +420,14 @@ var I18N = {
408
420
  tasksApproval: "tasks.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC9C4\uD589 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC73C\uC138\uC694. (\uC2B9\uC778 \uD6C4 \uBB38\uC11C \uC0C1\uD0DC\uB97C Approved\uB85C \uBCC0\uACBD)",
409
421
  docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
410
422
  issueCreateAndWrite: "\uC774\uC288 \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694.",
423
+ issuePrepareFromDoc: "`issue.md`\uB97C \uAE30\uC900\uC73C\uB85C \uC774\uC288 \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC544 \uC0C1\uD0DC\uB97C `Ready`\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
424
+ issueCreateFromDoc: "`issue.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 GitHub Issue\uB97C \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C \uC774\uC288 \uBC88\uD638\uB97C `issue.md`\uC640 `spec.md/tasks.md`\uC5D0 \uBC18\uC601\uD558\uC138\uC694.",
411
425
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
412
426
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
413
427
  projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uBC88 \uD0DC\uC2A4\uD06C\uC5D0\uC11C \uC218\uC815\uD55C \uD30C\uC77C\uB9CC \uC120\uD0DD\uD574 git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
414
428
  projectCommitUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uBC88 \uD0DC\uC2A4\uD06C\uC5D0\uC11C \uC218\uC815\uD55C \uD30C\uC77C\uB9CC \uC120\uD0DD\uD574 git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "feat({folderName}): {commitTopic}")',
429
+ 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)',
430
+ 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)',
415
431
  standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
416
432
  createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
417
433
  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.',
@@ -427,12 +443,25 @@ var I18N = {
427
443
  taskCommitGateReasonMismatchLastDone: "\uCD5C\uADFC tasks.md \uCEE4\uBC0B\uC774 \uC9C1\uC804 \uC644\uB8CC \uD0DC\uC2A4\uD06C\uC640 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
428
444
  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)",
429
445
  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)",
430
- prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9). \uC2A4\uD0AC\uC744 \uC4F8 \uC218 \uC5C6\uC73C\uBA74 `{fallback}` \uC815\uCC45\uC73C\uB85C \uC9C4\uD589\uD558\uACE0 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. Findings \uC815\uCC45: {findingsPolicy}",
446
+ prePrReviewFindingsMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0 Findings` \uD544\uB4DC\uAC00 \uC5C6\uAC70\uB098 \uAC12 \uD615\uC2DD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
447
+ prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 placeholder\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uADFC\uAC70(\uBB38\uC11C \uACBD\uB85C/\uB9C1\uD06C/\uB85C\uADF8)\uB97C \uCC44\uC6B0\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
448
+ prePrReviewMajorBlocked: "Pre-PR \uC8FC\uC694 Findings\uAC00 {count}\uAC74\uC73C\uB85C \uAE30\uB85D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `blockOnFindings=true` \uC815\uCC45\uC5D0\uC11C\uB294 \uC8FC\uC694 \uC774\uC288 \uD574\uACB0/\uD569\uC758 \uC804 PR \uC0DD\uC131\uC73C\uB85C \uC9C4\uD589\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
449
+ prePrReviewMinorBlocked: "Pre-PR minor Findings\uAC00 {count}\uAC74\uC73C\uB85C \uAE30\uB85D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `minorPolicy=block` \uC815\uCC45\uC5D0\uC11C\uB294 minor \uC774\uC288 \uC815\uB9AC/\uD569\uC758 \uC804 PR \uC0DD\uC131\uC73C\uB85C \uC9C4\uD589\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
450
+ prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9). \uC2A4\uD0AC\uC744 \uC4F8 \uC218 \uC5C6\uC73C\uBA74 `{fallback}` \uC815\uCC45\uC73C\uB85C \uC9C4\uD589\uD558\uACE0 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. Major \uC815\uCC45: {findingsPolicy}. Minor \uC815\uCC45: {minorFindingsPolicy}",
431
451
  prePrReviewFindingsBlock: "\uC911\uC694 \uC774\uC288\uB294 \uC218\uC815/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
432
452
  prePrReviewFindingsWarn: "\uB9AC\uC2A4\uD06C\uB97C \uACF5\uC720\uD558\uBA74 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
453
+ prePrReviewMinorFindingsBlock: "minor \uC774\uC288\uB3C4 \uC815\uB9AC/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
454
+ prePrReviewMinorFindingsWarn: "minor \uC774\uC288\uB294 \uAE30\uB85D/\uACF5\uC720 \uD6C4 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
433
455
  prCreate: "PR \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBCC0\uACBD \uC0AC\uD56D/\uD14C\uC2A4\uD2B8 \uC139\uC158\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 PR\uC744 \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 tasks.md\uC5D0 PR \uB9C1\uD06C\uB97C \uAE30\uB85D\uD558\uC138\uC694.",
456
+ prCreatePrepareFromDoc: "`pr.md`\uB97C \uAE30\uC900\uC73C\uB85C PR \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC544 \uC0C1\uD0DC\uB97C `Ready`\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
457
+ prCreateExecuteFromDoc: "`pr.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C/PR \uC0C1\uD0DC\uB97C `pr.md`\uC640 `tasks.md`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.",
458
+ prCreatePrepare: "PR \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBCC0\uACBD \uC0AC\uD56D/\uD14C\uC2A4\uD2B8 \uC139\uC158\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, PR \uC0DD\uC131 \uC804 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK)\uC744 \uBC1B\uC73C\uC138\uC694.",
459
+ prCreateExecute: "\uD655\uC815\uB41C PR \uBCF8\uBB38\uC73C\uB85C PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C\uB97C tasks.md\uC758 PR \uD544\uB4DC\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.",
460
+ 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.",
434
461
  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.)",
435
- prResolveReview: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uB294 \uB3D9\uC548 PR \uC0C1\uD0DC\uB294 Review\uB85C \uC720\uC9C0\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.)",
462
+ prResolveReview: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uB294 \uB3D9\uC548 PR \uC0C1\uD0DC\uB294 Review\uB85C \uC720\uC9C0\uD558\uC138\uC694. \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD0DC\uC2A4\uD06C\uBA85\uC774 \uC544\uB2C8\uB77C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694. \uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uBA74 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uC131\uACF5 \uC2DC PR \uC0C1\uD0DC\uAC00 Approved\uB85C \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.)",
463
+ prReviewResolve: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uB294 \uB3D9\uC548 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC720\uC9C0\uD558\uC138\uC694. \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uD0DC\uC2A4\uD06C\uBA85\uC774 \uC544\uB2C8\uB77C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694.",
464
+ 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.)",
436
465
  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.",
437
466
  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.",
438
467
  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."
@@ -443,9 +472,11 @@ var I18N = {
443
472
  docsPathIgnored: "\uD604\uC7AC Feature \uBB38\uC11C \uACBD\uB85C\uAC00 git ignore \uB300\uC0C1\uC785\uB2C8\uB2E4: {path} (docs \uCEE4\uBC0B \uAC10\uC9C0\uAC00 \uC81C\uD55C\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.)",
444
473
  docsUncommittedChanges: "\uBB38\uC11C \uBCC0\uACBD\uC0AC\uD56D\uC774 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uCD94\uAC00 \uBB38\uC11C \uCEE4\uBC0B \uD544\uC694) \uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uADDC\uCE59\uC740 git-workflow \uAC00\uC774\uB4DC\uB97C \uAE30\uC900\uC73C\uB85C \uD655\uC778\uD558\uC138\uC694.",
445
474
  projectUncommittedChanges: "\uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uBCC0\uACBD\uC0AC\uD56D\uC774 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. (\uCD94\uAC00 \uCF54\uB4DC \uCEE4\uBC0B \uD544\uC694)",
446
- legacyTasksDocStatusField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. `\uBB38\uC11C \uC0C1\uD0DC` \uD544\uB4DC(Review/Approved)\uB97C \uCD94\uAC00\uD574 \uD0DC\uC2A4\uD06C \uC2B9\uC778 \uB2E8\uACC4\uB97C \uD65C\uC131\uD654\uD558\uC138\uC694.",
475
+ legacyTasksDocStatusField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. `\uBB38\uC11C \uC0C1\uD0DC` \uD544\uB4DC(Draft/Review/Approved)\uB97C \uCD94\uAC00\uD574 \uD0DC\uC2A4\uD06C \uC2B9\uC778 \uB2E8\uACC4\uB97C \uD65C\uC131\uD654\uD558\uC138\uC694.",
447
476
  legacyTasksPrFields: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR` \uBC0F `PR \uC0C1\uD0DC` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
448
477
  legacyTasksPrePrReviewField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`)",
478
+ legacyTasksPrePrFindingsField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Findings` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0 Findings**: major=0, minor=0`)",
479
+ legacyTasksPrePrEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
449
480
  workflowSpecNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC spec.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (spec.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
450
481
  workflowPlanNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC plan.md \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (plan.md\uC758 \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
451
482
  workflowIssueMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC \uC774\uC288 \uBC88\uD638\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uC138\uC694.)",
@@ -454,7 +485,11 @@ var I18N = {
454
485
  workflowPrStatusMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (PR \uC0DD\uC131/\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C\uB294 PR \uC0C1\uD0DC\uB97C Review\uB85C \uC124\uC815\uD558\uC138\uC694.)",
455
486
  workflowPrStatusNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uC0C1\uD0DC\uAC00 Approved\uAC00 \uC544\uB2D9\uB2C8\uB2E4. (PR \uC0DD\uC131/\uB9AC\uBDF0 \uB2E8\uACC4\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0, merge \uC131\uACF5 \uC2DC\uC5D0\uB9CC Approved\uB85C \uB3D9\uAE30\uD654\uD558\uC138\uC694.)",
456
487
  workflowPrePrReviewMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. (tasks.md\uC5D0 `- **PR \uC804 \uB9AC\uBDF0**: Pending | Done`\uC744 \uCD94\uAC00\uD558\uC138\uC694.)",
457
- workflowPrePrReviewNotDone: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0`\uAC00 Done\uC774 \uC544\uB2D9\uB2C8\uB2E4. (\uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0 \uD6C4 Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)"
488
+ workflowPrePrReviewNotDone: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0`\uAC00 Done\uC774 \uC544\uB2D9\uB2C8\uB2E4. (\uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0 \uD6C4 Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.)",
489
+ workflowPrePrFindingsMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Findings`\uAC00 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`major=0, minor=0` \uD615\uC2DD)",
490
+ workflowPrePrEvidenceMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (\uB9AC\uBDF0 \uADFC\uAC70\uB97C \uAE30\uB85D\uD558\uC138\uC694.)",
491
+ workflowPrePrFindingsBlocked: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC Pre-PR \uC8FC\uC694 Findings\uAC00 {count}\uAC74 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4. (`blockOnFindings=true` \uC815\uCC45)",
492
+ workflowPrePrMinorFindingsBlocked: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC Pre-PR minor Findings\uAC00 {count}\uAC74 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4. (`minorPolicy=block` \uC815\uCC45)"
458
493
  }
459
494
  },
460
495
  en: {
@@ -513,8 +548,8 @@ var I18N = {
513
548
  "doctor.issue.specStatusUnset": "spec.md Status is not set. (May still be a template)",
514
549
  "doctor.issue.planStatusUnset": "plan.md Status is not set. (May still be a template)",
515
550
  "doctor.issue.tasksEmpty": "tasks.md has no tasks.",
516
- "doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Review or Approved.)",
517
- "doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: Review | Approved`.",
551
+ "doctor.issue.tasksDocStatusUnset": "tasks.md Doc Status is not set. (Set it to Draft, Review, or Approved.)",
552
+ "doctor.issue.tasksDocStatusMissing": "tasks.md is missing the Doc Status field. Add `- **Doc Status**: Draft | Review | Approved`.",
518
553
  "doctor.issue.duplicateFeatureId": "Duplicate Feature ID detected: {id} ({count})",
519
554
  "doctor.issue.missingFeatureId": "Feature folder name is not in F001-... format. (Cannot extract ID)",
520
555
  "context.noActiveFeatures": "\u26A0\uFE0F No active features found.",
@@ -530,7 +565,15 @@ var I18N = {
530
565
  "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for `<label>` or `<label> OK` (e.g. `A`, `A OK`) before proceeding (config: approval can override)",
531
566
  "context.actionOptionHint": "Approval reply format: include a label token (e.g. `A`, `A OK`, `A proceed`)",
532
567
  "context.actionExplainHint": "Before requesting approval, explain what each label will run/change with a one-line summary.",
533
- "context.finalLabelPrompt": "Available labels now: {labels}. End with a label request in `<label>` or `<label> OK` format. (e.g. {example})",
568
+ "context.finalLabelPrompt": "Available labels now: {labels}. Please reply in `<label>` or `<label> OK` format. (e.g. {example})",
569
+ "context.suggestionHeader": "Suggested Next Options",
570
+ "context.suggestionCommandHint": "Reference command: {command}",
571
+ "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply in `<label>` or `<label> OK` format. (e.g. {example})",
572
+ "context.suggestion.createFeature": "Create a new feature",
573
+ "context.suggestion.showDone": "Show completed features",
574
+ "context.suggestion.showAll": "Show all features",
575
+ "context.suggestion.selectFeature": "Select a feature and open detailed context",
576
+ "context.suggestion.showOpen": "Show open features",
534
577
  "context.finalLabelCommandHint": "When a label is provided, run approval selection: {command}",
535
578
  "context.finalTicketCommandHint": "Execute commands using the ticket from approval result: {command}",
536
579
  "context.readBuiltinDocFirst": "Read required built-in docs only if not read in this session yet or likely changed.",
@@ -542,6 +585,10 @@ var I18N = {
542
585
  "context.list.recordPrLink": "Record PR link",
543
586
  "context.list.addPrePrReviewField": "Add Pre-PR Review field",
544
587
  "context.list.completePrePrReview": "Complete Pre-PR review",
588
+ "context.list.addPrePrFindings": "Add/fill Pre-PR Findings",
589
+ "context.list.addPrePrEvidence": "Add Pre-PR Evidence",
590
+ "context.list.resolvePrePrMajorFindings": "Resolve major pre-PR findings ({count})",
591
+ "context.list.resolvePrePrMinorFindings": "Resolve minor pre-PR findings ({count})",
545
592
  "context.list.setPrStatus": "Set PR Status",
546
593
  "context.list.prStatusToApproved": "PR merge required (PR Status: {status} \u2192 Approved)",
547
594
  "context.list.approveSpec": "Approve spec",
@@ -804,10 +851,14 @@ var I18N = {
804
851
  tasksApproval: "Share tasks.md with the user and get progress approval (`A` or `A OK` format). (Then set Doc Status to Approved)",
805
852
  docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
806
853
  issueCreateAndWrite: "Generate the issue body template, refine goals/completion criteria, get explicit user OK, create the issue, then update issue number in spec.md/tasks.md and prepare a docs commit.",
854
+ issuePrepareFromDoc: "Use `issue.md` to refine issue title/body/labels draft, get explicit user OK, then set status to `Ready`.",
855
+ issueCreateFromDoc: "When `issue.md` status is `Ready`, create the GitHub Issue and sync the created issue number into `issue.md` and `spec.md/tasks.md`.",
807
856
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
808
857
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} docs update"',
809
858
  projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files changed in this task with git add [files], then run again." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
810
859
  projectCommitUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files changed in this task with git add [files], then run again." && exit 1 || git commit -m "feat({folderName}): {commitTopic}")',
860
+ 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).',
861
+ 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).',
811
862
  standaloneNeedsProjectRoot: "Standalone mode requires projectRoot. (npx lee-spec-kit config --project-root ...)",
812
863
  createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
813
864
  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.',
@@ -823,12 +874,25 @@ var I18N = {
823
874
  taskCommitGateReasonMismatchLastDone: "The latest tasks.md commit does not match the last completed task",
824
875
  prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
825
876
  prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
826
- prePrReviewRun: "Run a pre-PR code review before creating the PR. Preferred skills: {skills} (if a better installed skill fits this change, propose it first). If no skill can run, use `{fallback}` and set `Pre-PR Review` to Done in tasks.md. Findings policy: {findingsPolicy}",
877
+ prePrReviewFindingsMissing: "tasks.md is missing `Pre-PR Findings` or uses an invalid format. Record it as `- **Pre-PR Findings**: major=0, minor=0`. (CHECK required)",
878
+ prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty or placeholder. Add concrete review evidence (doc path/link/log). (CHECK required)",
879
+ prePrReviewMajorBlocked: "Pre-PR major findings are recorded ({count}). With `blockOnFindings=true`, PR creation is blocked until major findings are resolved/aligned.",
880
+ prePrReviewMinorBlocked: "Pre-PR minor findings are recorded ({count}). With `minorPolicy=block`, PR creation is blocked until minor findings are resolved/aligned.",
881
+ prePrReviewRun: "Run a pre-PR code review before creating the PR. Preferred skills: {skills} (if a better installed skill fits this change, propose it first). If no skill can run, use `{fallback}` and set `Pre-PR Review` to Done in tasks.md. Major policy: {findingsPolicy}. Minor policy: {minorFindingsPolicy}",
827
882
  prePrReviewFindingsBlock: "major findings must be fixed/aligned before PR creation",
828
883
  prePrReviewFindingsWarn: "you may proceed after sharing the risks",
884
+ prePrReviewMinorFindingsBlock: "minor findings must also be fixed/aligned before PR creation",
885
+ prePrReviewMinorFindingsWarn: "you may proceed after documenting/sharing minor risks",
829
886
  prCreate: "Generate the PR body template, refine changes/tests sections, get explicit user OK, create the PR, then record the PR link in tasks.md.",
887
+ prCreatePrepareFromDoc: "Use `pr.md` to refine PR title/body/labels draft, get explicit user OK, then set status to `Ready`.",
888
+ prCreateExecuteFromDoc: "When `pr.md` status is `Ready`, create the PR and record the PR link/status in `pr.md` and `tasks.md`.",
889
+ prCreatePrepare: "Generate the PR body template, refine changes/tests sections, and get explicit user OK before PR creation.",
890
+ prCreateExecute: "Create the PR with the finalized body, then record the created PR link in tasks.md.",
891
+ 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.",
830
892
  prFillStatus: "Set PR Status in tasks.md to Review. (Keep Review during PR creation/review stages.)",
831
- prResolveReview: "Keep PR Status as Review while addressing comments. 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.)",
893
+ prResolveReview: "Keep PR Status as Review while addressing comments. For review-fix commits, use commit messages that summarize resolved review feedback (not task titles). Once ready to merge, get explicit user OK and run `npx lee-spec-kit github pr {featureRef} --merge --confirm OK`. (On success, PR Status is synced to Approved.)",
894
+ prReviewResolve: "Keep PR Status as Review while addressing comments. For review-fix commits, use commit messages that summarize resolved review feedback (not task titles).",
895
+ 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.)",
832
896
  prRequestReview: "Request review and set/keep PR Status as Review.",
833
897
  featureDone: "Workflow requirements and all tasks/completion criteria are satisfied. This feature is done.",
834
898
  fallbackRerunContext: "Cannot determine status. Check the docs and run context again."
@@ -839,9 +903,11 @@ var I18N = {
839
903
  docsPathIgnored: "Current feature docs path is ignored by git: {path} (docs commit detection may be limited).",
840
904
  docsUncommittedChanges: "Docs changes are not committed. (Additional docs commit needed.) Check commit message rules against the git-workflow guide.",
841
905
  projectUncommittedChanges: "Project code changes are not committed. (Additional code commit needed.)",
842
- legacyTasksDocStatusField: "Legacy tasks.md format detected. Add a `Doc Status` field (Review/Approved) to enable tasks approval.",
906
+ legacyTasksDocStatusField: "Legacy tasks.md format detected. Add a `Doc Status` field (Draft/Review/Approved) to enable tasks approval.",
843
907
  legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
844
908
  legacyTasksPrePrReviewField: "Legacy tasks.md format detected. Add `Pre-PR Review` before PR steps. (`- **Pre-PR Review**: Pending | Done`)",
909
+ legacyTasksPrePrFindingsField: "Legacy tasks.md format detected. Add `Pre-PR Findings` before PR steps. (`- **Pre-PR Findings**: major=0, minor=0`)",
910
+ legacyTasksPrePrEvidenceField: "Legacy tasks.md format detected. Add `Pre-PR Evidence` before PR steps.",
845
911
  workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
846
912
  workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
847
913
  workflowIssueMissing: "Implementation is done but Issue Number is missing. (Fill Issue Number in spec.md/tasks.md.)",
@@ -850,7 +916,11 @@ var I18N = {
850
916
  workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Review during PR creation/review stages.)",
851
917
  workflowPrStatusNotApproved: "Implementation is done but PR Status is not Approved. (Keep PR Status as Review before merge and sync to Approved only after successful merge.)",
852
918
  workflowPrePrReviewMissing: "Implementation is done but `Pre-PR Review` is missing. (Add `- **Pre-PR Review**: Pending | Done` in tasks.md.)",
853
- workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)"
919
+ workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)",
920
+ workflowPrePrFindingsMissing: "Implementation is done but `Pre-PR Findings` is missing or invalid. (Use `major=0, minor=0` format.)",
921
+ workflowPrePrEvidenceMissing: "Implementation is done but `Pre-PR Evidence` is empty. (Record review evidence.)",
922
+ workflowPrePrFindingsBlocked: "Implementation is done but major pre-PR findings remain ({count}) while `blockOnFindings=true`.",
923
+ workflowPrePrMinorFindingsBlocked: "Implementation is done but minor pre-PR findings remain ({count}) while `minorPolicy=block`."
854
924
  }
855
925
  }
856
926
  };
@@ -2011,7 +2081,10 @@ async function runInit(options) {
2011
2081
  mode: workflowMode,
2012
2082
  codeDirtyScope: "auto",
2013
2083
  taskCommitGate: "strict",
2014
- prePrReview: { skills: ["code-review-excellence"] }
2084
+ prePrReview: {
2085
+ skills: ["code-review-excellence"],
2086
+ minorPolicy: "warn"
2087
+ }
2015
2088
  },
2016
2089
  pr: {
2017
2090
  screenshots: { upload: false }
@@ -2287,10 +2360,20 @@ function sanitizeTasksForLocal(content, lang) {
2287
2360
  )) {
2288
2361
  continue;
2289
2362
  }
2363
+ if (/^\s*-\s*\*\*(Pre-PR Findings|Pre-PR Evidence|PR 전 리뷰 Findings|PR 전 리뷰 Evidence)\*\*\s*:/.test(
2364
+ line
2365
+ )) {
2366
+ continue;
2367
+ }
2290
2368
  if (/^\s*-\s*(Example|Values)\s*:/.test(line)) continue;
2291
2369
  if (/^\s*-\s*(예|값)\s*:/.test(line)) continue;
2292
2370
  if (/^\s*-\s*Mark\s+`?Done`?/i.test(line)) continue;
2293
2371
  if (/^\s*-\s*사전 코드리뷰 완료 후/.test(line)) continue;
2372
+ if (/^\s*-\s*Update with final findings counts from pre-PR review/i.test(line))
2373
+ continue;
2374
+ if (/^\s*-\s*Example:\s*review note link/i.test(line)) continue;
2375
+ if (/^\s*-\s*사전 리뷰 최종 결과/.test(line)) continue;
2376
+ if (/^\s*-\s*예:\s*리뷰 노트 링크/.test(line)) continue;
2294
2377
  filtered.push(line);
2295
2378
  }
2296
2379
  next = filtered.join("\n");
@@ -2308,6 +2391,8 @@ async function applyLocalWorkflowTemplateToFeatureDir(featureDir, lang) {
2308
2391
  path18.join(featureDir, "tasks.md"),
2309
2392
  (content) => sanitizeTasksForLocal(content, lang)
2310
2393
  );
2394
+ await fs15.remove(path18.join(featureDir, "issue.md"));
2395
+ await fs15.remove(path18.join(featureDir, "pr.md"));
2311
2396
  }
2312
2397
 
2313
2398
  // src/commands/feature.ts
@@ -2661,7 +2746,8 @@ function resolvePrePrReviewPolicy(workflow) {
2661
2746
  enabled: workflowPolicy.requirePr ? configuredEnabled : false,
2662
2747
  skills: configuredSkills.length > 0 ? configuredSkills : DEFAULT_PRE_PR_REVIEW_SKILLS,
2663
2748
  fallback: configured?.fallback === "builtin-checklist" ? configured.fallback : "builtin-checklist",
2664
- blockOnFindings: typeof configured?.blockOnFindings === "boolean" ? configured.blockOnFindings : true
2749
+ blockOnFindings: typeof configured?.blockOnFindings === "boolean" ? configured.blockOnFindings : true,
2750
+ minorPolicy: configured?.minorPolicy === "block" ? "block" : "warn"
2665
2751
  };
2666
2752
  }
2667
2753
 
@@ -2678,8 +2764,30 @@ function isImplementationDone(feature) {
2678
2764
  function isPrMetadataConfigured(feature) {
2679
2765
  return feature.docs.prFieldExists && feature.docs.prStatusFieldExists;
2680
2766
  }
2767
+ function isReviewIterationPhase(feature, workflowPolicy) {
2768
+ return workflowPolicy.requirePr && workflowPolicy.requireReview && isPrMetadataConfigured(feature) && !!feature.pr.link && feature.pr.status === "Review";
2769
+ }
2770
+ function isPrePrReviewSatisfied(feature, prePrReviewPolicy) {
2771
+ if (!prePrReviewPolicy.enabled) return true;
2772
+ if (!feature.docs.prePrReviewFieldExists || feature.prePrReview.status !== "Done") {
2773
+ return false;
2774
+ }
2775
+ if (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findings) {
2776
+ return false;
2777
+ }
2778
+ if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
2779
+ return false;
2780
+ }
2781
+ if (prePrReviewPolicy.blockOnFindings && feature.prePrReview.findings.major > 0) {
2782
+ return false;
2783
+ }
2784
+ if (prePrReviewPolicy.minorPolicy === "block" && feature.prePrReview.findings.minor > 0) {
2785
+ return false;
2786
+ }
2787
+ return true;
2788
+ }
2681
2789
  function isFeatureDone(feature, workflowPolicy, prePrReviewPolicy) {
2682
- return feature.specStatus === "Approved" && feature.planStatus === "Approved" && !feature.git.docsHasUncommittedChanges && !feature.git.projectHasUncommittedChanges && feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature) && (!workflowPolicy.requireIssue || !!feature.issueNumber) && (!workflowPolicy.requirePr || isPrMetadataConfigured(feature) && !!feature.pr.link) && (!workflowPolicy.requireReview || feature.pr.status === "Approved") && (!prePrReviewPolicy.enabled || feature.docs.prePrReviewFieldExists && feature.prePrReview.status === "Done");
2790
+ return feature.specStatus === "Approved" && feature.planStatus === "Approved" && !feature.git.docsHasUncommittedChanges && !feature.git.projectHasUncommittedChanges && feature.docs.tasksExists && feature.tasks.total > 0 && feature.tasks.total === feature.tasks.done && isCompletionChecklistDone(feature) && isTasksDocApproved(feature) && (!workflowPolicy.requireIssue || !!feature.issueNumber) && (!workflowPolicy.requirePr || isPrMetadataConfigured(feature) && !!feature.pr.link) && (!workflowPolicy.requireReview || feature.pr.status === "Approved") && isPrePrReviewSatisfied(feature, prePrReviewPolicy);
2683
2791
  }
2684
2792
  function formatSkillList(skills) {
2685
2793
  return skills.join(", ");
@@ -2687,6 +2795,9 @@ function formatSkillList(skills) {
2687
2795
  function getFindingsPolicyText(lang, blockOnFindings) {
2688
2796
  return blockOnFindings ? tr(lang, "messages", "prePrReviewFindingsBlock") : tr(lang, "messages", "prePrReviewFindingsWarn");
2689
2797
  }
2798
+ function getMinorFindingsPolicyText(lang, minorPolicy) {
2799
+ return minorPolicy === "block" ? tr(lang, "messages", "prePrReviewMinorFindingsBlock") : tr(lang, "messages", "prePrReviewMinorFindingsWarn");
2800
+ }
2690
2801
  function normalizeCommitTopicText(value) {
2691
2802
  return value.replace(/\s+/g, " ").trim();
2692
2803
  }
@@ -2995,12 +3106,36 @@ function getStepDefinitions(lang, workflow) {
2995
3106
  current: {
2996
3107
  when: (f) => workflowPolicy.requireIssue && f.docs.tasksExists && f.tasks.total > 0 && f.specStatus === "Approved" && f.planStatus === "Approved" && isTasksDocApproved(f) && !f.issueNumber,
2997
3108
  actions: (f) => {
3109
+ if (!f.docs.issueDocExists) {
3110
+ return [
3111
+ {
3112
+ type: "instruction",
3113
+ category: "issue_create",
3114
+ requiresUserCheck: true,
3115
+ message: tr(lang, "messages", "issueCreateAndWrite", {
3116
+ featureRef: f.id || f.folderName
3117
+ })
3118
+ }
3119
+ ];
3120
+ }
3121
+ if (f.docs.issueDocStatus === "Ready") {
3122
+ return [
3123
+ {
3124
+ type: "instruction",
3125
+ category: "issue_create",
3126
+ requiresUserCheck: true,
3127
+ message: tr(lang, "messages", "issueCreateFromDoc", {
3128
+ featureRef: f.id || f.folderName
3129
+ })
3130
+ }
3131
+ ];
3132
+ }
2998
3133
  return [
2999
3134
  {
3000
3135
  type: "instruction",
3001
3136
  category: "issue_create",
3002
3137
  requiresUserCheck: true,
3003
- message: tr(lang, "messages", "issueCreateAndWrite", {
3138
+ message: tr(lang, "messages", "issuePrepareFromDoc", {
3004
3139
  featureRef: f.id || f.folderName
3005
3140
  })
3006
3141
  }
@@ -3075,6 +3210,30 @@ function getStepDefinitions(lang, workflow) {
3075
3210
  ];
3076
3211
  }
3077
3212
  if (f.git.projectHasUncommittedChanges) {
3213
+ if (isReviewIterationPhase(f, workflowPolicy)) {
3214
+ if (!f.git.projectGitCwd) {
3215
+ return [
3216
+ {
3217
+ type: "instruction",
3218
+ category: "review_fix_commit",
3219
+ message: tr(lang, "messages", "standaloneNeedsProjectRoot")
3220
+ }
3221
+ ];
3222
+ }
3223
+ return [
3224
+ {
3225
+ type: "instruction",
3226
+ category: "review_fix_commit",
3227
+ requiresUserCheck: true,
3228
+ message: f.issueNumber ? tr(lang, "messages", "reviewFixCommitIssueGuidance", {
3229
+ projectGitCwd: f.git.projectGitCwd,
3230
+ issueNumber: f.issueNumber
3231
+ }) : tr(lang, "messages", "reviewFixCommitGuidance", {
3232
+ projectGitCwd: f.git.projectGitCwd
3233
+ })
3234
+ }
3235
+ ];
3236
+ }
3078
3237
  if (!f.git.projectGitCwd) {
3079
3238
  return [
3080
3239
  {
@@ -3281,6 +3440,30 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3281
3440
  }
3282
3441
  ];
3283
3442
  }
3443
+ if (isReviewIterationPhase(f, workflowPolicy)) {
3444
+ if (!f.git.projectGitCwd) {
3445
+ return [
3446
+ {
3447
+ type: "instruction",
3448
+ category: "review_fix_commit",
3449
+ message: tr(lang, "messages", "standaloneNeedsProjectRoot")
3450
+ }
3451
+ ];
3452
+ }
3453
+ return [
3454
+ {
3455
+ type: "instruction",
3456
+ category: "review_fix_commit",
3457
+ requiresUserCheck: true,
3458
+ message: f.issueNumber ? tr(lang, "messages", "reviewFixCommitIssueGuidance", {
3459
+ projectGitCwd: f.git.projectGitCwd,
3460
+ issueNumber: f.issueNumber
3461
+ }) : tr(lang, "messages", "reviewFixCommitGuidance", {
3462
+ projectGitCwd: f.git.projectGitCwd
3463
+ })
3464
+ }
3465
+ ];
3466
+ }
3284
3467
  if (!f.git.projectGitCwd) {
3285
3468
  return [
3286
3469
  {
@@ -3316,10 +3499,10 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3316
3499
  step: 12,
3317
3500
  name: tr(lang, "steps", "prePrReview"),
3318
3501
  checklist: {
3319
- done: (f) => !prePrReviewPolicy.enabled || f.docs.prePrReviewFieldExists && f.prePrReview.status === "Done"
3502
+ done: (f) => isPrePrReviewSatisfied(f, prePrReviewPolicy)
3320
3503
  },
3321
3504
  current: {
3322
- when: (f) => prePrReviewPolicy.enabled && workflowPolicy.requirePr && f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f) && !f.git.docsHasUncommittedChanges && !f.git.projectHasUncommittedChanges && (!isPrMetadataConfigured(f) || !f.pr.link) && (!f.docs.prePrReviewFieldExists || f.prePrReview.status !== "Done"),
3505
+ when: (f) => prePrReviewPolicy.enabled && workflowPolicy.requirePr && f.docs.tasksExists && f.tasks.total > 0 && f.tasks.total === f.tasks.done && isCompletionChecklistDone(f) && !f.git.docsHasUncommittedChanges && !f.git.projectHasUncommittedChanges && (!isPrMetadataConfigured(f) || !f.pr.link) && !isPrePrReviewSatisfied(f, prePrReviewPolicy),
3323
3506
  actions: (f) => {
3324
3507
  if (!prePrReviewPolicy.enabled) return [];
3325
3508
  if (!f.docs.prePrReviewFieldExists) {
@@ -3332,6 +3515,92 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3332
3515
  }
3333
3516
  ];
3334
3517
  }
3518
+ if (f.prePrReview.status !== "Done") {
3519
+ if (!prePrReviewPolicy.skills.length) {
3520
+ return [
3521
+ {
3522
+ type: "instruction",
3523
+ category: "pre_pr_review",
3524
+ requiresUserCheck: true,
3525
+ message: tr(lang, "messages", "prePrReviewRun", {
3526
+ skills: "code-review-excellence",
3527
+ fallback: prePrReviewPolicy.fallback,
3528
+ findingsPolicy: getFindingsPolicyText(
3529
+ lang,
3530
+ prePrReviewPolicy.blockOnFindings
3531
+ ),
3532
+ minorFindingsPolicy: getMinorFindingsPolicyText(
3533
+ lang,
3534
+ prePrReviewPolicy.minorPolicy
3535
+ )
3536
+ })
3537
+ }
3538
+ ];
3539
+ }
3540
+ return [
3541
+ {
3542
+ type: "instruction",
3543
+ category: "pre_pr_review",
3544
+ requiresUserCheck: true,
3545
+ message: tr(lang, "messages", "prePrReviewRun", {
3546
+ skills: formatSkillList(prePrReviewPolicy.skills),
3547
+ fallback: prePrReviewPolicy.fallback,
3548
+ findingsPolicy: getFindingsPolicyText(
3549
+ lang,
3550
+ prePrReviewPolicy.blockOnFindings
3551
+ ),
3552
+ minorFindingsPolicy: getMinorFindingsPolicyText(
3553
+ lang,
3554
+ prePrReviewPolicy.minorPolicy
3555
+ )
3556
+ })
3557
+ }
3558
+ ];
3559
+ }
3560
+ if (!f.docs.prePrFindingsFieldExists || !f.prePrReview.findings) {
3561
+ return [
3562
+ {
3563
+ type: "instruction",
3564
+ category: "pre_pr_review",
3565
+ requiresUserCheck: true,
3566
+ message: tr(lang, "messages", "prePrReviewFindingsMissing")
3567
+ }
3568
+ ];
3569
+ }
3570
+ if (!f.docs.prePrEvidenceFieldExists || !f.prePrReview.evidenceProvided) {
3571
+ return [
3572
+ {
3573
+ type: "instruction",
3574
+ category: "pre_pr_review",
3575
+ requiresUserCheck: true,
3576
+ message: tr(lang, "messages", "prePrReviewEvidenceMissing")
3577
+ }
3578
+ ];
3579
+ }
3580
+ if (prePrReviewPolicy.blockOnFindings && f.prePrReview.findings.major > 0) {
3581
+ return [
3582
+ {
3583
+ type: "instruction",
3584
+ category: "pre_pr_review",
3585
+ requiresUserCheck: true,
3586
+ message: tr(lang, "messages", "prePrReviewMajorBlocked", {
3587
+ count: f.prePrReview.findings.major
3588
+ })
3589
+ }
3590
+ ];
3591
+ }
3592
+ if (prePrReviewPolicy.minorPolicy === "block" && f.prePrReview.findings.minor > 0) {
3593
+ return [
3594
+ {
3595
+ type: "instruction",
3596
+ category: "pre_pr_review",
3597
+ requiresUserCheck: true,
3598
+ message: tr(lang, "messages", "prePrReviewMinorBlocked", {
3599
+ count: f.prePrReview.findings.minor
3600
+ })
3601
+ }
3602
+ ];
3603
+ }
3335
3604
  if (!prePrReviewPolicy.skills.length) {
3336
3605
  return [
3337
3606
  {
@@ -3344,6 +3613,10 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3344
3613
  findingsPolicy: getFindingsPolicyText(
3345
3614
  lang,
3346
3615
  prePrReviewPolicy.blockOnFindings
3616
+ ),
3617
+ minorFindingsPolicy: getMinorFindingsPolicyText(
3618
+ lang,
3619
+ prePrReviewPolicy.minorPolicy
3347
3620
  )
3348
3621
  })
3349
3622
  }
@@ -3360,6 +3633,10 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3360
3633
  findingsPolicy: getFindingsPolicyText(
3361
3634
  lang,
3362
3635
  prePrReviewPolicy.blockOnFindings
3636
+ ),
3637
+ minorFindingsPolicy: getMinorFindingsPolicyText(
3638
+ lang,
3639
+ prePrReviewPolicy.minorPolicy
3363
3640
  )
3364
3641
  })
3365
3642
  }
@@ -3386,12 +3663,36 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3386
3663
  }
3387
3664
  ];
3388
3665
  }
3666
+ if (!f.docs.prDocExists) {
3667
+ return [
3668
+ {
3669
+ type: "instruction",
3670
+ category: "pr_create",
3671
+ requiresUserCheck: true,
3672
+ message: tr(lang, "messages", "prCreateRequiredSequence", {
3673
+ featureRef: f.id || f.folderName
3674
+ })
3675
+ }
3676
+ ];
3677
+ }
3678
+ if (f.docs.prDocStatus === "Ready") {
3679
+ return [
3680
+ {
3681
+ type: "instruction",
3682
+ category: "pr_create",
3683
+ requiresUserCheck: true,
3684
+ message: tr(lang, "messages", "prCreateExecuteFromDoc", {
3685
+ featureRef: f.id || f.folderName
3686
+ })
3687
+ }
3688
+ ];
3689
+ }
3389
3690
  return [
3390
3691
  {
3391
3692
  type: "instruction",
3392
3693
  category: "pr_create",
3393
3694
  requiresUserCheck: true,
3394
- message: tr(lang, "messages", "prCreate", {
3695
+ message: tr(lang, "messages", "prCreatePrepareFromDoc", {
3395
3696
  featureRef: f.id || f.folderName
3396
3697
  })
3397
3698
  }
@@ -3424,7 +3725,13 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3424
3725
  type: "instruction",
3425
3726
  category: "code_review",
3426
3727
  requiresUserCheck: true,
3427
- message: tr(lang, "messages", "prResolveReview", {
3728
+ message: tr(lang, "messages", "prReviewResolve")
3729
+ },
3730
+ {
3731
+ type: "instruction",
3732
+ category: "code_review",
3733
+ requiresUserCheck: true,
3734
+ message: tr(lang, "messages", "prReviewMerge", {
3428
3735
  featureRef: f.id || f.folderName
3429
3736
  })
3430
3737
  }
@@ -3726,10 +4033,33 @@ function parseDocStatus(value) {
3726
4033
  if (!value) return void 0;
3727
4034
  const trimmed = value.trim();
3728
4035
  if (trimmed.includes("|")) return void 0;
3729
- const match = trimmed.match(/\b(Draft|Review|Approved)\b/i);
4036
+ const match = trimmed.match(/\b(Draft|Review|In[ -_]?Review|Approved)\b/i);
4037
+ if (!match) return void 0;
4038
+ const normalized = match[1].toLowerCase().replace(/[\s_-]/g, "");
4039
+ if (normalized === "draft") return "Draft";
4040
+ if (normalized === "review" || normalized === "inreview") return "Review";
4041
+ return "Approved";
4042
+ }
4043
+ function parseWorkflowDocStatus(value) {
4044
+ if (!value) return void 0;
4045
+ const trimmed = value.trim();
4046
+ if (!trimmed || trimmed.includes("|")) return void 0;
4047
+ const match = trimmed.match(/\b(Draft|Ready|Opened|Open|Merged)\b/i);
3730
4048
  if (!match) return void 0;
3731
4049
  const normalized = match[1].toLowerCase();
3732
4050
  if (normalized === "draft") return "Draft";
4051
+ if (normalized === "ready" || normalized === "opened" || normalized === "open" || normalized === "merged") {
4052
+ return "Ready";
4053
+ }
4054
+ return void 0;
4055
+ }
4056
+ function parsePrReviewStatus(value) {
4057
+ if (!value) return void 0;
4058
+ const trimmed = value.trim();
4059
+ if (!trimmed || trimmed.includes("|")) return void 0;
4060
+ const match = trimmed.match(/\b(Review|Approved)\b/i);
4061
+ if (!match) return void 0;
4062
+ const normalized = match[1].toLowerCase();
3733
4063
  if (normalized === "review") return "Review";
3734
4064
  return "Approved";
3735
4065
  }
@@ -3737,10 +4067,31 @@ function parsePrePrReviewStatus(value) {
3737
4067
  if (!value) return void 0;
3738
4068
  const trimmed = value.trim();
3739
4069
  if (!trimmed || trimmed.includes("|")) return void 0;
3740
- if (/^done$/i.test(trimmed)) return "Done";
4070
+ if (/^(done|complete|completed)$/i.test(trimmed)) return "Done";
3741
4071
  if (/^pending$/i.test(trimmed)) return "Pending";
3742
4072
  return void 0;
3743
4073
  }
4074
+ function parsePrePrFindings(value) {
4075
+ if (!value) return void 0;
4076
+ const trimmed = value.trim();
4077
+ if (!trimmed || trimmed.includes("|")) return void 0;
4078
+ const majorMatch = trimmed.match(/\bmajor\s*[:=]\s*(\d+)\b/i);
4079
+ const minorMatch = trimmed.match(/\bminor\s*[:=]\s*(\d+)\b/i);
4080
+ if (!majorMatch || !minorMatch) return void 0;
4081
+ const major = Number(majorMatch[1]);
4082
+ const minor = Number(minorMatch[1]);
4083
+ if (!Number.isInteger(major) || !Number.isInteger(minor)) return void 0;
4084
+ if (major < 0 || minor < 0) return void 0;
4085
+ return { major, minor };
4086
+ }
4087
+ function isPlaceholderReviewEvidence(value) {
4088
+ if (!value) return true;
4089
+ const trimmed = value.trim();
4090
+ if (!trimmed) return true;
4091
+ return /^(?:-|#)?\s*(?:tbd|todo|n\/a|na|none|pending|미정|없음|-)\s*$/i.test(
4092
+ trimmed
4093
+ );
4094
+ }
3744
4095
  function parseIssueNumber(value) {
3745
4096
  if (!value) return void 0;
3746
4097
  const match = value.match(/#?(\d+)/);
@@ -3880,6 +4231,25 @@ function isCompletionChecklistDone2(feature) {
3880
4231
  function isPrMetadataConfigured2(feature) {
3881
4232
  return feature.docs.prFieldExists && feature.docs.prStatusFieldExists;
3882
4233
  }
4234
+ function isPrePrReviewSatisfied2(feature, policy) {
4235
+ if (!policy.enabled) return true;
4236
+ if (!feature.docs.prePrReviewFieldExists || feature.prePrReview.status !== "Done") {
4237
+ return false;
4238
+ }
4239
+ if (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findings) {
4240
+ return false;
4241
+ }
4242
+ if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
4243
+ return false;
4244
+ }
4245
+ if (policy.blockOnFindings && feature.prePrReview.findings.major > 0) {
4246
+ return false;
4247
+ }
4248
+ if (policy.minorPolicy === "block" && feature.prePrReview.findings.minor > 0) {
4249
+ return false;
4250
+ }
4251
+ return true;
4252
+ }
3883
4253
  async function parseFeature(featurePath, type, context, options) {
3884
4254
  const lang = options.lang;
3885
4255
  const workflowPolicy = resolveWorkflowPolicy(options.workflow);
@@ -3891,6 +4261,8 @@ async function parseFeature(featurePath, type, context, options) {
3891
4261
  const specPath = path18.join(featurePath, "spec.md");
3892
4262
  const planPath = path18.join(featurePath, "plan.md");
3893
4263
  const tasksPath = path18.join(featurePath, "tasks.md");
4264
+ const issueDocPath = path18.join(featurePath, "issue.md");
4265
+ const prDocPath = path18.join(featurePath, "pr.md");
3894
4266
  let specStatus;
3895
4267
  let issueNumber;
3896
4268
  const specExists = await fs15.pathExists(specPath);
@@ -3917,11 +4289,23 @@ async function parseFeature(featurePath, type, context, options) {
3917
4289
  let tasksDocStatusFieldExists = false;
3918
4290
  let completionChecklist;
3919
4291
  let prePrReviewStatus;
4292
+ let prePrFindings;
4293
+ let prePrEvidence;
4294
+ let prePrEvidenceProvided = false;
3920
4295
  let prLink;
3921
4296
  let prStatus;
3922
4297
  let prFieldExists = false;
3923
4298
  let prStatusFieldExists = false;
4299
+ let issueDocStatus;
4300
+ let issueDocStatusFieldExists = false;
4301
+ let issueDocIssueFieldExists = false;
4302
+ let prDocStatus;
4303
+ let prDocStatusFieldExists = false;
4304
+ let prDocPrFieldExists = false;
4305
+ let prDocReviewStatusFieldExists = false;
3924
4306
  let prePrReviewFieldExists = false;
4307
+ let prePrFindingsFieldExists = false;
4308
+ let prePrEvidenceFieldExists = false;
3925
4309
  if (tasksExists) {
3926
4310
  const content = await fs15.readFile(tasksPath, "utf-8");
3927
4311
  const {
@@ -3950,7 +4334,7 @@ async function parseFeature(featurePath, type, context, options) {
3950
4334
  prLink = parsePrLink(prValue);
3951
4335
  const prStatusValue = extractFirstSpecValue(content, ["PR \uC0C1\uD0DC", "PR Status"]);
3952
4336
  prStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
3953
- prStatus = parseDocStatus(prStatusValue);
4337
+ prStatus = parsePrReviewStatus(prStatusValue);
3954
4338
  const prePrReviewValue = extractFirstSpecValue(content, [
3955
4339
  "PR \uC804 \uB9AC\uBDF0",
3956
4340
  "Pre-PR Review"
@@ -3960,6 +4344,74 @@ async function parseFeature(featurePath, type, context, options) {
3960
4344
  "Pre-PR Review"
3961
4345
  ]);
3962
4346
  prePrReviewStatus = parsePrePrReviewStatus(prePrReviewValue);
4347
+ const prePrFindingsValue = extractFirstSpecValue(content, [
4348
+ "PR \uC804 \uB9AC\uBDF0 Findings",
4349
+ "Pre-PR Findings"
4350
+ ]);
4351
+ prePrFindingsFieldExists = hasAnySpecKey(content, [
4352
+ "PR \uC804 \uB9AC\uBDF0 Findings",
4353
+ "Pre-PR Findings"
4354
+ ]);
4355
+ prePrFindings = parsePrePrFindings(prePrFindingsValue);
4356
+ const prePrEvidenceValue = extractFirstSpecValue(content, [
4357
+ "PR \uC804 \uB9AC\uBDF0 Evidence",
4358
+ "Pre-PR Evidence"
4359
+ ]);
4360
+ prePrEvidenceFieldExists = hasAnySpecKey(content, [
4361
+ "PR \uC804 \uB9AC\uBDF0 Evidence",
4362
+ "Pre-PR Evidence"
4363
+ ]);
4364
+ prePrEvidence = prePrEvidenceValue?.trim();
4365
+ prePrEvidenceProvided = !isPlaceholderReviewEvidence(prePrEvidenceValue);
4366
+ }
4367
+ const issueDocExists = await fs15.pathExists(issueDocPath);
4368
+ if (issueDocExists) {
4369
+ const content = await fs15.readFile(issueDocPath, "utf-8");
4370
+ const issueDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4371
+ issueDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
4372
+ issueDocStatus = parseWorkflowDocStatus(issueDocStatusValue);
4373
+ const issueValue = extractFirstSpecValue(content, [
4374
+ "\uC774\uC288 \uBC88\uD638",
4375
+ "Issue Number",
4376
+ "Issue"
4377
+ ]);
4378
+ issueDocIssueFieldExists = hasAnySpecKey(content, [
4379
+ "\uC774\uC288 \uBC88\uD638",
4380
+ "Issue Number",
4381
+ "Issue"
4382
+ ]);
4383
+ const parsedIssueFromDoc = parseIssueNumber(issueValue);
4384
+ if (parsedIssueFromDoc) {
4385
+ issueNumber = parsedIssueFromDoc;
4386
+ }
4387
+ }
4388
+ const prDocExists = await fs15.pathExists(prDocPath);
4389
+ if (prDocExists) {
4390
+ const content = await fs15.readFile(prDocPath, "utf-8");
4391
+ const prDocStatusValue = extractFirstSpecValue(content, ["\uC0C1\uD0DC", "Status"]);
4392
+ prDocStatusFieldExists = hasAnySpecKey(content, ["\uC0C1\uD0DC", "Status"]);
4393
+ prDocStatus = parseWorkflowDocStatus(prDocStatusValue);
4394
+ const prValue = extractFirstSpecValue(content, ["PR", "Pull Request"]);
4395
+ prDocPrFieldExists = hasAnySpecKey(content, ["PR", "Pull Request"]);
4396
+ const parsedPrLink = parsePrLink(prValue);
4397
+ if (parsedPrLink) {
4398
+ prLink = parsedPrLink;
4399
+ }
4400
+ const prReviewStatusValue = extractFirstSpecValue(content, [
4401
+ "PR \uC0C1\uD0DC",
4402
+ "PR Status"
4403
+ ]);
4404
+ prDocReviewStatusFieldExists = hasAnySpecKey(content, ["PR \uC0C1\uD0DC", "PR Status"]);
4405
+ const parsedPrStatus = parsePrReviewStatus(prReviewStatusValue);
4406
+ if (parsedPrStatus) {
4407
+ prStatus = parsedPrStatus;
4408
+ }
4409
+ }
4410
+ if (prDocPrFieldExists) {
4411
+ prFieldExists = true;
4412
+ }
4413
+ if (prDocReviewStatusFieldExists) {
4414
+ prStatusFieldExists = true;
3963
4415
  }
3964
4416
  const warnings = [];
3965
4417
  if (context.projectBranchAvailable === false) {
@@ -4045,12 +4497,18 @@ async function parseFeature(featurePath, type, context, options) {
4045
4497
  })
4046
4498
  );
4047
4499
  }
4048
- if (tasksExists && workflowPolicy.requirePr && (!prFieldExists || !prStatusFieldExists)) {
4500
+ if (tasksExists && workflowPolicy.requirePr && !prDocExists && (!prFieldExists || !prStatusFieldExists)) {
4049
4501
  warnings.push(tr(lang, "warnings", "legacyTasksPrFields"));
4050
4502
  }
4051
4503
  if (tasksExists && prePrReviewPolicy.enabled && !prePrReviewFieldExists) {
4052
4504
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrReviewField"));
4053
4505
  }
4506
+ if (tasksExists && prePrReviewPolicy.enabled && !prePrFindingsFieldExists) {
4507
+ warnings.push(tr(lang, "warnings", "legacyTasksPrePrFindingsField"));
4508
+ }
4509
+ if (tasksExists && prePrReviewPolicy.enabled && !prePrEvidenceFieldExists) {
4510
+ warnings.push(tr(lang, "warnings", "legacyTasksPrePrEvidenceField"));
4511
+ }
4054
4512
  if (tasksExists && !tasksDocStatusFieldExists) {
4055
4513
  warnings.push(tr(lang, "warnings", "legacyTasksDocStatusField"));
4056
4514
  }
@@ -4062,7 +4520,21 @@ async function parseFeature(featurePath, type, context, options) {
4062
4520
  }
4063
4521
  const tasksDocApproved = !tasksDocStatusFieldExists || tasksDocStatus === "Approved";
4064
4522
  const implementationDone = tasksExists && tasksSummary.total > 0 && tasksSummary.total === tasksSummary.done && isCompletionChecklistDone2({ completionChecklist }) && tasksDocApproved;
4065
- const workflowDone = implementationDone && !docsHasUncommittedChanges && !projectHasUncommittedChanges && specStatus === "Approved" && planStatus === "Approved" && (!workflowPolicy.requireIssue || !!issueNumber) && (!workflowPolicy.requirePr || isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink) && (!workflowPolicy.requireReview || prStatus === "Approved") && (!prePrReviewPolicy.enabled || prePrReviewFieldExists && prePrReviewStatus === "Done");
4523
+ const workflowDone = implementationDone && !docsHasUncommittedChanges && !projectHasUncommittedChanges && specStatus === "Approved" && planStatus === "Approved" && (!workflowPolicy.requireIssue || !!issueNumber) && (!workflowPolicy.requirePr || isPrMetadataConfigured2({ docs: { prFieldExists, prStatusFieldExists } }) && !!prLink) && (!workflowPolicy.requireReview || prStatus === "Approved") && isPrePrReviewSatisfied2(
4524
+ {
4525
+ docs: {
4526
+ prePrReviewFieldExists,
4527
+ prePrFindingsFieldExists,
4528
+ prePrEvidenceFieldExists
4529
+ },
4530
+ prePrReview: {
4531
+ status: prePrReviewStatus,
4532
+ findings: prePrFindings,
4533
+ evidenceProvided: prePrEvidenceProvided
4534
+ }
4535
+ },
4536
+ prePrReviewPolicy
4537
+ );
4066
4538
  if (implementationDone && !workflowDone) {
4067
4539
  if (specStatus !== "Approved") {
4068
4540
  warnings.push(tr(lang, "warnings", "workflowSpecNotApproved"));
@@ -4090,6 +4562,22 @@ async function parseFeature(featurePath, type, context, options) {
4090
4562
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewMissing"));
4091
4563
  } else if (prePrReviewStatus !== "Done") {
4092
4564
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewNotDone"));
4565
+ } else if (!prePrFindingsFieldExists || !prePrFindings) {
4566
+ warnings.push(tr(lang, "warnings", "workflowPrePrFindingsMissing"));
4567
+ } else if (!prePrEvidenceFieldExists || !prePrEvidenceProvided) {
4568
+ warnings.push(tr(lang, "warnings", "workflowPrePrEvidenceMissing"));
4569
+ } else if (prePrReviewPolicy.blockOnFindings && prePrFindings.major > 0) {
4570
+ warnings.push(
4571
+ tr(lang, "warnings", "workflowPrePrFindingsBlocked", {
4572
+ count: prePrFindings.major
4573
+ })
4574
+ );
4575
+ } else if (prePrReviewPolicy.minorPolicy === "block" && prePrFindings.minor > 0) {
4576
+ warnings.push(
4577
+ tr(lang, "warnings", "workflowPrePrMinorFindingsBlocked", {
4578
+ count: prePrFindings.minor
4579
+ })
4580
+ );
4093
4581
  }
4094
4582
  }
4095
4583
  }
@@ -4113,7 +4601,10 @@ async function parseFeature(featurePath, type, context, options) {
4113
4601
  nextTodoTask,
4114
4602
  completionChecklist,
4115
4603
  prePrReview: {
4116
- status: prePrReviewStatus
4604
+ status: prePrReviewStatus,
4605
+ findings: prePrFindings,
4606
+ evidence: prePrEvidence,
4607
+ evidenceProvided: prePrEvidenceProvided
4117
4608
  },
4118
4609
  pr: { link: prLink, status: prStatus },
4119
4610
  git: {
@@ -4133,10 +4624,21 @@ async function parseFeature(featurePath, type, context, options) {
4133
4624
  specExists,
4134
4625
  planExists,
4135
4626
  tasksExists,
4627
+ issueDocExists,
4628
+ issueDocStatus,
4629
+ issueDocStatusFieldExists,
4630
+ issueDocIssueFieldExists,
4631
+ prDocExists,
4632
+ prDocStatus,
4633
+ prDocStatusFieldExists,
4634
+ prDocPrFieldExists,
4635
+ prDocReviewStatusFieldExists,
4136
4636
  tasksDocStatusFieldExists,
4137
4637
  prFieldExists,
4138
4638
  prStatusFieldExists,
4139
- prePrReviewFieldExists
4639
+ prePrReviewFieldExists,
4640
+ prePrFindingsFieldExists,
4641
+ prePrEvidenceFieldExists
4140
4642
  }
4141
4643
  };
4142
4644
  const { currentStep, actions, nextAction } = resolveFeatureProgress(
@@ -4683,6 +5185,7 @@ async function backfillMissingConfigDefaults(docsDir) {
4683
5185
  }
4684
5186
  setIfMissing(prePrReview, "fallback", "builtin-checklist", "workflow.prePrReview.fallback");
4685
5187
  setIfMissing(prePrReview, "blockOnFindings", true, "workflow.prePrReview.blockOnFindings");
5188
+ setIfMissing(prePrReview, "minorPolicy", "warn", "workflow.prePrReview.minorPolicy");
4686
5189
  if (!isPlainObject(raw.pr)) {
4687
5190
  raw.pr = {};
4688
5191
  changedPaths.push("pr");
@@ -4984,7 +5487,8 @@ var REMOTE_ACTION_CATEGORIES = /* @__PURE__ */ new Set([
4984
5487
  var LOCAL_ACTION_CATEGORIES = /* @__PURE__ */ new Set([
4985
5488
  "docs_commit",
4986
5489
  "branch_create",
4987
- "task_execute"
5490
+ "task_execute",
5491
+ "review_fix_commit"
4988
5492
  ]);
4989
5493
  var REMOTE_COMMAND_PATTERN = /\b(?:git\s+push|git\s+merge|gh\s+(?:issue|pr)\b)/i;
4990
5494
  function resolveComponentOption(options) {
@@ -5033,6 +5537,7 @@ function getActionSummary(action) {
5033
5537
  if (action.category === "pr_status_update") return "Update PR status";
5034
5538
  if (action.category === "code_review") return "Process code review feedback";
5035
5539
  if (action.category === "task_execute") return "Proceed with task execution";
5540
+ if (action.category === "review_fix_commit") return "Commit review feedback fixes";
5036
5541
  if (action.category === "feature_done") return "Feature is complete";
5037
5542
  if (action.category === "spec_approve") return "Request spec approval";
5038
5543
  if (action.category === "plan_approve") return "Request plan approval";
@@ -5246,14 +5751,14 @@ var BUILTIN_DOC_DEFINITIONS = [
5246
5751
  relativePath: (_, lang) => path18.join(lang, "common", "agents", "git-workflow.md")
5247
5752
  },
5248
5753
  {
5249
- id: "issue-template",
5250
- title: { ko: "Issue \uD15C\uD50C\uB9BF", en: "Issue Template" },
5251
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "issue-template.md")
5754
+ id: "issue-doc",
5755
+ title: { ko: "Issue \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "Issue Document Template" },
5756
+ relativePath: (_, lang) => path18.join(lang, "common", "features", "feature-base", "issue.md")
5252
5757
  },
5253
5758
  {
5254
- id: "pr-template",
5255
- title: { ko: "PR \uD15C\uD50C\uB9BF", en: "PR Template" },
5256
- relativePath: (_, lang) => path18.join(lang, "common", "agents", "pr-template.md")
5759
+ id: "pr-doc",
5760
+ title: { ko: "PR \uBB38\uC11C \uD15C\uD50C\uB9BF", en: "PR Document Template" },
5761
+ relativePath: (_, lang) => path18.join(lang, "common", "features", "feature-base", "pr.md")
5257
5762
  },
5258
5763
  {
5259
5764
  id: "create-feature",
@@ -5282,17 +5787,17 @@ var DOC_FOLLOWUPS = {
5282
5787
  "execute-task",
5283
5788
  "git-workflow",
5284
5789
  "create-issue",
5285
- "issue-template",
5790
+ "issue-doc",
5286
5791
  "create-pr",
5287
- "pr-template"
5792
+ "pr-doc"
5288
5793
  ],
5289
5794
  "git-workflow": [],
5290
- "issue-template": [],
5291
- "pr-template": [],
5795
+ "issue-doc": [],
5796
+ "pr-doc": [],
5292
5797
  "create-feature": ["execute-task"],
5293
5798
  "execute-task": ["git-workflow"],
5294
- "create-issue": ["issue-template"],
5295
- "create-pr": ["pr-template"]
5799
+ "create-issue": ["issue-doc"],
5800
+ "create-pr": ["pr-doc"]
5296
5801
  };
5297
5802
  var CATEGORY_DOC_MAP = {
5298
5803
  spec_write: ["agents"],
@@ -5302,11 +5807,12 @@ var CATEGORY_DOC_MAP = {
5302
5807
  tasks_write: ["agents", "execute-task"],
5303
5808
  tasks_approve: ["execute-task"],
5304
5809
  task_execute: ["execute-task", "git-workflow"],
5810
+ review_fix_commit: ["create-pr", "git-workflow"],
5305
5811
  docs_commit: ["git-workflow"],
5306
5812
  branch_create: ["git-workflow"],
5307
- issue_create: ["create-issue", "issue-template", "git-workflow"],
5813
+ issue_create: ["create-issue", "issue-doc", "git-workflow"],
5308
5814
  pre_pr_review: ["create-pr"],
5309
- pr_create: ["create-pr", "pr-template", "git-workflow"],
5815
+ pr_create: ["create-pr", "pr-doc", "git-workflow"],
5310
5816
  pr_status_update: ["create-pr"],
5311
5817
  code_review: ["create-pr"]
5312
5818
  };
@@ -5316,8 +5822,10 @@ function getBuiltinDocIds() {
5316
5822
  function normalizeBuiltinDocId(input) {
5317
5823
  const normalized = input.trim().toLowerCase().replace(/_/g, "-");
5318
5824
  if (normalized === "git-workflow") return "git-workflow";
5319
- if (normalized === "issue-template") return "issue-template";
5320
- if (normalized === "pr-template") return "pr-template";
5825
+ if (normalized === "issue-doc" || normalized === "issue-md") return "issue-doc";
5826
+ if (normalized === "pr-doc" || normalized === "pr-md") return "pr-doc";
5827
+ if (normalized === "issue-template") return "issue-doc";
5828
+ if (normalized === "pr-template") return "pr-doc";
5321
5829
  if (normalized === "create-feature") return "create-feature";
5322
5830
  if (normalized === "execute-task") return "execute-task";
5323
5831
  if (normalized === "create-issue") return "create-issue";
@@ -5601,6 +6109,10 @@ function listLabels(actionOptions) {
5601
6109
  if (actionOptions.length === 0) return "-";
5602
6110
  return actionOptions.map((o) => o.label).join(", ");
5603
6111
  }
6112
+ function listSuggestionLabels(suggestionOptions) {
6113
+ if (suggestionOptions.length === 0) return "-";
6114
+ return suggestionOptions.map((o) => o.label).join(", ");
6115
+ }
5604
6116
  function resolveFeatureRefForApproval(state, featureName) {
5605
6117
  const raw = featureName?.trim() || state.matchedFeature?.folderName || "<slug|F001|F001-slug>";
5606
6118
  return raw;
@@ -5622,6 +6134,103 @@ function buildFinalApprovalPrompt(lang, actionOptions) {
5622
6134
  example
5623
6135
  });
5624
6136
  }
6137
+ function buildSuggestionFinalPrompt(lang, suggestionOptions) {
6138
+ if (suggestionOptions.length === 0) return "";
6139
+ const labels = listSuggestionLabels(suggestionOptions);
6140
+ const example = suggestionOptions[0]?.label || "A";
6141
+ return tr(lang, "cli", "context.suggestionFinalPrompt", {
6142
+ labels,
6143
+ example
6144
+ });
6145
+ }
6146
+ function toSuggestionLabel(index) {
6147
+ let n = index + 1;
6148
+ let label = "";
6149
+ while (n > 0) {
6150
+ const rem = (n - 1) % 26;
6151
+ label = String.fromCharCode(65 + rem) + label;
6152
+ n = Math.floor((n - 1) / 26);
6153
+ }
6154
+ return label;
6155
+ }
6156
+ function buildSuggestionOptions(lang, state, projectType, selectedComponent) {
6157
+ const componentArg = selectedComponent ? ` --component ${selectedComponent}` : "";
6158
+ const createFeatureCommand = projectType === "multi" ? selectedComponent ? `npx lee-spec-kit feature <name> --component ${selectedComponent}` : "npx lee-spec-kit feature <name> --component <component>" : "npx lee-spec-kit feature <name>";
6159
+ const selectFeatureCommand = projectType === "multi" ? selectedComponent ? `npx lee-spec-kit context <slug|F001|F001-slug> --component ${selectedComponent}` : "npx lee-spec-kit context <slug|F001|F001-slug> --component <component>" : "npx lee-spec-kit context <slug|F001|F001-slug>";
6160
+ const showDoneCommand = `npx lee-spec-kit context --done${componentArg}`;
6161
+ const showAllCommand = `npx lee-spec-kit context --all${componentArg}`;
6162
+ const showOpenCommand = `npx lee-spec-kit context${componentArg}`;
6163
+ const rawSuggestions = [];
6164
+ switch (state.status) {
6165
+ case "no_features":
6166
+ rawSuggestions.push({
6167
+ summary: tr(lang, "cli", "context.suggestion.createFeature"),
6168
+ command: createFeatureCommand
6169
+ });
6170
+ break;
6171
+ case "no_open":
6172
+ rawSuggestions.push({
6173
+ summary: tr(lang, "cli", "context.suggestion.showDone"),
6174
+ command: showDoneCommand
6175
+ });
6176
+ rawSuggestions.push({
6177
+ summary: tr(lang, "cli", "context.suggestion.createFeature"),
6178
+ command: createFeatureCommand
6179
+ });
6180
+ rawSuggestions.push({
6181
+ summary: tr(lang, "cli", "context.suggestion.showAll"),
6182
+ command: showAllCommand
6183
+ });
6184
+ break;
6185
+ case "multiple_active":
6186
+ rawSuggestions.push({
6187
+ summary: tr(lang, "cli", "context.suggestion.selectFeature"),
6188
+ command: selectFeatureCommand
6189
+ });
6190
+ rawSuggestions.push({
6191
+ summary: tr(lang, "cli", "context.suggestion.showAll"),
6192
+ command: showAllCommand
6193
+ });
6194
+ break;
6195
+ case "no_match":
6196
+ rawSuggestions.push({
6197
+ summary: tr(lang, "cli", "context.suggestion.showOpen"),
6198
+ command: showOpenCommand
6199
+ });
6200
+ rawSuggestions.push({
6201
+ summary: tr(lang, "cli", "context.suggestion.showAll"),
6202
+ command: showAllCommand
6203
+ });
6204
+ break;
6205
+ }
6206
+ return rawSuggestions.map((item, index) => {
6207
+ const label = toSuggestionLabel(index);
6208
+ return {
6209
+ label,
6210
+ summary: item.summary,
6211
+ detail: `${item.summary}: ${item.command}`,
6212
+ command: item.command
6213
+ };
6214
+ });
6215
+ }
6216
+ function printSuggestionOptions(lang, suggestionOptions) {
6217
+ if (suggestionOptions.length === 0) return;
6218
+ const finalPrompt = buildSuggestionFinalPrompt(lang, suggestionOptions);
6219
+ console.log(chalk6.green(chalk6.bold(`\u{1F449} ${tr(lang, "cli", "context.suggestionHeader")}`)));
6220
+ suggestionOptions.forEach((option) => {
6221
+ console.log(` ${option.label}: ${option.summary}`);
6222
+ console.log(
6223
+ chalk6.gray(
6224
+ ` \u21B3 ${tr(lang, "cli", "context.suggestionCommandHint", {
6225
+ command: option.command
6226
+ })}`
6227
+ )
6228
+ );
6229
+ });
6230
+ if (finalPrompt) {
6231
+ console.log(chalk6.cyan(` \u21B3 ${finalPrompt}`));
6232
+ }
6233
+ }
5625
6234
  function formatActionSummary2(action) {
5626
6235
  if (action.type === "command") {
5627
6236
  return `(${action.scope}) ${action.cmd}`;
@@ -5724,6 +6333,22 @@ function getListLabel(f, stepsMap, lang, workflowPolicy, prePrReviewPolicy) {
5724
6333
  if (prePrReviewPolicy.enabled && f.prePrReview.status !== "Done") {
5725
6334
  return tr(lang, "cli", "context.list.completePrePrReview");
5726
6335
  }
6336
+ if (prePrReviewPolicy.enabled && (!f.docs.prePrFindingsFieldExists || !f.prePrReview.findings)) {
6337
+ return tr(lang, "cli", "context.list.addPrePrFindings");
6338
+ }
6339
+ if (prePrReviewPolicy.enabled && (!f.docs.prePrEvidenceFieldExists || !f.prePrReview.evidenceProvided)) {
6340
+ return tr(lang, "cli", "context.list.addPrePrEvidence");
6341
+ }
6342
+ if (prePrReviewPolicy.enabled && prePrReviewPolicy.blockOnFindings && (f.prePrReview.findings?.major || 0) > 0) {
6343
+ return tr(lang, "cli", "context.list.resolvePrePrMajorFindings", {
6344
+ count: f.prePrReview.findings?.major || 0
6345
+ });
6346
+ }
6347
+ if (prePrReviewPolicy.enabled && prePrReviewPolicy.minorPolicy === "block" && (f.prePrReview.findings?.minor || 0) > 0) {
6348
+ return tr(lang, "cli", "context.list.resolvePrePrMinorFindings", {
6349
+ count: f.prePrReview.findings?.minor || 0
6350
+ });
6351
+ }
5727
6352
  if (workflowPolicy.requirePr && !f.pr.link) {
5728
6353
  return tr(lang, "cli", "context.list.recordPrLink");
5729
6354
  }
@@ -5794,6 +6419,13 @@ async function runContext(featureName, options) {
5794
6419
  };
5795
6420
  const state = await resolveContextState(config, featureName, selectionOptions);
5796
6421
  const requiredDocs = buildRequiredDocHints(state.actionOptions);
6422
+ const suggestionOptions = buildSuggestionOptions(
6423
+ lang,
6424
+ state,
6425
+ config.projectType,
6426
+ selectedComponent
6427
+ );
6428
+ const suggestionFinalPrompt = buildSuggestionFinalPrompt(lang, suggestionOptions);
5797
6429
  if (options.approve || options.execute) {
5798
6430
  await runApprovedOption(
5799
6431
  state,
@@ -5836,6 +6468,7 @@ async function runContext(featureName, options) {
5836
6468
  readyToCloseCandidates: state.selectionMode === "open" ? state.readyToCloseFeatures : [],
5837
6469
  actions: state.actions,
5838
6470
  actionOptions: state.actionOptions,
6471
+ suggestionOptions,
5839
6472
  primaryActionLabel: primaryAction?.label ?? null,
5840
6473
  primaryActionType: primaryAction?.action.type ?? null,
5841
6474
  primaryActionCategory: primaryAction?.action.category ?? null,
@@ -5857,14 +6490,14 @@ async function runContext(featureName, options) {
5857
6490
  "actionOptions[].detail",
5858
6491
  "actionOptions[].approvalPrompt"
5859
6492
  ],
5860
- recommendation: "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user. Keep `requiredDocs`, `checkPolicy`, and raw execution commands as internal guidance. For commit actions, include scope (`docs`/`project`) and commit message in the visible prompt. User replies should include the label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`). For command execution, require one-time `approvalTicket` only when the selected action has `requiresUserCheck=true`.",
6493
+ recommendation: "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user. Keep `requiredDocs`, `checkPolicy`, and raw execution commands as internal guidance. For commit actions, include scope (`docs`/`project`) and commit message in the visible prompt. User replies should include the label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`). For command execution, prefer one-shot `npx lee-spec-kit flow <featureRef> --approve <LABEL> --execute` to avoid session mismatch after context compression/reset. Use ticket-based `context --execute --ticket` only when explicitly needed.",
5861
6494
  oneApprovalPerAction: true,
5862
6495
  requireFreshContext: true,
5863
6496
  contextVersion: state.contextVersion,
5864
6497
  config: config.approval ?? { mode: "builtin" }
5865
6498
  },
5866
6499
  approvalRequest: {
5867
- guidance: "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`. Do not expose `requiredDocs`, `checkPolicy`, or raw `cmd` unless explicitly requested.",
6500
+ guidance: "User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`. Do not expose `requiredDocs`, `checkPolicy`, or raw `cmd` unless explicitly requested. For approved command actions, prefer one-shot `flow --approve <LABEL> --execute`.",
5868
6501
  finalPrompt: finalApprovalPrompt,
5869
6502
  userFacingLines: [
5870
6503
  ...state.actionOptions.map((o) => o.approvalPrompt),
@@ -5889,6 +6522,21 @@ async function runContext(featureName, options) {
5889
6522
  operationType: o.action.operationType
5890
6523
  }))
5891
6524
  },
6525
+ suggestionRequest: {
6526
+ guidance: "When `actionOptions` is empty, present `suggestionOptions` as user-facing next choices. Keep command strings internal unless the user asks for executable commands.",
6527
+ finalPrompt: suggestionFinalPrompt,
6528
+ userFacingLines: [
6529
+ ...suggestionOptions.map((o) => `${o.label}: ${o.summary}`),
6530
+ suggestionFinalPrompt
6531
+ ].filter((line) => line.length > 0),
6532
+ labels: suggestionOptions.map((o) => o.label),
6533
+ options: suggestionOptions.map((o) => ({
6534
+ label: o.label,
6535
+ summary: o.summary,
6536
+ detail: o.detail,
6537
+ command: o.command
6538
+ }))
6539
+ },
5892
6540
  prPolicy: {
5893
6541
  screenshots: {
5894
6542
  upload: config.pr?.screenshots?.upload ?? false
@@ -5953,6 +6601,8 @@ async function runContext(featureName, options) {
5953
6601
  )
5954
6602
  );
5955
6603
  console.log();
6604
+ printSuggestionOptions(lang, suggestionOptions);
6605
+ console.log();
5956
6606
  return;
5957
6607
  }
5958
6608
  if (state.warnings.length > 0) {
@@ -5975,6 +6625,8 @@ async function runContext(featureName, options) {
5975
6625
  );
5976
6626
  }
5977
6627
  console.log();
6628
+ printSuggestionOptions(lang, suggestionOptions);
6629
+ console.log();
5978
6630
  return;
5979
6631
  }
5980
6632
  if (state.targetFeatures.length > 1) {
@@ -6065,6 +6717,8 @@ async function runContext(featureName, options) {
6065
6717
  );
6066
6718
  }
6067
6719
  console.log();
6720
+ printSuggestionOptions(lang, suggestionOptions);
6721
+ console.log();
6068
6722
  return;
6069
6723
  }
6070
6724
  const f = state.targetFeatures[0];
@@ -7407,10 +8061,10 @@ function getGithubDraftContractView(kind, lang) {
7407
8061
  };
7408
8062
  }
7409
8063
  function getGithubDraftContractForBuiltinDoc(docId, lang) {
7410
- if (docId === "create-issue" || docId === "issue-template") {
8064
+ if (docId === "create-issue" || docId === "issue-doc") {
7411
8065
  return getGithubDraftContractView("issue", lang);
7412
8066
  }
7413
- if (docId === "create-pr" || docId === "pr-template") {
8067
+ if (docId === "create-pr" || docId === "pr-doc") {
7414
8068
  return getGithubDraftContractView("pr", lang);
7415
8069
  }
7416
8070
  return null;
@@ -9313,7 +9967,11 @@ function shouldShowBanner() {
9313
9967
  const argv = process.argv.slice(2);
9314
9968
  const disabledByEnv = (process.env.LEE_SPEC_KIT_NO_BANNER || "").trim() === "1";
9315
9969
  const disabledByFlag = argv.includes("--no-banner");
9316
- return !disabledByEnv && !disabledByFlag;
9970
+ const hasJsonFlag = argv.includes("--json");
9971
+ const isNonTtyOutput = !process.stdout.isTTY;
9972
+ if (disabledByEnv || disabledByFlag) return false;
9973
+ if (hasJsonFlag || isNonTtyOutput) return false;
9974
+ return true;
9317
9975
  }
9318
9976
  function shouldCheckForUpdates() {
9319
9977
  const argv = process.argv.slice(2);