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.
- package/README.en.md +9 -6
- package/README.md +8 -5
- package/dist/index.js +709 -51
- package/package.json +1 -1
- package/templates/en/common/agents/agents.md +5 -3
- package/templates/en/common/agents/issue-template.md +1 -0
- package/templates/en/common/agents/pr-template.md +1 -0
- package/templates/en/common/agents/skills/create-feature.md +1 -0
- package/templates/en/common/agents/skills/create-issue.md +17 -10
- package/templates/en/common/agents/skills/create-pr.md +17 -9
- package/templates/en/common/agents/skills/execute-task.md +23 -11
- package/templates/en/common/features/README.md +17 -1
- package/templates/en/common/features/feature-base/decisions.md +18 -0
- package/templates/en/common/features/feature-base/issue.md +34 -0
- package/templates/en/common/features/feature-base/plan.md +1 -1
- package/templates/en/common/features/feature-base/pr.md +35 -0
- package/templates/en/common/features/feature-base/spec.md +1 -1
- package/templates/en/common/features/feature-base/tasks.md +8 -3
- package/templates/ko/common/agents/agents.md +5 -3
- package/templates/ko/common/agents/issue-template.md +1 -0
- package/templates/ko/common/agents/pr-template.md +1 -0
- package/templates/ko/common/agents/skills/create-feature.md +1 -0
- package/templates/ko/common/agents/skills/create-issue.md +17 -10
- package/templates/ko/common/agents/skills/create-pr.md +17 -9
- package/templates/ko/common/agents/skills/execute-task.md +14 -2
- package/templates/ko/common/features/README.md +17 -1
- package/templates/ko/common/features/feature-base/decisions.md +18 -0
- package/templates/ko/common/features/feature-base/issue.md +34 -0
- package/templates/ko/common/features/feature-base/plan.md +1 -1
- package/templates/ko/common/features/feature-base/pr.md +35 -0
- package/templates/ko/common/features/feature-base/spec.md +1 -1
- 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}. \
|
|
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
|
-
|
|
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}.
|
|
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
|
-
|
|
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: {
|
|
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") && (
|
|
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", "
|
|
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) =>
|
|
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) && (
|
|
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", "
|
|
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", "
|
|
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 =
|
|
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") && (
|
|
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-
|
|
5250
|
-
title: { ko: "Issue \uD15C\uD50C\uB9BF", en: "Issue Template" },
|
|
5251
|
-
relativePath: (_, lang) => path18.join(lang, "common", "
|
|
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-
|
|
5255
|
-
title: { ko: "PR \uD15C\uD50C\uB9BF", en: "PR Template" },
|
|
5256
|
-
relativePath: (_, lang) => path18.join(lang, "common", "
|
|
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-
|
|
5790
|
+
"issue-doc",
|
|
5286
5791
|
"create-pr",
|
|
5287
|
-
"pr-
|
|
5792
|
+
"pr-doc"
|
|
5288
5793
|
],
|
|
5289
5794
|
"git-workflow": [],
|
|
5290
|
-
"issue-
|
|
5291
|
-
"pr-
|
|
5795
|
+
"issue-doc": [],
|
|
5796
|
+
"pr-doc": [],
|
|
5292
5797
|
"create-feature": ["execute-task"],
|
|
5293
5798
|
"execute-task": ["git-workflow"],
|
|
5294
|
-
"create-issue": ["issue-
|
|
5295
|
-
"create-pr": ["pr-
|
|
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-
|
|
5813
|
+
issue_create: ["create-issue", "issue-doc", "git-workflow"],
|
|
5308
5814
|
pre_pr_review: ["create-pr"],
|
|
5309
|
-
pr_create: ["create-pr", "pr-
|
|
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-
|
|
5320
|
-
if (normalized === "pr-
|
|
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,
|
|
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-
|
|
8064
|
+
if (docId === "create-issue" || docId === "issue-doc") {
|
|
7411
8065
|
return getGithubDraftContractView("issue", lang);
|
|
7412
8066
|
}
|
|
7413
|
-
if (docId === "create-pr" || docId === "pr-
|
|
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
|
-
|
|
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);
|