lee-spec-kit 0.6.21 → 0.6.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -155,33 +155,40 @@ var ko = {
155
155
  "context.tipShowAll": "\uC804\uCCB4 \uBCF4\uAE30",
156
156
  "context.tipShowDone": "\uC644\uB8CC\uB9CC \uBCF4\uAE30",
157
157
  "context.checkRequired": "[\uD655\uC778 \uD544\uC694] ",
158
- "context.checkPolicyHint": "\u2139\uFE0F \uC0AC\uC6A9\uC790 \uD655\uC778 \uC815\uCC45\uC740 \uC138\uC158 \uC2DC\uC791(\uB610\uB294 context \uC555\uCD95/\uB9AC\uC14B \uC9C1\uD6C4)\uC5D0 1\uD68C \uD655\uC778\uD558\uACE0, \uC774\uD6C4\uC5D0\uB294 \uC815\uCC45/\uC124\uC815 \uBCC0\uACBD \uB610\uB294 \uC0AC\uC6A9\uC790 \uC0C8\uB85C\uACE0\uCE68 \uC694\uCCAD \uC2DC\uC5D0\uB9CC \uC7AC\uD655\uC778\uD558\uC138\uC694. (git push/merge/merge commit \uD3EC\uD568) [\uD655\uC778 \uD544\uC694]\uAC00 \uC788\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uB77C\uBCA8 \uD1A0\uD070\uC774 \uD3EC\uD568\uB41C \uC751\uB2F5(\uC608: `A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589 (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
159
- "context.actionOptionHint": "\uC2B9\uC778 \uC751\uB2F5 \uD615\uC2DD: \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 (\uC608: `A`, `A OK`, `A \uC9C4\uD589\uD574`)",
158
+ "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 \uB77C\uBCA8 \uD1A0\uD070 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC5D0 \uB9DE\uB294 \uC751\uB2F5\uC744 \uBC1B\uC740 \uB4A4 \uC9C4\uD589\uD558\uC138\uC694. (config: approval\uB85C \uC870\uC815 \uAC00\uB2A5)",
159
+ "context.actionOptionHint": "\uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59: `A`, `A OK`, `A \uC9C4\uD589\uD574` \uC911 \uD558\uB098\uC758 \uD615\uC2DD\uC73C\uB85C \uC751\uB2F5",
160
160
  "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.",
161
- "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`)",
162
- "context.finalLabelPromptWithRequest": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`) \uC694\uCCAD \uD14D\uC2A4\uD2B8\uAC00 \uD544\uC694\uD55C \uB77C\uBCA8\uC740 \uB2E4\uC74C \uD615\uC2DD\uC73C\uB85C \uC785\uB825\uD558\uC138\uC694: {requestExamples}",
161
+ "context.finalLabelPrompt": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`)",
162
+ "context.finalLabelPromptWithRequest": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \uC751\uB2F5 \uADDC\uCE59(`A`, `A OK`, `A \uC9C4\uD589\uD574`)\uC73C\uB85C \uC751\uB2F5\uD558\uC138\uC694. (\uC608: `{example}`) \uC694\uCCAD \uD14D\uC2A4\uD2B8\uAC00 \uD544\uC694\uD55C \uB77C\uBCA8\uC740 \uB2E4\uC74C \uD615\uC2DD\uC73C\uB85C \uC785\uB825\uD558\uC138\uC694: {requestExamples}",
163
163
  "context.suggestionHeader": "\uCD94\uCC9C \uB2E4\uC74C \uC120\uD0DD\uC9C0",
164
164
  "context.suggestionCommandHint": "\uB77C\uBCA8 \uCC38\uACE0 \uBA85\uB839: {command}",
165
165
  "context.suggestionFinalPrompt": "\uD604\uC7AC \uCD94\uCC9C \uB77C\uBCA8: {labels}. \uC751\uB2F5\uC740 \uB77C\uBCA8 \uD1A0\uD070 \uD3EC\uD568 \uD615\uC2DD\uC73C\uB85C \uD574\uC8FC\uC138\uC694. (\uC608: {example}, `A \uC9C4\uD589\uD574`)",
166
+ "context.commandDetail.branchCreateWithWorktree": "({scope}) worktree {worktree}\uB97C \uC0AC\uC6A9\uD574 \uBE0C\uB79C\uCE58 {branch}\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
167
+ "context.commandDetail.branchCreateWithBranch": "({scope}) \uBE0C\uB79C\uCE58 {branch}\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
168
+ "context.commandDetail.branchCreateGeneric": "({scope}) feature \uBE0C\uB79C\uCE58\uC6A9 worktree\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694",
169
+ "context.commandDetail.codeReviewMergeAfterOk": "({scope}) \uBA85\uC2DC\uC801 \uC2B9\uC778 \uD6C4 PR\uC744 \uBA38\uC9C0\uD558\uC138\uC694",
170
+ "context.commandDetail.codeReviewPushFix": "({scope}) \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 push\uD558\uC138\uC694",
171
+ "context.actionSummary.runDocsCommand": "\uBB38\uC11C \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
172
+ "context.actionSummary.runProjectCommand": "\uD504\uB85C\uC81D\uD2B8 \uC791\uC5C5 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694",
166
173
  "context.actionDetail.featureFolder": "Feature \uD3F4\uB354\uC640 \uAE30\uBCF8 \uBB38\uC11C \uACE8\uACA9\uC744 \uC900\uBE44\uD558\uC138\uC694",
167
174
  "context.actionDetail.specWrite": "spec.md\uB97C \uC791\uC131/\uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C \uB9DE\uCD94\uC138\uC694",
168
- "context.actionDetail.specApprove": "spec.md\uB97C \uACF5\uC720\uD558\uACE0 \uBA85\uC2DC\uC801 \uC2B9\uC778\uC744 \uC694\uCCAD\uD558\uC138\uC694",
175
+ "context.actionDetail.specApprove": "spec.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
169
176
  "context.actionDetail.planWrite": "plan.md\uB97C \uC791\uC131/\uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C \uB9DE\uCD94\uC138\uC694",
170
- "context.actionDetail.planApprove": "plan.md\uB97C \uACF5\uC720\uD558\uACE0 \uBA85\uC2DC\uC801 \uC2B9\uC778\uC744 \uC694\uCCAD\uD558\uC138\uC694",
177
+ "context.actionDetail.planApprove": "plan.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
171
178
  "context.actionDetail.tasksWrite": "tasks.md\uB97C \uC791\uC131/\uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C \uC815\uB82C\uD558\uC138\uC694",
172
- "context.actionDetail.tasksApprove": "tasks.md\uB97C \uACF5\uC720\uD558\uACE0 \uC9C4\uD589 \uC2B9\uC778\uC744 \uC694\uCCAD\uD558\uC138\uC694",
173
- "context.actionDetail.issueCreate": "\uC774\uC288 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uC900\uBE44/\uC0DD\uC131/\uB3D9\uAE30\uD654\uD558\uC138\uC694",
174
- "context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C \uC2E4\uD589 \uB2E8\uACC4\uB97C \uC9C4\uD589\uD558\uC138\uC694",
179
+ "context.actionDetail.tasksApprove": "tasks.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
180
+ "context.actionDetail.issueCreate": "\uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 \uC774\uC288 \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
181
+ "context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
175
182
  "context.actionDetail.reviewFixCommit": "\uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uB9CC\uB4DC\uC138\uC694",
176
- "context.actionDetail.prePrReview": "Pre-PR \uB9AC\uBDF0 \uC810\uAC80\uC744 \uC218\uD589\uD558\uACE0 Findings/Evidence\uB97C \uAE30\uB85D\uD558\uC138\uC694",
177
- "context.actionDetail.prCreate": "PR\uC744 \uC900\uBE44/\uC0DD\uC131\uD558\uACE0 PR \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
178
- "context.actionDetail.prStatusUpdate": "tasks.md\uC758 PR \uC0C1\uD0DC \uD544\uB4DC\uB97C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
179
- "context.actionDetail.codeReview": "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uBC18\uC601\uD558\uACE0 Findings/Evidence\uB97C \uCD5C\uC2E0\uD654\uD558\uC138\uC694",
180
- "context.actionDetail.worktreeCleanup": "feature worktree\uB97C \uC81C\uAC70\uD558\uACE0 stale worktree \uC5D4\uD2B8\uB9AC\uB97C \uC815\uB9AC\uD558\uC138\uC694",
181
- "context.actionDetail.prMetadataMigrate": "tasks.md\uC758 PR \uD544\uB4DC\uB97C \uCD5C\uC2E0 \uD15C\uD50C\uB9BF\uC73C\uB85C \uB9C8\uC774\uADF8\uB808\uC774\uC158\uD558\uC138\uC694",
183
+ "context.actionDetail.prePrReview": "PR \uC804 \uB9AC\uBDF0\uB97C \uC218\uD589\uD558\uACE0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694",
184
+ "context.actionDetail.prCreate": "PR\uC744 \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 PR \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
185
+ "context.actionDetail.prStatusUpdate": "tasks.md\uC758 PR \uC0C1\uD0DC\uB97C \uCD5C\uC2E0\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
186
+ "context.actionDetail.codeReview": "\uCF54\uB4DC \uB9AC\uBDF0 \uC9C0\uC801\uC0AC\uD56D\uC744 \uBC18\uC601\uD558\uACE0 PR \uB9AC\uBDF0 \uC815\uBCF4\uB97C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
187
+ "context.actionDetail.worktreeCleanup": "\uC644\uB8CC\uB41C feature worktree\uB97C \uC815\uB9AC\uD558\uC138\uC694",
188
+ "context.actionDetail.prMetadataMigrate": "tasks.md\uC758 PR \uD56D\uBAA9 \uD615\uC2DD\uC744 \uCD5C\uC2E0 \uD15C\uD50C\uB9BF\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694",
182
189
  "context.actionDetail.userRequestReplan": "\uC0C8 \uC0AC\uC6A9\uC790 \uC694\uAD6C\uB97C \uBA3C\uC800 \uBC18\uC601\uD55C \uB4A4 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
183
- "context.actionDetail.featureDone": "\uC774 Feature\uC758 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC644\uB8CC \uC870\uAC74\uC774 \uCDA9\uC871\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
184
- "context.actionDetail.fallback": "\uD604\uC7AC \uBB38\uC11C/\uC0C1\uD0DC\uB97C \uC810\uAC80\uD55C \uB4A4 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
190
+ "context.actionDetail.featureDone": "\uC774 Feature\uC758 \uC644\uB8CC \uC870\uAC74\uC774 \uBAA8\uB450 \uCDA9\uC871\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
191
+ "context.actionDetail.fallback": "\uD604\uC7AC \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uB4A4 context\uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
185
192
  "context.suggestion.createFeature": "\uC0C8 Feature\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4",
186
193
  "context.suggestion.runOnboard": "\uCD08\uAE30 \uC124\uC815 \uC810\uAC80(onboard)\uC744 \uC2E4\uD589\uD569\uB2C8\uB2E4",
187
194
  "context.suggestion.showDone": "\uC644\uB8CC\uB41C Feature \uBAA9\uB85D\uC744 \uD655\uC778\uD569\uB2C8\uB2E4",
@@ -199,12 +206,10 @@ var ko = {
199
206
  "context.list.recordPrLink": "PR \uB9C1\uD06C \uAE30\uB85D",
200
207
  "context.list.addPrePrReviewField": "Pre-PR Review \uD544\uB4DC \uCD94\uAC00",
201
208
  "context.list.completePrePrReview": "Pre-PR \uB9AC\uBDF0 \uC644\uB8CC \uCC98\uB9AC",
202
- "context.list.addPrePrFindings": "Pre-PR Findings \uD544\uB4DC/\uAC12 \uBCF4\uC644",
203
209
  "context.list.addPrePrEvidence": "Pre-PR Evidence \uADFC\uAC70 \uCD94\uAC00",
204
- "context.list.addPrReviewFindings": "PR \uB9AC\uBDF0 Findings \uD544\uB4DC/\uAC12 \uBCF4\uC644",
210
+ "context.list.addPrePrDecision": "Pre-PR Decision \uAE30\uB85D",
205
211
  "context.list.addPrReviewEvidence": "PR \uB9AC\uBDF0 Evidence \uC694\uC57D \uCD94\uAC00",
206
- "context.list.resolvePrePrMajorFindings": "Pre-PR \uC8FC\uC694 Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
207
- "context.list.resolvePrePrMinorFindings": "Pre-PR minor Findings \uD574\uC18C \uD544\uC694 ({count}\uAC74)",
212
+ "context.list.addPrReviewDecision": "PR \uB9AC\uBDF0 Decision \uAE30\uB85D",
208
213
  "context.list.setPrStatus": "PR \uC0C1\uD0DC \uC124\uC815",
209
214
  "context.list.prStatusToApproved": "PR \uBA38\uC9C0 \uD544\uC694 (\uD604\uC7AC PR \uC0C1\uD0DC: {status} \u2192 Approved)",
210
215
  "context.list.approveSpec": "spec \uC2B9\uC778 \uD544\uC694",
@@ -326,8 +331,8 @@ var ko = {
326
331
  "github.postMergeCheckoutWarning": "PR merge\uB294 \uC644\uB8CC\uB418\uC5C8\uC9C0\uB9CC `{base}` checkout\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4(\uCE58\uBA85 \uC544\uB2D8): {detail}",
327
332
  "github.postMergePullWarning": "PR merge\uB294 \uC644\uB8CC\uB418\uC5C8\uC9C0\uB9CC `{base}` pull\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4(\uCE58\uBA85 \uC544\uB2D8): {detail}",
328
333
  "github.issueDefaultTitle": "{slug} ({summary})",
329
- "github.prDefaultTitleWithIssue": "feat(#{issue}): {slug} (\uAD6C\uD604 \uC5C5\uB370\uC774\uD2B8)",
330
- "github.prDefaultTitleNoIssue": "feat: {slug} (\uAD6C\uD604 \uC5C5\uB370\uC774\uD2B8)",
334
+ "github.prDefaultTitleWithIssue": "feat(#{issue}): {slug} ({featureRef} \uAD6C\uD604)",
335
+ "github.prDefaultTitleNoIssue": "feat: {slug} ({featureRef} \uAD6C\uD604)",
331
336
  "github.issueHeader": "\u{1F9FE} GitHub Issue \uB3C4\uC6B0\uBBF8",
332
337
  "github.prHeader": "\u{1F500} GitHub PR \uB3C4\uC6B0\uBBF8",
333
338
  "github.labelFeature": "Feature",
@@ -482,7 +487,7 @@ var ko = {
482
487
  reviewFixCommitGuidance: "PR \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uB9AC\uBDF0 \uBC18\uC601 \uD30C\uC77C\uB9CC \uC2A4\uD14C\uC774\uC9D5\uD55C \uB4A4 `fix(review): <review-fix-summary>` \uD615\uC2DD\uC73C\uB85C \uCEE4\uBC0B\uD558\uC138\uC694. `<review-fix-summary>`\uC5D0\uB294 \uC774\uBC88 \uCEE4\uBC0B\uC5D0\uC11C \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uB9AC\uBDF0 \uD56D\uBAA9 \uC694\uC57D\uC744 \uC791\uC131\uD558\uC138\uC694. (\uD0DC\uC2A4\uD06C \uC81C\uBAA9 \uC7AC\uC0AC\uC6A9 \uAE08\uC9C0)",
483
488
  standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
484
489
  createBranch: 'cd "{projectGitCwd}" && mkdir -p .worktrees && (git worktree add ".worktrees/feat-{issueNumber}-{slug}" "feat/{issueNumber}-{slug}" || git worktree add -b "feat/{issueNumber}-{slug}" ".worktrees/feat-{issueNumber}-{slug}") && echo "worktree: {projectGitCwd}/.worktrees/feat-{issueNumber}-{slug}"',
485
- worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune',
490
+ worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
486
491
  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.',
487
492
  tasksAllDoneButChecklist: "\uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\uC758 \uB0A8\uC740 \uD56D\uBAA9\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uD604\uC7AC \uC9C4\uD589: ({checked}/{total}) \uC0AC\uC6A9\uC790\uC640 \uD655\uC778 \uD6C4 \uCDA9\uC871 \uD56D\uBAA9\uC744 [x]\uB85C \uCCB4\uD06C\uD558\uACE0 \uCD5C\uC885 \uC2B9\uC778(OK)\uC744 \uBC18\uC601\uD558\uC138\uC694.",
488
493
  finishDoingTask: '\uD604\uC7AC DOING/REVIEW \uD0DC\uC2A4\uD06C\uB97C \uC218\uD589\uD558\uC138\uC694: "{title}" ({done}/{total}) \uC644\uB8CC \uC2DC \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC740 \uB4A4 DONE \uCC98\uB9AC',
@@ -496,19 +501,13 @@ var ko = {
496
501
  taskCommitGateReasonMismatchLastDone: "\uCD5C\uADFC \uD504\uB85C\uC81D\uD2B8 \uCF54\uB4DC \uCEE4\uBC0B\uC774 \uC9C1\uC804 \uC644\uB8CC \uD0DC\uC2A4\uD06C\uC640 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
497
502
  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)",
498
503
  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)",
499
- 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)",
500
504
  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)",
501
- 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.",
502
- 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.",
503
- prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 `{fallback}`\uC774\uBA70, `create-pr` \uBB38\uC11C\uC758 `Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8` \uC139\uC158\uC744 \uD56D\uC0C1 \uC218\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9)\uB85C \uCD94\uAC00 \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC644\uB8CC \uD6C4 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. Major \uC815\uCC45: {findingsPolicy}. Minor \uC815\uCC45: {minorFindingsPolicy}",
504
- prePrReviewFindingsBlock: "\uC911\uC694 \uC774\uC288\uB294 \uC218\uC815/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
505
- prePrReviewFindingsWarn: "\uB9AC\uC2A4\uD06C\uB97C \uACF5\uC720\uD558\uBA74 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
506
- prePrReviewMinorFindingsBlock: "minor \uC774\uC288\uB3C4 \uC815\uB9AC/\uD569\uC758 \uD6C4\uC5D0\uB9CC PR \uC0DD\uC131",
507
- prePrReviewMinorFindingsWarn: "minor \uC774\uC288\uB294 \uAE30\uB85D/\uACF5\uC720 \uD6C4 PR \uC0DD\uC131 \uC9C4\uD589 \uAC00\uB2A5",
508
- prReviewFindingsFieldMissing: "tasks.md\uC5D0 `PR \uB9AC\uBDF0 Findings` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
509
- prReviewFindingsMissing: "tasks.md\uC758 `PR \uB9AC\uBDF0 Findings` \uAC12\uC774 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC798\uBABB\uB418\uC5C8\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
505
+ prePrReviewDecisionMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uACB0\uC815 \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `\uACB0\uC815: ...`(\uB610\uB294 `decision: ...`) \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
506
+ prePrReviewRun: "PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 `{fallback}`\uC774\uBA70, `create-pr` \uBB38\uC11C\uC758 `Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8` \uC139\uC158\uC744 \uD56D\uC0C1 \uC218\uD589\uD558\uC138\uC694. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: {skills} (\uC124\uCE58\uB41C \uB354 \uC801\uD569\uD55C \uC2A4\uD0AC\uC774 \uC788\uB2E4\uBA74 \uBA3C\uC800 \uC81C\uC548 \uD6C4 \uC0AC\uC6A9)\uB85C \uCD94\uAC00 \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694. \uC644\uB8CC \uD6C4 `PR \uC804 \uB9AC\uBDF0`\uB97C Done\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694.",
510
507
  prReviewEvidenceFieldMissing: "tasks.md\uC5D0 `PR \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Evidence**: -` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
511
508
  prReviewEvidenceMissing: "tasks.md\uC758 `PR \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 placeholder\uC774\uAC70\uB098 \uC694\uC57D \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD574\uACB0/\uD569\uC758\uD55C \uB9AC\uBDF0 \uCF54\uBA58\uD2B8 \uADFC\uAC70\uB97C `\uC694\uC57D: ...`(\uB610\uB294 `summary: ...`) \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
509
+ prReviewDecisionFieldMissing: "tasks.md\uC5D0 `PR \uB9AC\uBDF0 Decision` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uB9AC\uBDF0 Decision**: -` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC \uC9C4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
510
+ prReviewDecisionMissing: "tasks.md\uC758 `PR \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uACB0\uC815 \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `\uACB0\uC815: ...`(\uB610\uB294 `decision: ...`) \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
512
511
  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.",
513
512
  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.",
514
513
  prCreateExecuteFromDoc: "`pr.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 PR\uC744 \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C PR \uB9C1\uD06C/PR \uC0C1\uD0DC\uB97C `tasks.md`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694. (`pr.md`\uB294 \uC0C1\uD0DC `Ready`\uB9CC \uC720\uC9C0)",
@@ -516,9 +515,9 @@ var ko = {
516
515
  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.",
517
516
  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.",
518
517
  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.)",
519
- prReviewMergedSyncStatus: "\uC6D0\uACA9 PR\uC774 \uC774\uBBF8 \uBA38\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. (PR/\uB9AC\uBDF0 \uADFC\uAC70 \uD544\uB4DC\uB3C4 \uCD5C\uC2E0 \uC0C1\uD0DC\uB85C \uD655\uC778)",
518
+ prReviewMergedSyncStatus: "\uC6D0\uACA9 PR\uC774 \uC774\uBBF8 \uBA38\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. tasks.md\uC758 PR \uC0C1\uD0DC\uB97C Approved\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694. (PR \uB9AC\uBDF0 Evidence/Decision \uD544\uB4DC\uB3C4 \uCD5C\uC2E0 \uC0C1\uD0DC\uB85C \uD655\uC778)",
520
519
  prResolveReview: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD574\uACB0\uD558\uC138\uC694. PR \uC0C1\uD0DC\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0, \uB9AC\uBDF0 \uC218\uC815 \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB294 \uC2E4\uC81C\uB85C \uD574\uACB0\uD55C \uD56D\uBAA9 \uC694\uC57D\uC73C\uB85C \uC791\uC131\uD558\uC138\uC694. (\uD0DC\uC2A4\uD06C \uC81C\uBAA9 \uC7AC\uC0AC\uC6A9 \uAE08\uC9C0) \uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uBA74 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 \uBA38\uC9C0 \uC635\uC158\uC744 \uC2E4\uD589\uD558\uC138\uC694. (\uC131\uACF5 \uC2DC PR \uC0C1\uD0DC\uAC00 Approved\uB85C \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.)",
521
- prReviewResolve: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694. PR \uC0C1\uD0DC\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0 `PR \uB9AC\uBDF0 Findings/Evidence`\uB97C \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. \uC6D0\uACA9 \uBC18\uC601(push)\uC740 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 \uC9C4\uD589\uD558\uC138\uC694.",
520
+ prReviewResolve: "\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694. PR \uC0C1\uD0DC\uB294 Review\uB97C \uC720\uC9C0\uD558\uACE0 `PR \uB9AC\uBDF0 Evidence/Decision`\uC744 \uCD5C\uC2E0\uC73C\uB85C \uAE30\uB85D\uD558\uC138\uC694. \uC6D0\uACA9 \uBC18\uC601(push)\uC740 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4, \uB85C\uCEEC \uBE0C\uB79C\uCE58\uAC00 upstream\uBCF4\uB2E4 \uC55E\uC120 \uACBD\uC6B0\uC5D0\uB9CC \uC9C4\uD589\uD558\uC138\uC694.",
522
521
  prReviewPush: 'cd "{projectGitCwd}" && git push',
523
522
  prReviewRemoteBlocked: "\uC6D0\uACA9 PR \uC0C1\uD0DC\uB97C \uD655\uC778\uD55C \uACB0\uACFC \uC544\uC9C1 \uBA38\uC9C0 \uC900\uBE44\uAC00 \uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: {reasons}. \uB9AC\uBDF0 \uCF54\uBA58\uD2B8/\uCCB4\uD06C \uC0C1\uD0DC\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
524
523
  prReviewRemoteReasonChangesRequested: "\uB9AC\uBDF0 \uC2B9\uC778 \uC0C1\uD0DC\uAC00 \uBCC0\uACBD \uC694\uCCAD \uB610\uB294 \uCD94\uAC00 \uB9AC\uBDF0 \uD544\uC694 \uC0C1\uD0DC\uC785\uB2C8\uB2E4",
@@ -543,10 +542,10 @@ var ko = {
543
542
  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.",
544
543
  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.",
545
544
  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`)",
546
- 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`)",
547
545
  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.",
548
- legacyTasksPrReviewFindingsField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Findings` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uB9AC\uBDF0 Findings**: major=0, minor=0`)",
546
+ legacyTasksPrePrDecisionField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. PR \uB2E8\uACC4 \uC804\uC5D0 `PR \uC804 \uB9AC\uBDF0 Decision` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uC804 \uB9AC\uBDF0 Decision**: \uACB0\uC815: ...`)",
549
547
  legacyTasksPrReviewEvidenceField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Evidence` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
548
+ legacyTasksPrReviewDecisionField: "\uAD6C\uBC84\uC804 tasks.md \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB2E8\uACC4 \uC804\uC5D0 `PR \uB9AC\uBDF0 Decision` \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uC138\uC694. (`- **PR \uB9AC\uBDF0 Decision**: \uACB0\uC815: ...`)",
550
549
  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.)",
551
550
  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.)",
552
551
  workflowIssueMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC \uC774\uC288 \uBC88\uD638\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uC138\uC694.)",
@@ -554,17 +553,15 @@ var ko = {
554
553
  workflowPrLinkMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC PR \uB9C1\uD06C\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. (tasks.md\uC758 PR \uD544\uB4DC\uB97C \uCC44\uC6B0\uC138\uC694.)",
555
554
  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.)",
556
555
  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.)",
557
- workflowPrReviewFindingsMissing: "\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C `PR \uB9AC\uBDF0 Findings`\uAC00 \uC5C6\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`major=0, minor=0` \uD615\uC2DD)",
558
556
  workflowPrReviewEvidenceMissing: "\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C `PR \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 placeholder\uC774\uAC70\uB098 \uC694\uC57D \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. (`\uC694\uC57D: ...` \uB610\uB294 `summary: ...` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D)",
557
+ workflowPrReviewDecisionMissing: "\uB9AC\uBDF0 \uB2E8\uACC4\uC5D0\uC11C `PR \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uACB0\uC815 \uD615\uC2DD\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. (`\uACB0\uC815: ...` \uB610\uB294 `decision: ...` \uD615\uC2DD\uC73C\uB85C \uAE30\uB85D)",
559
558
  workflowPrRemoteChangesRequested: "\uC6D0\uACA9 PR\uC5D0\uC11C \uBCC0\uACBD \uC694\uCCAD \uB610\uB294 \uCD94\uAC00 \uB9AC\uBDF0\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCF54\uBA58\uD2B8 \uBC18\uC601 \uD6C4 push\uD558\uACE0 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
560
559
  workflowPrRemoteChecksFailing: "\uC6D0\uACA9 PR \uCCB4\uD06C \uC2E4\uD328\uAC00 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC2E4\uD328 \uC6D0\uC778\uC744 \uD574\uACB0 \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
561
560
  workflowPrRemoteChecksPending: "\uC6D0\uACA9 PR \uCCB4\uD06C \uB300\uAE30\uAC00 {count}\uAC74 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uCCB4\uD06C \uC644\uB8CC \uD6C4 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.",
562
561
  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.)",
563
562
  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.)",
564
- 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)",
565
563
  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.)",
566
- 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)",
567
- 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)"
564
+ workflowPrePrDecisionMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 \uBE44\uC5B4\uC788\uAC70\uB098 \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`\uACB0\uC815: ...` \uB610\uB294 `decision: ...` \uD615\uC2DD)"
568
565
  }
569
566
  };
570
567
  var ko_default = ko;
@@ -640,33 +637,40 @@ var en = {
640
637
  "context.tipShowAll": "Show all",
641
638
  "context.tipShowDone": "Show done only",
642
639
  "context.checkRequired": "[CHECK required] ",
643
- "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for a reply that includes a label token (e.g. `A`, `A OK`, `A proceed`) before proceeding (config: approval can override)",
644
- "context.actionOptionHint": "Approval reply format: include a label token (e.g. `A`, `A OK`, `A proceed`)",
640
+ "context.checkPolicyHint": "\u2139\uFE0F Check user-approval policy once at session start (or right after context compression/reset); re-check only when policy/config changes or the user explicitly requests refresh. (includes git push/merge and merge commits). If you see [CHECK required], wait for a reply that follows label-token rules (`A`, `A OK`, `A proceed`) before proceeding (config: approval can override)",
641
+ "context.actionOptionHint": "Label reply rules: answer as `A`, `A OK`, or `A proceed`",
645
642
  "context.actionExplainHint": "Before requesting approval, explain what each label will run/change with a one-line summary.",
646
- "context.finalLabelPrompt": "Available labels now: {labels}. Reply with a label-token format. (e.g. `{example}`)",
647
- "context.finalLabelPromptWithRequest": "Available labels now: {labels}. Reply with a label-token format. (e.g. `{example}`) Labels that require a request must be replied as: {requestExamples}",
643
+ "context.finalLabelPrompt": "Available labels now: {labels}. Reply using label-token rules (`A`, `A OK`, `A proceed`). (e.g. `{example}`)",
644
+ "context.finalLabelPromptWithRequest": "Available labels now: {labels}. Reply using label-token rules (`A`, `A OK`, `A proceed`). (e.g. `{example}`) Labels that require a request must be replied as: {requestExamples}",
648
645
  "context.suggestionHeader": "Suggested Next Options",
649
646
  "context.suggestionCommandHint": "Reference command: {command}",
650
647
  "context.suggestionFinalPrompt": "Recommended labels now: {labels}. Please reply with a format that includes a label token. (e.g. {example}, `A proceed`)",
648
+ "context.commandDetail.branchCreateWithWorktree": "({scope}) create or reuse worktree {worktree} for branch {branch}",
649
+ "context.commandDetail.branchCreateWithBranch": "({scope}) create or reuse worktree for branch {branch}",
650
+ "context.commandDetail.branchCreateGeneric": "({scope}) create or reuse feature branch worktree",
651
+ "context.commandDetail.codeReviewMergeAfterOk": "({scope}) merge PR after explicit OK",
652
+ "context.commandDetail.codeReviewPushFix": "({scope}) push review-fix commits",
653
+ "context.actionSummary.runDocsCommand": "Run docs command",
654
+ "context.actionSummary.runProjectCommand": "Run project command",
651
655
  "context.actionDetail.featureFolder": "Prepare feature folder and baseline docs",
652
656
  "context.actionDetail.specWrite": "Write or refine spec.md and set status",
653
- "context.actionDetail.specApprove": "Share spec.md and request explicit approval",
657
+ "context.actionDetail.specApprove": "Approve spec.md",
654
658
  "context.actionDetail.planWrite": "Write or refine plan.md and set status",
655
- "context.actionDetail.planApprove": "Share plan.md and request explicit approval",
659
+ "context.actionDetail.planApprove": "Approve plan.md",
656
660
  "context.actionDetail.tasksWrite": "Write or refine tasks.md and align document status",
657
- "context.actionDetail.tasksApprove": "Share tasks.md and request progress approval",
658
- "context.actionDetail.issueCreate": "Prepare and create/update issue metadata",
659
- "context.actionDetail.taskExecute": "Proceed with the current task execution step",
661
+ "context.actionDetail.tasksApprove": "Approve tasks.md",
662
+ "context.actionDetail.issueCreate": "Create the issue and sync issue fields in tasks.md",
663
+ "context.actionDetail.taskExecute": "Proceed with the current task",
660
664
  "context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
661
- "context.actionDetail.prePrReview": "Complete pre-PR review checks and record findings/evidence",
662
- "context.actionDetail.prCreate": "Prepare or create PR and sync PR metadata",
663
- "context.actionDetail.prStatusUpdate": "Update PR status fields in tasks.md",
664
- "context.actionDetail.codeReview": "Address review comments and sync findings/evidence",
665
- "context.actionDetail.worktreeCleanup": "remove the feature worktree and prune stale worktree entries",
666
- "context.actionDetail.prMetadataMigrate": "Migrate tasks.md PR fields to the latest template",
665
+ "context.actionDetail.prePrReview": "Run pre-PR review and record results",
666
+ "context.actionDetail.prCreate": "Create PR and sync PR fields in tasks.md",
667
+ "context.actionDetail.prStatusUpdate": "Sync PR status in tasks.md with remote status",
668
+ "context.actionDetail.codeReview": "Address review feedback and update PR review fields",
669
+ "context.actionDetail.worktreeCleanup": "Clean up the completed feature worktree",
670
+ "context.actionDetail.prMetadataMigrate": "Update tasks.md PR fields to the latest template format",
667
671
  "context.actionDetail.userRequestReplan": "Handle the new user request first and re-run context",
668
- "context.actionDetail.featureDone": "All workflow checks are complete for this feature",
669
- "context.actionDetail.fallback": "Re-check context after verifying current docs/status",
672
+ "context.actionDetail.featureDone": "All completion checks are satisfied for this feature",
673
+ "context.actionDetail.fallback": "Verify current status and re-run context",
670
674
  "context.suggestion.createFeature": "Create a new feature",
671
675
  "context.suggestion.runOnboard": "Run onboarding checks",
672
676
  "context.suggestion.showDone": "Show completed features",
@@ -684,12 +688,10 @@ var en = {
684
688
  "context.list.recordPrLink": "Record PR link",
685
689
  "context.list.addPrePrReviewField": "Add Pre-PR Review field",
686
690
  "context.list.completePrePrReview": "Complete Pre-PR review",
687
- "context.list.addPrePrFindings": "Add/fill Pre-PR Findings",
688
691
  "context.list.addPrePrEvidence": "Add Pre-PR Evidence",
689
- "context.list.addPrReviewFindings": "Add/fill PR Review Findings",
692
+ "context.list.addPrePrDecision": "Add Pre-PR Decision",
690
693
  "context.list.addPrReviewEvidence": "Add PR Review Evidence summary",
691
- "context.list.resolvePrePrMajorFindings": "Resolve major pre-PR findings ({count})",
692
- "context.list.resolvePrePrMinorFindings": "Resolve minor pre-PR findings ({count})",
694
+ "context.list.addPrReviewDecision": "Add PR Review Decision",
693
695
  "context.list.setPrStatus": "Set PR Status",
694
696
  "context.list.prStatusToApproved": "PR merge required (PR Status: {status} \u2192 Approved)",
695
697
  "context.list.approveSpec": "Approve spec",
@@ -811,8 +813,8 @@ var en = {
811
813
  "github.postMergeCheckoutWarning": "PR merged, but checkout to `{base}` failed (non-fatal): {detail}",
812
814
  "github.postMergePullWarning": "PR merged, but pull for `{base}` failed (non-fatal): {detail}",
813
815
  "github.issueDefaultTitle": "{slug} ({summary})",
814
- "github.prDefaultTitleWithIssue": "feat(#{issue}): {slug} (implementation update)",
815
- "github.prDefaultTitleNoIssue": "feat: {slug} (implementation update)",
816
+ "github.prDefaultTitleWithIssue": "feat(#{issue}): {slug} ({featureRef} implementation)",
817
+ "github.prDefaultTitleNoIssue": "feat: {slug} ({featureRef} implementation)",
816
818
  "github.issueHeader": "\u{1F9FE} GitHub Issue Helper",
817
819
  "github.prHeader": "\u{1F500} GitHub PR Helper",
818
820
  "github.labelFeature": "Feature",
@@ -967,7 +969,7 @@ var en = {
967
969
  reviewFixCommitGuidance: "Commit PR review fixes. Stage only review-fix files, then commit with `fix(review): <review-fix-summary>`. `<review-fix-summary>` must describe review comments resolved in this commit (do not reuse task titles).",
968
970
  standaloneNeedsProjectRoot: "Standalone mode requires projectRoot. (npx lee-spec-kit config --project-root ...)",
969
971
  createBranch: 'cd "{projectGitCwd}" && mkdir -p .worktrees && (git worktree add ".worktrees/feat-{issueNumber}-{slug}" "feat/{issueNumber}-{slug}" || git worktree add -b "feat/{issueNumber}-{slug}" ".worktrees/feat-{issueNumber}-{slug}") && echo "worktree: {projectGitCwd}/.worktrees/feat-{issueNumber}-{slug}"',
970
- worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune',
972
+ worktreeCleanupCommand: 'cd "{projectGitCwd}" && git worktree remove "{worktreePath}" && git worktree prune && CURRENT_BRANCH=$(git branch --show-current) && DEFAULT_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | cut -d/ -f2-) && TARGET_BRANCH="${DEFAULT_BRANCH:-$CURRENT_BRANCH}" && if [ -n "$TARGET_BRANCH" ]; then git checkout "$TARGET_BRANCH" >/dev/null 2>&1 || true; fi && if git rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1 && [ -z "$(git status --porcelain)" ]; then git pull --ff-only || true; fi',
971
973
  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.',
972
974
  tasksAllDoneButChecklist: "Proceed with remaining completion checklist items. Current progress: ({checked}/{total}) Mark items as [x] only after user confirmation and real verification. Record final approval (OK) as well.",
973
975
  finishDoingTask: 'Continue working on the current DOING/REVIEW task: "{title}" ({done}/{total}) After it is complete, share outcome/verification and get approval before marking DONE',
@@ -981,19 +983,13 @@ var en = {
981
983
  taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
982
984
  prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
983
985
  prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
984
- 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)",
985
986
  prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty or placeholder. Add concrete review evidence (doc path/link/log). (CHECK required)",
986
- prePrReviewMajorBlocked: "Pre-PR major findings are recorded ({count}). With `blockOnFindings=true`, PR creation is blocked until major findings are resolved/aligned.",
987
- prePrReviewMinorBlocked: "Pre-PR minor findings are recorded ({count}). With `minorPolicy=block`, PR creation is blocked until minor findings are resolved/aligned.",
988
- prePrReviewRun: "Run a pre-PR code review before creating the PR. Always execute the `{fallback}` baseline by following the `Pre-PR Baseline Checklist` section in the `create-pr` doc. Then use preferred skills ({skills}) for deeper review (if a better installed skill fits this change, propose it first). After completing it, set `Pre-PR Review` to Done in tasks.md. Major policy: {findingsPolicy}. Minor policy: {minorFindingsPolicy}",
989
- prePrReviewFindingsBlock: "major findings must be fixed/aligned before PR creation",
990
- prePrReviewFindingsWarn: "you may proceed after sharing the risks",
991
- prePrReviewMinorFindingsBlock: "minor findings must also be fixed/aligned before PR creation",
992
- prePrReviewMinorFindingsWarn: "you may proceed after documenting/sharing minor risks",
993
- prReviewFindingsFieldMissing: "tasks.md is missing the `PR Review Findings` field. Add `- **PR Review Findings**: major=0, minor=0` and continue. (CHECK required)",
994
- prReviewFindingsMissing: "tasks.md `PR Review Findings` is missing or invalid. Record it as `- **PR Review Findings**: major=0, minor=0`. (CHECK required)",
987
+ prePrReviewDecisionMissing: "tasks.md `Pre-PR Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
988
+ prePrReviewRun: "Run a pre-PR code review before creating the PR. Always execute the `{fallback}` baseline by following the `Pre-PR Baseline Checklist` section in the `create-pr` doc. Then use preferred skills ({skills}) for deeper review (if a better installed skill fits this change, propose it first). After completing it, set `Pre-PR Review` to Done in tasks.md.",
995
989
  prReviewEvidenceFieldMissing: "tasks.md is missing the `PR Review Evidence` field. Add `- **PR Review Evidence**: -` and continue. (CHECK required)",
996
990
  prReviewEvidenceMissing: "tasks.md `PR Review Evidence` is empty/placeholder or missing summary format. Record evidence as `summary: ...` (or `\uC694\uC57D: ...`) for resolved/aligned review comments. (CHECK required)",
991
+ prReviewDecisionFieldMissing: "tasks.md is missing the `PR Review Decision` field. Add `- **PR Review Decision**: -` and continue. (CHECK required)",
992
+ prReviewDecisionMissing: "tasks.md `PR Review Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
997
993
  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.",
998
994
  prCreatePrepareFromDoc: "Use `pr.md` to refine PR title/body/labels draft, get explicit user OK, then set status to `Ready`.",
999
995
  prCreateExecuteFromDoc: "When `pr.md` status is `Ready`, create the PR and record the PR link/status in `tasks.md`. (Keep only `pr.md` status as `Ready`.)",
@@ -1001,9 +997,9 @@ var en = {
1001
997
  prCreateExecute: "Create the PR with the finalized body, then record the created PR link in tasks.md.",
1002
998
  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.",
1003
999
  prFillStatus: "Set PR Status in tasks.md to Review. (Keep Review during PR creation/review stages.)",
1004
- prReviewMergedSyncStatus: "The remote PR is already merged. Update PR Status in tasks.md to Approved. (Also verify PR/review evidence fields are up to date.)",
1000
+ prReviewMergedSyncStatus: "The remote PR is already merged. Update PR Status in tasks.md to Approved. (Also verify PR review Evidence/Decision fields are up to date.)",
1005
1001
  prResolveReview: "Address review comments while keeping PR Status as Review. For review-fix commits, summarize resolved feedback in the commit message (do not reuse task titles). Once ready to merge, get explicit user OK and run the merge option. (On success, PR Status is synced to Approved.)",
1006
- prReviewResolve: "Review/analyze PR comments first, then apply required fixes while addressing comments. Keep PR Status as Review and keep `PR Review Findings/Evidence` updated. Run push only after explicit user OK.",
1002
+ prReviewResolve: "Review/analyze PR comments first, then apply required fixes while addressing comments. Keep PR Status as Review and keep `PR Review Evidence/Decision` updated. Run push only after explicit user OK and only when local branch is ahead of upstream.",
1007
1003
  prReviewPush: 'cd "{projectGitCwd}" && git push',
1008
1004
  prReviewRemoteBlocked: "Remote PR checks indicate this PR is not ready to merge yet: {reasons}. Resolve review comments/check statuses, then re-check.",
1009
1005
  prReviewRemoteReasonChangesRequested: "review decision is changes requested or additional review required",
@@ -1028,10 +1024,10 @@ var en = {
1028
1024
  legacyTasksDocStatusField: "Legacy tasks.md format detected. Add a `Doc Status` field (Draft/Review/Approved) to enable tasks approval.",
1029
1025
  legacyTasksPrFields: "Legacy tasks.md format detected. Add `PR` and `PR Status` fields before PR steps.",
1030
1026
  legacyTasksPrePrReviewField: "Legacy tasks.md format detected. Add `Pre-PR Review` before PR steps. (`- **Pre-PR Review**: Pending | Done`)",
1031
- legacyTasksPrePrFindingsField: "Legacy tasks.md format detected. Add `Pre-PR Findings` before PR steps. (`- **Pre-PR Findings**: major=0, minor=0`)",
1032
1027
  legacyTasksPrePrEvidenceField: "Legacy tasks.md format detected. Add `Pre-PR Evidence` before PR steps.",
1033
- legacyTasksPrReviewFindingsField: "Legacy tasks.md format detected. Add `PR Review Findings` before review iteration. (`- **PR Review Findings**: major=0, minor=0`)",
1028
+ legacyTasksPrePrDecisionField: "Legacy tasks.md format detected. Add `Pre-PR Decision` before PR steps. (`- **Pre-PR Decision**: decision: ...`)",
1034
1029
  legacyTasksPrReviewEvidenceField: "Legacy tasks.md format detected. Add `PR Review Evidence` before review iteration.",
1030
+ legacyTasksPrReviewDecisionField: "Legacy tasks.md format detected. Add `PR Review Decision` before review iteration. (`- **PR Review Decision**: decision: ...`)",
1035
1031
  workflowSpecNotApproved: "Implementation is done but spec.md Status is not Approved. (Update spec.md Status to Approved.)",
1036
1032
  workflowPlanNotApproved: "Implementation is done but plan.md Status is not Approved. (Update plan.md Status to Approved.)",
1037
1033
  workflowIssueMissing: "Implementation is done but Issue Number is missing. (Fill Issue Number in tasks.md.)",
@@ -1039,17 +1035,15 @@ var en = {
1039
1035
  workflowPrLinkMissing: "Implementation is done but PR link is missing. (Fill the PR field in tasks.md.)",
1040
1036
  workflowPrStatusMissing: "Implementation is done but PR Status is missing. (Set PR Status to Review during PR creation/review stages.)",
1041
1037
  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.)",
1042
- workflowPrReviewFindingsMissing: "In review stage, `PR Review Findings` is missing or invalid. (Use `major=0, minor=0` format.)",
1043
1038
  workflowPrReviewEvidenceMissing: "In review stage, `PR Review Evidence` is empty/placeholder or missing summary format. (Use `summary: ...` or `\uC694\uC57D: ...`.)",
1039
+ workflowPrReviewDecisionMissing: "In review stage, `PR Review Decision` is empty/placeholder or missing decision format. (Use `decision: ...` or `\uACB0\uC815: ...`.)",
1044
1040
  workflowPrRemoteChangesRequested: "Remote PR shows changes requested or additional review required. Address comments, push, then re-check.",
1045
1041
  workflowPrRemoteChecksFailing: "Remote PR has {count} failing check(s). Fix failures, then re-check.",
1046
1042
  workflowPrRemoteChecksPending: "Remote PR has {count} pending check(s). Wait for checks to complete, then re-check.",
1047
1043
  workflowPrePrReviewMissing: "Implementation is done but `Pre-PR Review` is missing. (Add `- **Pre-PR Review**: Pending | Done` in tasks.md.)",
1048
1044
  workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)",
1049
- workflowPrePrFindingsMissing: "Implementation is done but `Pre-PR Findings` is missing or invalid. (Use `major=0, minor=0` format.)",
1050
1045
  workflowPrePrEvidenceMissing: "Implementation is done but `Pre-PR Evidence` is empty. (Record review evidence.)",
1051
- workflowPrePrFindingsBlocked: "Implementation is done but major pre-PR findings remain ({count}) while `blockOnFindings=true`.",
1052
- workflowPrePrMinorFindingsBlocked: "Implementation is done but minor pre-PR findings remain ({count}) while `minorPolicy=block`."
1046
+ workflowPrePrDecisionMissing: "Implementation is done but `Pre-PR Decision` is empty/invalid. (Use `decision: ...` or `\uACB0\uC815: ...`.)"
1053
1047
  }
1054
1048
  };
1055
1049
  var en_default = en;
@@ -2260,6 +2254,9 @@ async function runInit(options) {
2260
2254
  mode: workflowMode,
2261
2255
  codeDirtyScope: "auto",
2262
2256
  taskCommitGate: "warn",
2257
+ auto: {
2258
+ defaultPreset: "pr-handoff"
2259
+ },
2263
2260
  prePrReview: {
2264
2261
  skills: ["code-review-excellence"],
2265
2262
  minorPolicy: "warn"
@@ -2539,12 +2536,19 @@ function sanitizeTasksForLocal(content, lang) {
2539
2536
  )) {
2540
2537
  continue;
2541
2538
  }
2539
+ if (/^\s*-\s*\*\*(Pre-PR Decision|PR Review Decision|PR 전 리뷰 Decision|PR 리뷰 Decision)\*\*\s*:/.test(
2540
+ line
2541
+ )) {
2542
+ continue;
2543
+ }
2542
2544
  if (/^\s*-\s*(Example|Values)\s*:/.test(line)) continue;
2543
2545
  if (/^\s*-\s*(예|값)\s*:/.test(line)) continue;
2544
2546
  if (/^\s*-\s*Mark\s+`?Done`?/i.test(line)) continue;
2545
2547
  if (/^\s*-\s*사전 코드리뷰 완료 후/.test(line)) continue;
2546
2548
  if (/^\s*-\s*Update with final findings counts from pre-PR review/i.test(line))
2547
2549
  continue;
2550
+ if (/^\s*-\s*Record your key review decision/i.test(line)) continue;
2551
+ if (/^\s*-\s*사전 리뷰 주요 판단 근거를/.test(line)) continue;
2548
2552
  if (/^\s*-\s*Example:\s*review note link/i.test(line)) continue;
2549
2553
  if (/^\s*-\s*사전 리뷰 최종 결과/.test(line)) continue;
2550
2554
  if (/^\s*-\s*예:\s*리뷰 노트 링크/.test(line)) continue;
@@ -2847,6 +2851,31 @@ async function getNextFeatureId(docsDir, projectType, components) {
2847
2851
  return `F${String(next).padStart(width, "0")}`;
2848
2852
  }
2849
2853
 
2854
+ // src/utils/context/types.ts
2855
+ var ACTION_CATEGORIES = [
2856
+ "feature_folder",
2857
+ "spec_write",
2858
+ "spec_approve",
2859
+ "plan_write",
2860
+ "plan_approve",
2861
+ "tasks_write",
2862
+ "tasks_approve",
2863
+ "docs_commit",
2864
+ "issue_create",
2865
+ "branch_create",
2866
+ "task_execute",
2867
+ "review_fix_commit",
2868
+ "pr_create",
2869
+ "pr_metadata_migrate",
2870
+ "pre_pr_review",
2871
+ "pr_status_update",
2872
+ "code_review",
2873
+ "worktree_cleanup",
2874
+ "user_request_replan",
2875
+ "feature_done",
2876
+ "fallback"
2877
+ ];
2878
+
2850
2879
  // src/utils/workflow.ts
2851
2880
  var DEFAULT_PRE_PR_REVIEW_SKILLS = ["code-review-excellence"];
2852
2881
  function resolveWorkflowPolicy(workflow) {
@@ -2945,16 +2974,10 @@ function isPrePrReviewSatisfied(feature, prePrReviewPolicy) {
2945
2974
  if (!feature.docs.prePrReviewFieldExists || feature.prePrReview.status !== "Done") {
2946
2975
  return false;
2947
2976
  }
2948
- if (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findings) {
2949
- return false;
2950
- }
2951
2977
  if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
2952
2978
  return false;
2953
2979
  }
2954
- if (prePrReviewPolicy.blockOnFindings && feature.prePrReview.findings.major > 0) {
2955
- return false;
2956
- }
2957
- if (prePrReviewPolicy.minorPolicy === "block" && feature.prePrReview.findings.minor > 0) {
2980
+ if (!feature.docs.prePrDecisionFieldExists || !feature.prePrReview.decisionProvided) {
2958
2981
  return false;
2959
2982
  }
2960
2983
  return true;
@@ -2965,12 +2988,6 @@ function isFeatureDone(feature, workflowPolicy, prePrReviewPolicy) {
2965
2988
  function formatSkillList(skills) {
2966
2989
  return skills.join(", ");
2967
2990
  }
2968
- function getFindingsPolicyText(lang, blockOnFindings) {
2969
- return blockOnFindings ? tr(lang, "messages", "prePrReviewFindingsBlock") : tr(lang, "messages", "prePrReviewFindingsWarn");
2970
- }
2971
- function getMinorFindingsPolicyText(lang, minorPolicy) {
2972
- return minorPolicy === "block" ? tr(lang, "messages", "prePrReviewMinorFindingsBlock") : tr(lang, "messages", "prePrReviewMinorFindingsWarn");
2973
- }
2974
2991
  function getPrReviewRemoteBlockReasons(feature, lang) {
2975
2992
  const remote = feature.pr.remote;
2976
2993
  if (!remote || !remote.available) return [];
@@ -3547,6 +3564,7 @@ function getStepDefinitions(lang, workflow) {
3547
3564
  type: "instruction",
3548
3565
  category: "task_execute",
3549
3566
  requiresUserCheck: true,
3567
+ taskExecutePhase: "complete",
3550
3568
  message: tr(lang, "messages", "finishDoingTask", {
3551
3569
  title: f.activeTask.title,
3552
3570
  done: f.tasks.done,
@@ -3628,6 +3646,7 @@ function getStepDefinitions(lang, workflow) {
3628
3646
  type: "instruction",
3629
3647
  category: "task_execute",
3630
3648
  requiresUserCheck: true,
3649
+ taskExecutePhase: "start",
3631
3650
  message: `${tr(lang, "messages", "startNextTodoTask", {
3632
3651
  title: f.nextTodoTask.title,
3633
3652
  done: f.tasks.done,
@@ -3645,6 +3664,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3645
3664
  type: "instruction",
3646
3665
  category: "task_execute",
3647
3666
  requiresUserCheck: true,
3667
+ taskExecutePhase: "start",
3648
3668
  message: tr(lang, "messages", "startNextTodoTask", {
3649
3669
  title: f.nextTodoTask.title,
3650
3670
  done: f.tasks.done,
@@ -3781,15 +3801,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3781
3801
  requiresUserCheck: true,
3782
3802
  message: tr(lang, "messages", "prePrReviewRun", {
3783
3803
  skills: "code-review-excellence",
3784
- fallback: prePrReviewPolicy.fallback,
3785
- findingsPolicy: getFindingsPolicyText(
3786
- lang,
3787
- prePrReviewPolicy.blockOnFindings
3788
- ),
3789
- minorFindingsPolicy: getMinorFindingsPolicyText(
3790
- lang,
3791
- prePrReviewPolicy.minorPolicy
3792
- )
3804
+ fallback: prePrReviewPolicy.fallback
3793
3805
  })
3794
3806
  }
3795
3807
  ];
@@ -3801,29 +3813,11 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3801
3813
  requiresUserCheck: true,
3802
3814
  message: tr(lang, "messages", "prePrReviewRun", {
3803
3815
  skills: formatSkillList(prePrReviewPolicy.skills),
3804
- fallback: prePrReviewPolicy.fallback,
3805
- findingsPolicy: getFindingsPolicyText(
3806
- lang,
3807
- prePrReviewPolicy.blockOnFindings
3808
- ),
3809
- minorFindingsPolicy: getMinorFindingsPolicyText(
3810
- lang,
3811
- prePrReviewPolicy.minorPolicy
3812
- )
3816
+ fallback: prePrReviewPolicy.fallback
3813
3817
  })
3814
3818
  }
3815
3819
  ];
3816
3820
  }
3817
- if (!f.docs.prePrFindingsFieldExists || !f.prePrReview.findings) {
3818
- return [
3819
- {
3820
- type: "instruction",
3821
- category: "pre_pr_review",
3822
- requiresUserCheck: true,
3823
- message: tr(lang, "messages", "prePrReviewFindingsMissing")
3824
- }
3825
- ];
3826
- }
3827
3821
  if (!f.docs.prePrEvidenceFieldExists || !f.prePrReview.evidenceProvided) {
3828
3822
  return [
3829
3823
  {
@@ -3834,27 +3828,13 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3834
3828
  }
3835
3829
  ];
3836
3830
  }
3837
- if (prePrReviewPolicy.blockOnFindings && f.prePrReview.findings.major > 0) {
3838
- return [
3839
- {
3840
- type: "instruction",
3841
- category: "pre_pr_review",
3842
- requiresUserCheck: true,
3843
- message: tr(lang, "messages", "prePrReviewMajorBlocked", {
3844
- count: f.prePrReview.findings.major
3845
- })
3846
- }
3847
- ];
3848
- }
3849
- if (prePrReviewPolicy.minorPolicy === "block" && f.prePrReview.findings.minor > 0) {
3831
+ if (!f.docs.prePrDecisionFieldExists || !f.prePrReview.decisionProvided) {
3850
3832
  return [
3851
3833
  {
3852
3834
  type: "instruction",
3853
3835
  category: "pre_pr_review",
3854
3836
  requiresUserCheck: true,
3855
- message: tr(lang, "messages", "prePrReviewMinorBlocked", {
3856
- count: f.prePrReview.findings.minor
3857
- })
3837
+ message: tr(lang, "messages", "prePrReviewDecisionMissing")
3858
3838
  }
3859
3839
  ];
3860
3840
  }
@@ -3866,15 +3846,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3866
3846
  requiresUserCheck: true,
3867
3847
  message: tr(lang, "messages", "prePrReviewRun", {
3868
3848
  skills: "code-review-excellence",
3869
- fallback: prePrReviewPolicy.fallback,
3870
- findingsPolicy: getFindingsPolicyText(
3871
- lang,
3872
- prePrReviewPolicy.blockOnFindings
3873
- ),
3874
- minorFindingsPolicy: getMinorFindingsPolicyText(
3875
- lang,
3876
- prePrReviewPolicy.minorPolicy
3877
- )
3849
+ fallback: prePrReviewPolicy.fallback
3878
3850
  })
3879
3851
  }
3880
3852
  ];
@@ -3886,15 +3858,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3886
3858
  requiresUserCheck: true,
3887
3859
  message: tr(lang, "messages", "prePrReviewRun", {
3888
3860
  skills: formatSkillList(prePrReviewPolicy.skills),
3889
- fallback: prePrReviewPolicy.fallback,
3890
- findingsPolicy: getFindingsPolicyText(
3891
- lang,
3892
- prePrReviewPolicy.blockOnFindings
3893
- ),
3894
- minorFindingsPolicy: getMinorFindingsPolicyText(
3895
- lang,
3896
- prePrReviewPolicy.minorPolicy
3897
- )
3861
+ fallback: prePrReviewPolicy.fallback
3898
3862
  })
3899
3863
  }
3900
3864
  ];
@@ -3987,43 +3951,43 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
3987
3951
  }
3988
3952
  ];
3989
3953
  }
3990
- if (!f.docs.prReviewFindingsFieldExists) {
3954
+ if (!f.docs.prReviewEvidenceFieldExists) {
3991
3955
  return [
3992
3956
  {
3993
3957
  type: "instruction",
3994
3958
  category: "code_review",
3995
3959
  requiresUserCheck: true,
3996
- message: tr(lang, "messages", "prReviewFindingsFieldMissing")
3960
+ message: tr(lang, "messages", "prReviewEvidenceFieldMissing")
3997
3961
  }
3998
3962
  ];
3999
3963
  }
4000
- if (!f.prReview.findings) {
3964
+ if (!f.prReview.evidenceProvided) {
4001
3965
  return [
4002
3966
  {
4003
3967
  type: "instruction",
4004
3968
  category: "code_review",
4005
3969
  requiresUserCheck: true,
4006
- message: tr(lang, "messages", "prReviewFindingsMissing")
3970
+ message: tr(lang, "messages", "prReviewEvidenceMissing")
4007
3971
  }
4008
3972
  ];
4009
3973
  }
4010
- if (!f.docs.prReviewEvidenceFieldExists) {
3974
+ if (!f.docs.prReviewDecisionFieldExists) {
4011
3975
  return [
4012
3976
  {
4013
3977
  type: "instruction",
4014
3978
  category: "code_review",
4015
3979
  requiresUserCheck: true,
4016
- message: tr(lang, "messages", "prReviewEvidenceFieldMissing")
3980
+ message: tr(lang, "messages", "prReviewDecisionFieldMissing")
4017
3981
  }
4018
3982
  ];
4019
3983
  }
4020
- if ((f.prReview.findings.major > 0 || f.prReview.findings.minor > 0) && !f.prReview.evidenceProvided) {
3984
+ if (!f.prReview.decisionProvided) {
4021
3985
  return [
4022
3986
  {
4023
3987
  type: "instruction",
4024
3988
  category: "code_review",
4025
3989
  requiresUserCheck: true,
4026
- message: tr(lang, "messages", "prReviewEvidenceMissing")
3990
+ message: tr(lang, "messages", "prReviewDecisionMissing")
4027
3991
  }
4028
3992
  ];
4029
3993
  }
@@ -4044,7 +4008,7 @@ ${tr(lang, "messages", "taskCommitGateWarnProceed", {
4044
4008
  requiresUserCheck: true,
4045
4009
  message: tr(lang, "messages", "standaloneNeedsProjectRoot")
4046
4010
  });
4047
- } else {
4011
+ } else if ((f.git.projectBranchAhead || 0) > 0) {
4048
4012
  actions.push({
4049
4013
  type: "command",
4050
4014
  category: "code_review",
@@ -4154,9 +4118,28 @@ function normalizeApprovalToken(value) {
4154
4118
  return (value ?? "").trim().toLowerCase();
4155
4119
  }
4156
4120
  function applyApprovalPolicy(step, actions, approval) {
4157
- if (!approval) return actions;
4121
+ const taskExecuteCheckPolicy = approval?.taskExecuteCheck === "start_only" ? "start_only" : "both";
4122
+ if (!approval) {
4123
+ return actions.map((action) => ({
4124
+ ...action,
4125
+ requiresUserCheck: applyTaskExecutePhaseCheck(
4126
+ action,
4127
+ Boolean(action.requiresUserCheck),
4128
+ taskExecuteCheckPolicy
4129
+ )
4130
+ }));
4131
+ }
4158
4132
  const mode = approval.mode ?? "builtin";
4159
- if (mode === "builtin") return actions;
4133
+ if (mode === "builtin") {
4134
+ return actions.map((action) => ({
4135
+ ...action,
4136
+ requiresUserCheck: applyTaskExecutePhaseCheck(
4137
+ action,
4138
+ Boolean(action.requiresUserCheck),
4139
+ taskExecuteCheckPolicy
4140
+ )
4141
+ }));
4142
+ }
4160
4143
  if (mode === "steps") {
4161
4144
  const required = new Set(
4162
4145
  (approval.requireCheckSteps ?? approval.requireOkSteps ?? []).map((n) => typeof n === "number" ? n : Number(n)).filter((n) => Number.isFinite(n))
@@ -4174,8 +4157,9 @@ function applyApprovalPolicy(step, actions, approval) {
4174
4157
  return actions.map((a) => {
4175
4158
  const builtin = Boolean(a.requiresUserCheck);
4176
4159
  const category = normalizeApprovalToken(a.category ?? "uncategorized");
4160
+ const explicitlyRequired = requiredCategories.has("*") || requiredCategories.has(category);
4177
4161
  let requiresUserCheck = builtin;
4178
- if (requiredCategories.has("*") || requiredCategories.has(category)) {
4162
+ if (explicitlyRequired) {
4179
4163
  requiresUserCheck = true;
4180
4164
  } else if (skippedCategories.has("*") || skippedCategories.has(category)) {
4181
4165
  requiresUserCheck = false;
@@ -4184,9 +4168,24 @@ function applyApprovalPolicy(step, actions, approval) {
4184
4168
  } else if (defaultPolicy === "skip") {
4185
4169
  requiresUserCheck = false;
4186
4170
  }
4187
- return { ...a, requiresUserCheck };
4171
+ return {
4172
+ ...a,
4173
+ requiresUserCheck: applyTaskExecutePhaseCheck(
4174
+ a,
4175
+ requiresUserCheck,
4176
+ taskExecuteCheckPolicy,
4177
+ explicitlyRequired
4178
+ )
4179
+ };
4188
4180
  });
4189
4181
  }
4182
+ function applyTaskExecutePhaseCheck(action, requiresUserCheck, policy, explicitlyRequired = false) {
4183
+ if (policy !== "start_only") return requiresUserCheck;
4184
+ if (action.category !== "task_execute") return requiresUserCheck;
4185
+ if (action.taskExecutePhase !== "complete") return requiresUserCheck;
4186
+ if (explicitlyRequired) return requiresUserCheck;
4187
+ return false;
4188
+ }
4190
4189
  function withUserRequestReplanOption(actions, lang) {
4191
4190
  if (actions.some((action) => action.category === "user_request_replan")) {
4192
4191
  return actions;
@@ -4551,6 +4550,12 @@ function hasStructuredReviewSummary(value) {
4551
4550
  if (!trimmed) return false;
4552
4551
  return /^(?:summary|요약)\s*[::]\s*\S.+$/i.test(trimmed);
4553
4552
  }
4553
+ function hasStructuredReviewDecision(value) {
4554
+ if (!value) return false;
4555
+ const trimmed = value.trim();
4556
+ if (!trimmed) return false;
4557
+ return /^(?:decision|결정)\s*[::]\s*\S.+$/i.test(trimmed);
4558
+ }
4554
4559
  function parseIssueNumber(value) {
4555
4560
  if (!value) return void 0;
4556
4561
  const match = value.match(/#?(\d+)/);
@@ -4715,6 +4720,31 @@ function resolvePrRemoteStatus(prRef, projectGitCwd) {
4715
4720
  return null;
4716
4721
  }
4717
4722
  }
4723
+ function resolveBranchDivergence(projectGitCwd) {
4724
+ try {
4725
+ const raw = execFileSync(
4726
+ "git",
4727
+ ["rev-list", "--left-right", "--count", "HEAD...@{upstream}"],
4728
+ {
4729
+ cwd: projectGitCwd,
4730
+ encoding: "utf-8",
4731
+ stdio: ["ignore", "pipe", "pipe"]
4732
+ }
4733
+ ).trim();
4734
+ const match = raw.match(/^(\d+)\s+(\d+)$/);
4735
+ if (!match) {
4736
+ return { hasUpstream: false, ahead: 0, behind: 0 };
4737
+ }
4738
+ const ahead = Number(match[1]);
4739
+ const behind = Number(match[2]);
4740
+ if (!Number.isFinite(ahead) || !Number.isFinite(behind)) {
4741
+ return { hasUpstream: false, ahead: 0, behind: 0 };
4742
+ }
4743
+ return { hasUpstream: true, ahead, behind };
4744
+ } catch {
4745
+ return { hasUpstream: false, ahead: 0, behind: 0 };
4746
+ }
4747
+ }
4718
4748
  async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
4719
4749
  const configured = workflow?.componentPaths?.[component];
4720
4750
  const configuredCandidates = Array.isArray(configured) ? configured.map((value) => String(value).trim()).filter(Boolean) : [];
@@ -4815,16 +4845,10 @@ function isPrePrReviewSatisfied2(feature, policy) {
4815
4845
  if (!feature.docs.prePrReviewFieldExists || feature.prePrReview.status !== "Done") {
4816
4846
  return false;
4817
4847
  }
4818
- if (!feature.docs.prePrFindingsFieldExists || !feature.prePrReview.findings) {
4819
- return false;
4820
- }
4821
4848
  if (!feature.docs.prePrEvidenceFieldExists || !feature.prePrReview.evidenceProvided) {
4822
4849
  return false;
4823
4850
  }
4824
- if (policy.blockOnFindings && feature.prePrReview.findings.major > 0) {
4825
- return false;
4826
- }
4827
- if (policy.minorPolicy === "block" && feature.prePrReview.findings.minor > 0) {
4851
+ if (!feature.docs.prePrDecisionFieldExists || !feature.prePrReview.decisionProvided) {
4828
4852
  return false;
4829
4853
  }
4830
4854
  return true;
@@ -4895,9 +4919,13 @@ async function parseFeature(featurePath, type, context, options) {
4895
4919
  let prePrFindings;
4896
4920
  let prePrEvidence;
4897
4921
  let prePrEvidenceProvided = false;
4922
+ let prePrDecision;
4923
+ let prePrDecisionProvided = false;
4898
4924
  let prReviewFindings;
4899
4925
  let prReviewEvidence;
4900
4926
  let prReviewEvidenceProvided = false;
4927
+ let prReviewDecision;
4928
+ let prReviewDecisionProvided = false;
4901
4929
  let prLink;
4902
4930
  let prStatus;
4903
4931
  let prRemote;
@@ -4913,8 +4941,10 @@ async function parseFeature(featurePath, type, context, options) {
4913
4941
  let prePrReviewFieldExists = false;
4914
4942
  let prePrFindingsFieldExists = false;
4915
4943
  let prePrEvidenceFieldExists = false;
4944
+ let prePrDecisionFieldExists = false;
4916
4945
  let prReviewFindingsFieldExists = false;
4917
4946
  let prReviewEvidenceFieldExists = false;
4947
+ let prReviewDecisionFieldExists = false;
4918
4948
  if (tasksExists) {
4919
4949
  const content = await fs16.readFile(tasksPath, "utf-8");
4920
4950
  const {
@@ -4974,6 +5004,16 @@ async function parseFeature(featurePath, type, context, options) {
4974
5004
  ]);
4975
5005
  prePrEvidence = prePrEvidenceValue?.trim();
4976
5006
  prePrEvidenceProvided = !isPlaceholderReviewEvidence(prePrEvidenceValue);
5007
+ const prePrDecisionValue = extractFirstSpecValue(content, [
5008
+ "PR \uC804 \uB9AC\uBDF0 Decision",
5009
+ "Pre-PR Decision"
5010
+ ]);
5011
+ prePrDecisionFieldExists = hasAnySpecKey(content, [
5012
+ "PR \uC804 \uB9AC\uBDF0 Decision",
5013
+ "Pre-PR Decision"
5014
+ ]);
5015
+ prePrDecision = prePrDecisionValue?.trim();
5016
+ prePrDecisionProvided = !isPlaceholderReviewEvidence(prePrDecisionValue) && hasStructuredReviewDecision(prePrDecisionValue);
4977
5017
  const prReviewFindingsValue = extractFirstSpecValue(content, [
4978
5018
  "PR \uB9AC\uBDF0 Findings",
4979
5019
  "PR Review Findings"
@@ -4993,6 +5033,16 @@ async function parseFeature(featurePath, type, context, options) {
4993
5033
  ]);
4994
5034
  prReviewEvidence = prReviewEvidenceValue?.trim();
4995
5035
  prReviewEvidenceProvided = !isPlaceholderReviewEvidence(prReviewEvidenceValue) && hasStructuredReviewSummary(prReviewEvidenceValue);
5036
+ const prReviewDecisionValue = extractFirstSpecValue(content, [
5037
+ "PR \uB9AC\uBDF0 Decision",
5038
+ "PR Review Decision"
5039
+ ]);
5040
+ prReviewDecisionFieldExists = hasAnySpecKey(content, [
5041
+ "PR \uB9AC\uBDF0 Decision",
5042
+ "PR Review Decision"
5043
+ ]);
5044
+ prReviewDecision = prReviewDecisionValue?.trim();
5045
+ prReviewDecisionProvided = !isPlaceholderReviewEvidence(prReviewDecisionValue) && hasStructuredReviewDecision(prReviewDecisionValue);
4996
5046
  }
4997
5047
  if (effectiveProjectGitCwd && issueNumber) {
4998
5048
  const alreadyExpected = isExpectedFeatureBranch(
@@ -5073,6 +5123,9 @@ async function parseFeature(featurePath, type, context, options) {
5073
5123
  }
5074
5124
  let projectHasUncommittedChanges = typeof context.projectHasUncommittedChanges === "boolean" ? context.projectHasUncommittedChanges : false;
5075
5125
  let projectStatusUnavailable = !!context.projectStatusUnavailable;
5126
+ let projectHasUpstream = false;
5127
+ let projectBranchAhead = 0;
5128
+ let projectBranchBehind = 0;
5076
5129
  if (typeof context.projectHasUncommittedChanges !== "boolean" && effectiveProjectGitCwd) {
5077
5130
  const dirtyScopePolicy = resolveCodeDirtyScopePolicy(options.workflow, options.projectType);
5078
5131
  const projectCacheKey = JSON.stringify({
@@ -5113,6 +5166,12 @@ async function parseFeature(featurePath, type, context, options) {
5113
5166
  });
5114
5167
  }
5115
5168
  }
5169
+ if (effectiveProjectGitCwd) {
5170
+ const divergence = resolveBranchDivergence(effectiveProjectGitCwd);
5171
+ projectHasUpstream = divergence.hasUpstream;
5172
+ projectBranchAhead = divergence.ahead;
5173
+ projectBranchBehind = divergence.behind;
5174
+ }
5116
5175
  if (docsGitUnavailable) {
5117
5176
  warnings.push(tr(lang, "warnings", "docsGitUnavailable"));
5118
5177
  }
@@ -5129,18 +5188,18 @@ async function parseFeature(featurePath, type, context, options) {
5129
5188
  if (tasksExists && prePrReviewPolicy.enabled && !prePrReviewFieldExists) {
5130
5189
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrReviewField"));
5131
5190
  }
5132
- if (tasksExists && prePrReviewPolicy.enabled && !prePrFindingsFieldExists) {
5133
- warnings.push(tr(lang, "warnings", "legacyTasksPrePrFindingsField"));
5134
- }
5135
5191
  if (tasksExists && prePrReviewPolicy.enabled && !prePrEvidenceFieldExists) {
5136
5192
  warnings.push(tr(lang, "warnings", "legacyTasksPrePrEvidenceField"));
5137
5193
  }
5138
- if (tasksExists && workflowPolicy.requireReview && !prReviewFindingsFieldExists) {
5139
- warnings.push(tr(lang, "warnings", "legacyTasksPrReviewFindingsField"));
5194
+ if (tasksExists && prePrReviewPolicy.enabled && !prePrDecisionFieldExists) {
5195
+ warnings.push(tr(lang, "warnings", "legacyTasksPrePrDecisionField"));
5140
5196
  }
5141
5197
  if (tasksExists && workflowPolicy.requireReview && !prReviewEvidenceFieldExists) {
5142
5198
  warnings.push(tr(lang, "warnings", "legacyTasksPrReviewEvidenceField"));
5143
5199
  }
5200
+ if (tasksExists && workflowPolicy.requireReview && !prReviewDecisionFieldExists) {
5201
+ warnings.push(tr(lang, "warnings", "legacyTasksPrReviewDecisionField"));
5202
+ }
5144
5203
  if (tasksExists && !tasksDocStatusFieldExists) {
5145
5204
  warnings.push(tr(lang, "warnings", "legacyTasksDocStatusField"));
5146
5205
  }
@@ -5173,13 +5232,13 @@ async function parseFeature(featurePath, type, context, options) {
5173
5232
  {
5174
5233
  docs: {
5175
5234
  prePrReviewFieldExists,
5176
- prePrFindingsFieldExists,
5177
- prePrEvidenceFieldExists
5235
+ prePrEvidenceFieldExists,
5236
+ prePrDecisionFieldExists
5178
5237
  },
5179
5238
  prePrReview: {
5180
5239
  status: prePrReviewStatus,
5181
- findings: prePrFindings,
5182
- evidenceProvided: prePrEvidenceProvided
5240
+ evidenceProvided: prePrEvidenceProvided,
5241
+ decisionProvided: prePrDecisionProvided
5183
5242
  }
5184
5243
  },
5185
5244
  prePrReviewPolicy
@@ -5204,12 +5263,12 @@ async function parseFeature(featurePath, type, context, options) {
5204
5263
  if (prStatus && prStatus !== "Approved") {
5205
5264
  warnings.push(tr(lang, "warnings", "workflowPrStatusNotApproved"));
5206
5265
  if (prStatus === "Review") {
5207
- if (!prReviewFindingsFieldExists || !prReviewFindings) {
5208
- warnings.push(tr(lang, "warnings", "workflowPrReviewFindingsMissing"));
5209
- }
5210
- if ((!prReviewEvidenceFieldExists || !prReviewEvidenceProvided) && (prReviewFindings?.major || 0) + (prReviewFindings?.minor || 0) > 0) {
5266
+ if (!prReviewEvidenceFieldExists || !prReviewEvidenceProvided) {
5211
5267
  warnings.push(tr(lang, "warnings", "workflowPrReviewEvidenceMissing"));
5212
5268
  }
5269
+ if (!prReviewDecisionFieldExists || !prReviewDecisionProvided) {
5270
+ warnings.push(tr(lang, "warnings", "workflowPrReviewDecisionMissing"));
5271
+ }
5213
5272
  }
5214
5273
  }
5215
5274
  }
@@ -5219,22 +5278,10 @@ async function parseFeature(featurePath, type, context, options) {
5219
5278
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewMissing"));
5220
5279
  } else if (prePrReviewStatus !== "Done") {
5221
5280
  warnings.push(tr(lang, "warnings", "workflowPrePrReviewNotDone"));
5222
- } else if (!prePrFindingsFieldExists || !prePrFindings) {
5223
- warnings.push(tr(lang, "warnings", "workflowPrePrFindingsMissing"));
5224
5281
  } else if (!prePrEvidenceFieldExists || !prePrEvidenceProvided) {
5225
5282
  warnings.push(tr(lang, "warnings", "workflowPrePrEvidenceMissing"));
5226
- } else if (prePrReviewPolicy.blockOnFindings && prePrFindings.major > 0) {
5227
- warnings.push(
5228
- tr(lang, "warnings", "workflowPrePrFindingsBlocked", {
5229
- count: prePrFindings.major
5230
- })
5231
- );
5232
- } else if (prePrReviewPolicy.minorPolicy === "block" && prePrFindings.minor > 0) {
5233
- warnings.push(
5234
- tr(lang, "warnings", "workflowPrePrMinorFindingsBlocked", {
5235
- count: prePrFindings.minor
5236
- })
5237
- );
5283
+ } else if (!prePrDecisionFieldExists || !prePrDecisionProvided) {
5284
+ warnings.push(tr(lang, "warnings", "workflowPrePrDecisionMissing"));
5238
5285
  }
5239
5286
  }
5240
5287
  }
@@ -5261,12 +5308,16 @@ async function parseFeature(featurePath, type, context, options) {
5261
5308
  status: prePrReviewStatus,
5262
5309
  findings: prePrFindings,
5263
5310
  evidence: prePrEvidence,
5264
- evidenceProvided: prePrEvidenceProvided
5311
+ evidenceProvided: prePrEvidenceProvided,
5312
+ decision: prePrDecision,
5313
+ decisionProvided: prePrDecisionProvided
5265
5314
  },
5266
5315
  prReview: {
5267
5316
  findings: prReviewFindings,
5268
5317
  evidence: prReviewEvidence,
5269
- evidenceProvided: prReviewEvidenceProvided
5318
+ evidenceProvided: prReviewEvidenceProvided,
5319
+ decision: prReviewDecision,
5320
+ decisionProvided: prReviewDecisionProvided
5270
5321
  },
5271
5322
  pr: { link: prLink, status: prStatus, remote: prRemote },
5272
5323
  git: {
@@ -5279,7 +5330,10 @@ async function parseFeature(featurePath, type, context, options) {
5279
5330
  docsEverCommitted,
5280
5331
  docsHasUncommittedChanges,
5281
5332
  projectHasUncommittedChanges,
5282
- docsPathIgnored: docsPathIgnored === true
5333
+ docsPathIgnored: docsPathIgnored === true,
5334
+ projectHasUpstream,
5335
+ projectBranchAhead,
5336
+ projectBranchBehind
5283
5337
  },
5284
5338
  docs: {
5285
5339
  featurePathFromDocs: relativeFeaturePathFromDocs,
@@ -5301,8 +5355,10 @@ async function parseFeature(featurePath, type, context, options) {
5301
5355
  prePrReviewFieldExists,
5302
5356
  prePrFindingsFieldExists,
5303
5357
  prePrEvidenceFieldExists,
5358
+ prePrDecisionFieldExists,
5304
5359
  prReviewFindingsFieldExists,
5305
- prReviewEvidenceFieldExists
5360
+ prReviewEvidenceFieldExists,
5361
+ prReviewDecisionFieldExists
5306
5362
  }
5307
5363
  };
5308
5364
  const { currentStep, actions, nextAction } = resolveFeatureProgress(
@@ -5834,6 +5890,12 @@ async function backfillMissingConfigDefaults(docsDir) {
5834
5890
  setIfMissing(workflow, "mode", "github", "workflow.mode");
5835
5891
  setIfMissing(workflow, "codeDirtyScope", "auto", "workflow.codeDirtyScope");
5836
5892
  setIfMissing(workflow, "taskCommitGate", "warn", "workflow.taskCommitGate");
5893
+ if (!isPlainObject(workflow.auto)) {
5894
+ workflow.auto = {};
5895
+ changedPaths.push("workflow.auto");
5896
+ }
5897
+ const workflowAuto = workflow.auto;
5898
+ setIfMissing(workflowAuto, "defaultPreset", "pr-handoff", "workflow.auto.defaultPreset");
5837
5899
  if (!isPlainObject(workflow.prePrReview)) {
5838
5900
  workflow.prePrReview = {};
5839
5901
  changedPaths.push("workflow.prePrReview");
@@ -6180,7 +6242,6 @@ var ACTION_DETAIL_KEY_BY_CATEGORY = {
6180
6242
  tasks_write: "context.actionDetail.tasksWrite",
6181
6243
  tasks_approve: "context.actionDetail.tasksApprove",
6182
6244
  issue_create: "context.actionDetail.issueCreate",
6183
- task_execute: "context.actionDetail.taskExecute",
6184
6245
  review_fix_commit: "context.actionDetail.reviewFixCommit",
6185
6246
  pr_create: "context.actionDetail.prCreate",
6186
6247
  pr_status_update: "context.actionDetail.prStatusUpdate",
@@ -6224,28 +6285,20 @@ function annotateActionOperationType(action) {
6224
6285
  function annotateActions(actions) {
6225
6286
  return actions.map((action) => annotateActionOperationType(action));
6226
6287
  }
6227
- function getActionSummary(action) {
6228
- if (action.category === "docs_commit") return "Commit docs updates";
6229
- if (action.category === "issue_create") return "Create and record issue";
6230
- if (action.category === "branch_create") return "Create feature branch";
6231
- if (action.category === "pr_create") return "Create PR and record link";
6232
- if (action.category === "pre_pr_review") return "Run pre-PR self review";
6233
- if (action.category === "pr_status_update") return "Update PR status";
6234
- if (action.category === "code_review") return "Process code review feedback";
6235
- if (action.category === "worktree_cleanup") return "Clean up feature worktree";
6236
- if (action.category === "user_request_replan") return "Handle a new user request first";
6237
- if (action.category === "task_execute") return "Proceed with task execution";
6238
- if (action.category === "review_fix_commit") return "Commit review feedback fixes";
6239
- if (action.category === "feature_done") return "Feature is complete";
6240
- if (action.category === "spec_approve") return "Request spec approval";
6241
- if (action.category === "plan_approve") return "Request plan approval";
6242
- if (action.category === "tasks_approve") return "Request tasks approval";
6243
- if (action.category === "pr_metadata_migrate") return "Update tasks.md to latest PR fields";
6244
- if (action.category === "fallback") return "Re-check context and rerun";
6288
+ function getActionSummary(action, lang) {
6289
+ const detailKey = action.category ? ACTION_DETAIL_KEY_BY_CATEGORY[action.category] : void 0;
6290
+ if (detailKey) {
6291
+ const localized = tr(lang, "cli", detailKey);
6292
+ if (localized !== `cli.${detailKey}`) return localized;
6293
+ }
6245
6294
  if (action.type === "command") {
6246
- return action.scope === "docs" ? "Run docs command" : "Run project command";
6295
+ return tr(
6296
+ lang,
6297
+ "cli",
6298
+ action.scope === "docs" ? "context.actionSummary.runDocsCommand" : "context.actionSummary.runProjectCommand"
6299
+ );
6247
6300
  }
6248
- return action.message;
6301
+ return toOneLine(action.message);
6249
6302
  }
6250
6303
  function toOneLine(text) {
6251
6304
  const normalized = text.replace(/\s+/g, " ").trim();
@@ -6260,12 +6313,21 @@ function buildActionDetail(action, lang) {
6260
6313
  const worktree = worktreeMatch ? `.worktrees/${worktreeMatch[1]}` : null;
6261
6314
  const branch = branchMatch ? `feat/${branchMatch[1]}` : null;
6262
6315
  if (worktree && branch) {
6263
- return `(${action.scope}) create or reuse worktree ${worktree} for branch ${branch}`;
6316
+ return tr(lang, "cli", "context.commandDetail.branchCreateWithWorktree", {
6317
+ scope: action.scope,
6318
+ worktree,
6319
+ branch
6320
+ });
6264
6321
  }
6265
6322
  if (branch) {
6266
- return `(${action.scope}) create or reuse worktree for branch ${branch}`;
6323
+ return tr(lang, "cli", "context.commandDetail.branchCreateWithBranch", {
6324
+ scope: action.scope,
6325
+ branch
6326
+ });
6267
6327
  }
6268
- return `(${action.scope}) create or reuse feature branch worktree`;
6328
+ return tr(lang, "cli", "context.commandDetail.branchCreateGeneric", {
6329
+ scope: action.scope
6330
+ });
6269
6331
  };
6270
6332
  const extractCommitMessage = (command) => {
6271
6333
  const doubleQuoted = command.match(/git\s+commit\s+-m\s+"((?:\\"|[^"])*)"/);
@@ -6284,10 +6346,14 @@ function buildActionDetail(action, lang) {
6284
6346
  }
6285
6347
  if (action.category === "code_review") {
6286
6348
  if (/--merge\s+--confirm\s+OK/.test(action.cmd)) {
6287
- return `(${action.scope}) merge PR after explicit OK`;
6349
+ return tr(lang, "cli", "context.commandDetail.codeReviewMergeAfterOk", {
6350
+ scope: action.scope
6351
+ });
6288
6352
  }
6289
6353
  if (/\bgit\s+push\b/i.test(action.cmd)) {
6290
- return `(${action.scope}) push review-fix commits`;
6354
+ return tr(lang, "cli", "context.commandDetail.codeReviewPushFix", {
6355
+ scope: action.scope
6356
+ });
6291
6357
  }
6292
6358
  }
6293
6359
  if (action.category === "worktree_cleanup") {
@@ -6299,6 +6365,9 @@ function buildActionDetail(action, lang) {
6299
6365
  }
6300
6366
  return `(${action.scope}) ${action.cmd}`;
6301
6367
  }
6368
+ if (action.category === "task_execute") {
6369
+ return toOneLine(action.message);
6370
+ }
6302
6371
  const detailKey = action.category ? ACTION_DETAIL_KEY_BY_CATEGORY[action.category] : void 0;
6303
6372
  if (detailKey) {
6304
6373
  const localized = tr(lang, "cli", detailKey);
@@ -6309,7 +6378,7 @@ function buildActionDetail(action, lang) {
6309
6378
  function toActionOptions(actions, lang) {
6310
6379
  return actions.map((action, index) => {
6311
6380
  const label = getActionLabel(index);
6312
- const summary = getActionSummary(action);
6381
+ const summary = getActionSummary(action, lang);
6313
6382
  const detail = buildActionDetail(action, lang);
6314
6383
  const requiresRequestText = action.category === "user_request_replan";
6315
6384
  const replyExample = requiresRequestText ? `${label}, <your request>` : `${label} OK`;
@@ -6872,6 +6941,16 @@ function listSuggestionLabels(suggestionOptions) {
6872
6941
  if (suggestionOptions.length === 0) return "-";
6873
6942
  return suggestionOptions.map((o) => o.label).join(", ");
6874
6943
  }
6944
+ function listActiveCategories(actionOptions) {
6945
+ const unique2 = /* @__PURE__ */ new Set();
6946
+ for (const option of actionOptions) {
6947
+ if (option.action.category) unique2.add(option.action.category);
6948
+ }
6949
+ return Array.from(unique2);
6950
+ }
6951
+ function listUncategorizedLabels(actionOptions) {
6952
+ return actionOptions.filter((option) => !option.action.category).map((option) => option.label);
6953
+ }
6875
6954
  function resolveFeatureRefForApproval(state, featureName) {
6876
6955
  const raw = featureName?.trim() || state.matchedFeature?.folderName || "<slug|F001|F001-slug>";
6877
6956
  return raw;
@@ -7103,21 +7182,11 @@ function getListLabel(f, stepsMap, lang, workflowPolicy, prePrReviewPolicy) {
7103
7182
  if (prePrReviewPolicy.enabled && f.prePrReview.status !== "Done") {
7104
7183
  return tr(lang, "cli", "context.list.completePrePrReview");
7105
7184
  }
7106
- if (prePrReviewPolicy.enabled && (!f.docs.prePrFindingsFieldExists || !f.prePrReview.findings)) {
7107
- return tr(lang, "cli", "context.list.addPrePrFindings");
7108
- }
7109
7185
  if (prePrReviewPolicy.enabled && (!f.docs.prePrEvidenceFieldExists || !f.prePrReview.evidenceProvided)) {
7110
7186
  return tr(lang, "cli", "context.list.addPrePrEvidence");
7111
7187
  }
7112
- if (prePrReviewPolicy.enabled && prePrReviewPolicy.blockOnFindings && (f.prePrReview.findings?.major || 0) > 0) {
7113
- return tr(lang, "cli", "context.list.resolvePrePrMajorFindings", {
7114
- count: f.prePrReview.findings?.major || 0
7115
- });
7116
- }
7117
- if (prePrReviewPolicy.enabled && prePrReviewPolicy.minorPolicy === "block" && (f.prePrReview.findings?.minor || 0) > 0) {
7118
- return tr(lang, "cli", "context.list.resolvePrePrMinorFindings", {
7119
- count: f.prePrReview.findings?.minor || 0
7120
- });
7188
+ if (prePrReviewPolicy.enabled && (!f.docs.prePrDecisionFieldExists || !f.prePrReview.decisionProvided)) {
7189
+ return tr(lang, "cli", "context.list.addPrePrDecision");
7121
7190
  }
7122
7191
  if (workflowPolicy.requirePr && !f.pr.link) {
7123
7192
  return tr(lang, "cli", "context.list.recordPrLink");
@@ -7125,12 +7194,12 @@ function getListLabel(f, stepsMap, lang, workflowPolicy, prePrReviewPolicy) {
7125
7194
  if (workflowPolicy.requireReview && !f.pr.status) {
7126
7195
  return tr(lang, "cli", "context.list.setPrStatus");
7127
7196
  }
7128
- if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewFindingsFieldExists || !f.prReview.findings)) {
7129
- return tr(lang, "cli", "context.list.addPrReviewFindings");
7130
- }
7131
- if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewEvidenceFieldExists || (f.prReview.findings?.major || 0) + (f.prReview.findings?.minor || 0) > 0 && !f.prReview.evidenceProvided)) {
7197
+ if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewEvidenceFieldExists || !f.prReview.evidenceProvided)) {
7132
7198
  return tr(lang, "cli", "context.list.addPrReviewEvidence");
7133
7199
  }
7200
+ if (workflowPolicy.requireReview && f.pr.status === "Review" && (!f.docs.prReviewDecisionFieldExists || !f.prReview.decisionProvided)) {
7201
+ return tr(lang, "cli", "context.list.addPrReviewDecision");
7202
+ }
7134
7203
  if (workflowPolicy.requireReview && f.pr.status !== "Approved") {
7135
7204
  return tr(lang, "cli", "context.list.prStatusToApproved", {
7136
7205
  status: f.pr.status
@@ -7175,11 +7244,13 @@ function toCompactFeature(feature) {
7175
7244
  prePrReview: {
7176
7245
  status: feature.prePrReview.status,
7177
7246
  findings: feature.prePrReview.findings,
7178
- evidenceProvided: feature.prePrReview.evidenceProvided
7247
+ evidenceProvided: feature.prePrReview.evidenceProvided,
7248
+ decisionProvided: feature.prePrReview.decisionProvided
7179
7249
  },
7180
7250
  prReview: {
7181
7251
  findings: feature.prReview.findings,
7182
- evidenceProvided: feature.prReview.evidenceProvided
7252
+ evidenceProvided: feature.prReview.evidenceProvided,
7253
+ decisionProvided: feature.prReview.decisionProvided
7183
7254
  },
7184
7255
  pr: {
7185
7256
  link: feature.pr.link,
@@ -7194,7 +7265,10 @@ function toCompactFeature(feature) {
7194
7265
  docsEverCommitted: feature.git.docsEverCommitted,
7195
7266
  docsHasUncommittedChanges: feature.git.docsHasUncommittedChanges,
7196
7267
  projectHasUncommittedChanges: feature.git.projectHasUncommittedChanges,
7197
- docsPathIgnored: feature.git.docsPathIgnored
7268
+ docsPathIgnored: feature.git.docsPathIgnored,
7269
+ projectHasUpstream: feature.git.projectHasUpstream,
7270
+ projectBranchAhead: feature.git.projectBranchAhead,
7271
+ projectBranchBehind: feature.git.projectBranchBehind
7198
7272
  },
7199
7273
  docs: {
7200
7274
  specExists: feature.docs.specExists,
@@ -7208,8 +7282,10 @@ function toCompactFeature(feature) {
7208
7282
  prePrReviewFieldExists: feature.docs.prePrReviewFieldExists,
7209
7283
  prePrFindingsFieldExists: feature.docs.prePrFindingsFieldExists,
7210
7284
  prePrEvidenceFieldExists: feature.docs.prePrEvidenceFieldExists,
7285
+ prePrDecisionFieldExists: feature.docs.prePrDecisionFieldExists,
7211
7286
  prReviewFindingsFieldExists: feature.docs.prReviewFindingsFieldExists,
7212
- prReviewEvidenceFieldExists: feature.docs.prReviewEvidenceFieldExists
7287
+ prReviewEvidenceFieldExists: feature.docs.prReviewEvidenceFieldExists,
7288
+ prReviewDecisionFieldExists: feature.docs.prReviewDecisionFieldExists
7213
7289
  },
7214
7290
  warnings: feature.warnings
7215
7291
  };
@@ -7341,6 +7417,8 @@ async function runContext(featureName, options) {
7341
7417
  config.projectType,
7342
7418
  selectedComponent
7343
7419
  );
7420
+ const activeCategories = listActiveCategories(state.actionOptions);
7421
+ const uncategorizedLabels = listUncategorizedLabels(state.actionOptions);
7344
7422
  if (options.jsonCompact) {
7345
7423
  const compactResult = {
7346
7424
  schema: "context.v2.compact",
@@ -7371,6 +7449,10 @@ async function runContext(featureName, options) {
7371
7449
  acceptedTokens: ["<LABEL>", "<LABEL> OK", "<LABEL> ...", "... <LABEL> ..."],
7372
7450
  tokenPattern: "^.*\\b([A-Z]+)\\b.*$",
7373
7451
  validLabels: state.actionOptions.map((o) => o.label),
7452
+ activeCategories,
7453
+ knownCategories: ACTION_CATEGORIES,
7454
+ uncategorizedLabels,
7455
+ categoryPolicyGuidance: 'For approval.mode="category", match against `actionOptions[].category`.',
7374
7456
  oneApprovalPerAction: true,
7375
7457
  requireFreshContext: true,
7376
7458
  contextVersion: state.contextVersion,
@@ -7438,6 +7520,10 @@ async function runContext(featureName, options) {
7438
7520
  acceptedTokens: ["<LABEL>", "<LABEL> OK", "<LABEL> ...", "... <LABEL> ..."],
7439
7521
  tokenPattern: "^.*\\b([A-Z]+)\\b.*$",
7440
7522
  validLabels: state.actionOptions.map((o) => o.label),
7523
+ activeCategories,
7524
+ knownCategories: ACTION_CATEGORIES,
7525
+ uncategorizedLabels,
7526
+ categoryPolicyGuidance: 'For approval.mode="category", match against `actionOptions[].category`.',
7441
7527
  requireExplanationBeforeApproval: true,
7442
7528
  requiredExplanationFields: [
7443
7529
  "actionOptions[].label",
@@ -7469,6 +7555,7 @@ async function runContext(featureName, options) {
7469
7555
  requiresRequestText: o.requiresRequestText,
7470
7556
  replyExample: o.replyExample,
7471
7557
  actionType: o.action.type,
7558
+ category: o.action.category,
7472
7559
  scope: o.action.type === "command" ? o.action.scope : void 0,
7473
7560
  cwd: o.action.type === "command" ? o.action.cwd : void 0,
7474
7561
  cmd: o.action.type === "command" ? o.action.cmd : void 0,
@@ -7791,7 +7878,7 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
7791
7878
  if (!parsedLabel) {
7792
7879
  throw createCliError(
7793
7880
  "INVALID_APPROVAL",
7794
- "Invalid approval reply. Include a valid label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`)."
7881
+ tr(lang, "cli", "cliError.invalidApproval.replyWithValidLabel")
7795
7882
  );
7796
7883
  }
7797
7884
  const selected = state.actionOptions.find((o) => o.label === parsedLabel);
@@ -8739,6 +8826,9 @@ async function runView(featureName, options) {
8739
8826
  }
8740
8827
  console.log();
8741
8828
  }
8829
+ var BUILTIN_AUTO_PRESETS = {
8830
+ "pr-handoff": ["pr_create", "code_review", "pr_status_update"]
8831
+ };
8742
8832
  function runSelfCli(args) {
8743
8833
  const entry = process.argv[1];
8744
8834
  const result = spawnSync(process.execPath, [entry, "--no-banner", ...args], {
@@ -8785,8 +8875,401 @@ function buildSelectionArgs(featureName, options) {
8785
8875
  if (options.done) args.push("--done");
8786
8876
  return args;
8787
8877
  }
8878
+ function normalizeAutoCategories(values, sourceLabel) {
8879
+ const requested = values.map((value) => value.trim()).filter(Boolean);
8880
+ if (requested.length === 0) {
8881
+ throw createCliError(
8882
+ "INVALID_ARGUMENT",
8883
+ `${sourceLabel} requires at least one category.`
8884
+ );
8885
+ }
8886
+ const deduped = [];
8887
+ const seen = /* @__PURE__ */ new Set();
8888
+ for (const category of requested) {
8889
+ if (seen.has(category)) continue;
8890
+ seen.add(category);
8891
+ deduped.push(category);
8892
+ }
8893
+ const allowed = new Set(ACTION_CATEGORIES);
8894
+ const invalid = deduped.filter((category) => !allowed.has(category));
8895
+ if (invalid.length > 0) {
8896
+ throw createCliError(
8897
+ "INVALID_ARGUMENT",
8898
+ `Unknown category in ${sourceLabel}: ${invalid.join(", ")}. Known categories: ${ACTION_CATEGORIES.join(", ")}`
8899
+ );
8900
+ }
8901
+ return deduped;
8902
+ }
8903
+ function parseAutoUntilCategories(raw) {
8904
+ return normalizeAutoCategories(raw.split(","), "`--auto-until-category`");
8905
+ }
8906
+ function normalizePresetName(raw) {
8907
+ return raw.trim().toLowerCase();
8908
+ }
8909
+ function resolveConfiguredPresetMap(config) {
8910
+ const presets = /* @__PURE__ */ new Map();
8911
+ for (const [name, categories] of Object.entries(BUILTIN_AUTO_PRESETS)) {
8912
+ presets.set(name, normalizeAutoCategories(categories, `builtin preset "${name}"`));
8913
+ }
8914
+ const configuredPresets = config.workflow?.auto?.presets;
8915
+ if (!configuredPresets || typeof configuredPresets !== "object") return presets;
8916
+ for (const [rawName, rawCategories] of Object.entries(configuredPresets)) {
8917
+ const name = normalizePresetName(rawName);
8918
+ if (!name) continue;
8919
+ if (!Array.isArray(rawCategories)) {
8920
+ throw createCliError(
8921
+ "INVALID_ARGUMENT",
8922
+ `workflow.auto.presets.${name} must be a string array of categories.`
8923
+ );
8924
+ }
8925
+ presets.set(
8926
+ name,
8927
+ normalizeAutoCategories(
8928
+ rawCategories.map((value) => String(value || "")),
8929
+ `workflow.auto.presets.${name}`
8930
+ )
8931
+ );
8932
+ }
8933
+ return presets;
8934
+ }
8935
+ function resolvePresetCategories(config, rawPresetName) {
8936
+ const presetName = normalizePresetName(rawPresetName);
8937
+ if (!presetName) {
8938
+ throw createCliError("INVALID_ARGUMENT", "`--auto-preset` requires a preset name.");
8939
+ }
8940
+ const presetMap = resolveConfiguredPresetMap(config);
8941
+ const categories = presetMap.get(presetName);
8942
+ if (!categories) {
8943
+ throw createCliError(
8944
+ "INVALID_ARGUMENT",
8945
+ `Unknown auto preset: ${presetName}. Known presets: ${[...presetMap.keys()].sort().join(", ")}`
8946
+ );
8947
+ }
8948
+ return {
8949
+ preset: presetName,
8950
+ categories
8951
+ };
8952
+ }
8953
+ function resolveConfigDefaultAutoMode(config) {
8954
+ const autoPolicy = config.workflow?.auto;
8955
+ if (!autoPolicy) return null;
8956
+ if (Array.isArray(autoPolicy.defaultUntilCategories) && autoPolicy.defaultUntilCategories.length > 0) {
8957
+ return {
8958
+ untilCategories: normalizeAutoCategories(
8959
+ autoPolicy.defaultUntilCategories.map((value) => String(value || "")),
8960
+ "workflow.auto.defaultUntilCategories"
8961
+ ),
8962
+ preset: null,
8963
+ source: "config:workflow.auto.defaultUntilCategories"
8964
+ };
8965
+ }
8966
+ const defaultPreset = normalizePresetName(autoPolicy.defaultPreset || "");
8967
+ if (!defaultPreset) return null;
8968
+ const resolved = resolvePresetCategories(config, defaultPreset);
8969
+ return {
8970
+ untilCategories: resolved.categories,
8971
+ preset: resolved.preset,
8972
+ source: "config:workflow.auto.defaultPreset"
8973
+ };
8974
+ }
8975
+ function resolveAutoMode(config, options, requestText) {
8976
+ if (options.autoUntilCategory) {
8977
+ return {
8978
+ untilCategories: parseAutoUntilCategories(options.autoUntilCategory),
8979
+ preset: null,
8980
+ source: "flag:--auto-until-category"
8981
+ };
8982
+ }
8983
+ if (options.autoPreset) {
8984
+ const resolved = resolvePresetCategories(config, options.autoPreset);
8985
+ return {
8986
+ untilCategories: resolved.categories,
8987
+ preset: resolved.preset,
8988
+ source: "flag:--auto-preset"
8989
+ };
8990
+ }
8991
+ if (requestText) {
8992
+ return resolveConfigDefaultAutoMode(config);
8993
+ }
8994
+ return null;
8995
+ }
8996
+ function toAutoReasonCode(status) {
8997
+ switch (status) {
8998
+ case "gate_reached":
8999
+ return "AUTO_GATE_REACHED";
9000
+ case "manual_required":
9001
+ return "AUTO_MANUAL_REQUIRED";
9002
+ case "no_action_options":
9003
+ return "AUTO_NO_ACTION_OPTIONS";
9004
+ case "selection_required":
9005
+ return "AUTO_SELECTION_REQUIRED";
9006
+ case "no_progress":
9007
+ return "AUTO_NO_PROGRESS";
9008
+ case "request_label_missing":
9009
+ return "AUTO_REQUEST_LABEL_MISSING";
9010
+ case "request_failed":
9011
+ return "AUTO_REQUEST_FAILED";
9012
+ case "execution_failed":
9013
+ default:
9014
+ return "AUTO_EXECUTION_FAILED";
9015
+ }
9016
+ }
9017
+ async function runAutoUntilCategory(config, featureName, selectionOptions, untilCategories, requestText, metadata) {
9018
+ const contextArgs = ["context", ...buildSelectionArgs(featureName, selectionOptions)];
9019
+ const gateSet = new Set(untilCategories);
9020
+ const executions = [];
9021
+ const stagnantLimit = 3;
9022
+ let stagnantCount = 0;
9023
+ let previousSignature = null;
9024
+ let requestHandled = !requestText;
9025
+ let iterations = 0;
9026
+ while (true) {
9027
+ iterations += 1;
9028
+ const state = await resolveContextSelection(config, featureName, selectionOptions);
9029
+ const actionOptions = state.actionOptions;
9030
+ const signature = JSON.stringify({
9031
+ contextVersion: state.contextVersion,
9032
+ actions: actionOptions.map((option) => ({
9033
+ label: option.label,
9034
+ category: option.action.category || null,
9035
+ type: option.action.type,
9036
+ detail: option.detail
9037
+ }))
9038
+ });
9039
+ if (signature === previousSignature) {
9040
+ stagnantCount += 1;
9041
+ } else {
9042
+ stagnantCount = 0;
9043
+ previousSignature = signature;
9044
+ }
9045
+ if (stagnantCount >= stagnantLimit) {
9046
+ return {
9047
+ enabled: true,
9048
+ untilCategories,
9049
+ request: requestText,
9050
+ preset: metadata?.preset ?? null,
9051
+ source: metadata?.source ?? null,
9052
+ status: "no_progress",
9053
+ reasonCode: toAutoReasonCode("no_progress"),
9054
+ iterations,
9055
+ executions,
9056
+ gate: null,
9057
+ manual: null,
9058
+ error: "Auto-run stopped because the same context/action set repeated without progress."
9059
+ };
9060
+ }
9061
+ if (state.status !== "single_matched" || !state.matchedFeature) {
9062
+ return {
9063
+ enabled: true,
9064
+ untilCategories,
9065
+ request: requestText,
9066
+ preset: metadata?.preset ?? null,
9067
+ source: metadata?.source ?? null,
9068
+ status: "selection_required",
9069
+ reasonCode: toAutoReasonCode("selection_required"),
9070
+ iterations,
9071
+ executions,
9072
+ gate: null,
9073
+ manual: null,
9074
+ error: "Auto-run requires a single matched feature. Specify the feature explicitly."
9075
+ };
9076
+ }
9077
+ if (actionOptions.length === 0) {
9078
+ return {
9079
+ enabled: true,
9080
+ untilCategories,
9081
+ request: requestText,
9082
+ preset: metadata?.preset ?? null,
9083
+ source: metadata?.source ?? null,
9084
+ status: "no_action_options",
9085
+ reasonCode: toAutoReasonCode("no_action_options"),
9086
+ iterations,
9087
+ executions,
9088
+ gate: null,
9089
+ manual: null
9090
+ };
9091
+ }
9092
+ if (!requestHandled) {
9093
+ const requestOption = actionOptions.find(
9094
+ (option) => option.action.category === "user_request_replan"
9095
+ );
9096
+ if (!requestOption) {
9097
+ return {
9098
+ enabled: true,
9099
+ untilCategories,
9100
+ request: requestText,
9101
+ preset: metadata?.preset ?? null,
9102
+ source: metadata?.source ?? null,
9103
+ status: "request_label_missing",
9104
+ reasonCode: toAutoReasonCode("request_label_missing"),
9105
+ iterations,
9106
+ executions,
9107
+ gate: null,
9108
+ manual: null,
9109
+ error: "The current action options do not include `user_request_replan`; cannot apply --request automatically."
9110
+ };
9111
+ }
9112
+ const approvalReply = `${requestOption.label}, ${requestText}`;
9113
+ const approveResult2 = runSelfCliJson(
9114
+ [...contextArgs, "--approve", approvalReply],
9115
+ true
9116
+ );
9117
+ const approveStatus2 = approveResult2?.status ?? "unknown";
9118
+ executions.push({
9119
+ kind: "request",
9120
+ iteration: iterations,
9121
+ contextVersion: state.contextVersion,
9122
+ label: requestOption.label,
9123
+ category: requestOption.action.category,
9124
+ detail: requestOption.detail,
9125
+ approveStatus: approveStatus2,
9126
+ executeStatus: "skipped_instruction",
9127
+ executeReasonCode: approveResult2?.reasonCode
9128
+ });
9129
+ if (approveStatus2 !== "approved_selected") {
9130
+ return {
9131
+ enabled: true,
9132
+ untilCategories,
9133
+ request: requestText,
9134
+ preset: metadata?.preset ?? null,
9135
+ source: metadata?.source ?? null,
9136
+ status: "request_failed",
9137
+ reasonCode: toAutoReasonCode("request_failed"),
9138
+ iterations,
9139
+ executions,
9140
+ gate: null,
9141
+ manual: null,
9142
+ error: approveResult2?.error || `Request injection failed with status: ${approveStatus2}`
9143
+ };
9144
+ }
9145
+ requestHandled = true;
9146
+ continue;
9147
+ }
9148
+ const gateOption = actionOptions.find(
9149
+ (option) => gateSet.has(option.action.category || "")
9150
+ );
9151
+ if (gateOption) {
9152
+ const contextPayload = runSelfCliJson(contextArgs, true);
9153
+ return {
9154
+ enabled: true,
9155
+ untilCategories,
9156
+ request: requestText,
9157
+ preset: metadata?.preset ?? null,
9158
+ source: metadata?.source ?? null,
9159
+ status: "gate_reached",
9160
+ reasonCode: toAutoReasonCode("gate_reached"),
9161
+ iterations,
9162
+ executions,
9163
+ gate: {
9164
+ label: gateOption.label,
9165
+ category: gateOption.action.category,
9166
+ detail: gateOption.detail,
9167
+ finalPrompt: contextPayload?.approvalRequest?.finalPrompt,
9168
+ userFacingLines: contextPayload?.approvalRequest?.userFacingLines
9169
+ },
9170
+ manual: null
9171
+ };
9172
+ }
9173
+ const executable = actionOptions.find((option) => option.action.type === "command");
9174
+ if (!executable) {
9175
+ return {
9176
+ enabled: true,
9177
+ untilCategories,
9178
+ request: requestText,
9179
+ preset: metadata?.preset ?? null,
9180
+ source: metadata?.source ?? null,
9181
+ status: "manual_required",
9182
+ reasonCode: toAutoReasonCode("manual_required"),
9183
+ iterations,
9184
+ executions,
9185
+ gate: null,
9186
+ manual: {
9187
+ label: actionOptions[0].label,
9188
+ category: actionOptions[0].action.category,
9189
+ detail: actionOptions[0].detail
9190
+ }
9191
+ };
9192
+ }
9193
+ const approveResult = runSelfCliJson(
9194
+ [...contextArgs, "--approve", executable.label],
9195
+ true
9196
+ );
9197
+ const approveStatus = approveResult?.status ?? "unknown";
9198
+ if (approveStatus !== "approved_selected") {
9199
+ executions.push({
9200
+ kind: "command",
9201
+ iteration: iterations,
9202
+ contextVersion: state.contextVersion,
9203
+ label: executable.label,
9204
+ category: executable.action.category,
9205
+ detail: executable.detail,
9206
+ approveStatus,
9207
+ executeStatus: "skipped",
9208
+ executeReasonCode: approveResult?.reasonCode
9209
+ });
9210
+ return {
9211
+ enabled: true,
9212
+ untilCategories,
9213
+ request: requestText,
9214
+ preset: metadata?.preset ?? null,
9215
+ source: metadata?.source ?? null,
9216
+ status: "execution_failed",
9217
+ reasonCode: toAutoReasonCode("execution_failed"),
9218
+ iterations,
9219
+ executions,
9220
+ gate: null,
9221
+ manual: null,
9222
+ error: approveResult?.error || `Auto approval failed for label ${executable.label} (${approveStatus}).`
9223
+ };
9224
+ }
9225
+ const executeArgs = [
9226
+ ...contextArgs,
9227
+ "--approve",
9228
+ executable.label,
9229
+ "--execute"
9230
+ ];
9231
+ if (approveResult?.executeRequiresTicket && approveResult.approvalTicket?.token) {
9232
+ executeArgs.push("--ticket", approveResult.approvalTicket.token);
9233
+ }
9234
+ const executeResult = runSelfCliJson(executeArgs, true);
9235
+ executions.push({
9236
+ kind: "command",
9237
+ iteration: iterations,
9238
+ contextVersion: state.contextVersion,
9239
+ label: executable.label,
9240
+ category: executable.action.category,
9241
+ detail: executable.detail,
9242
+ approveStatus,
9243
+ executeStatus: executeResult?.status ?? "unknown",
9244
+ executeReasonCode: executeResult?.reasonCode
9245
+ });
9246
+ if (executeResult?.status !== "approved_executed") {
9247
+ return {
9248
+ enabled: true,
9249
+ untilCategories,
9250
+ request: requestText,
9251
+ status: "execution_failed",
9252
+ reasonCode: toAutoReasonCode("execution_failed"),
9253
+ iterations,
9254
+ executions,
9255
+ gate: null,
9256
+ manual: null,
9257
+ error: executeResult?.error || `Auto execution failed for label ${executable.label} (${executeResult?.status ?? "unknown"}).`
9258
+ };
9259
+ }
9260
+ }
9261
+ }
8788
9262
  function flowCommand(program2) {
8789
9263
  program2.command("flow [feature-name]").description("Run combined workflow checks (context + status + doctor)").option("--json", "Output in JSON format for agents").option("--component <component>", "Component name for multi projects").option("--all", "Include completed features when auto-detecting").option("--done", "Show completed (workflow-done) features only").option(
9264
+ "--request <text>",
9265
+ "Apply a new user request first via user_request_replan when auto mode is enabled"
9266
+ ).option(
9267
+ "--auto-preset <name>",
9268
+ "Auto-run command actions using a named preset (example: pr-handoff)"
9269
+ ).option(
9270
+ "--auto-until-category <categories>",
9271
+ "Auto-run command actions until one of categories appears (comma-separated)"
9272
+ ).option(
8790
9273
  "--approve <reply>",
8791
9274
  "Approve one labeled context option (examples: A, A OK, A proceed, A \uC9C4\uD589\uD574)"
8792
9275
  ).option("--execute", "Execute approved option when it is a command").option(
@@ -8841,6 +9324,38 @@ async function runFlow(featureName, options) {
8841
9324
  "`--execute` requires `--approve <reply>`."
8842
9325
  );
8843
9326
  }
9327
+ const requestText = options.request?.trim() || void 0;
9328
+ if (options.autoPreset && options.autoUntilCategory) {
9329
+ throw createCliError(
9330
+ "INVALID_ARGUMENT",
9331
+ "`--auto-preset` cannot be combined with `--auto-until-category`."
9332
+ );
9333
+ }
9334
+ const autoMode = resolveAutoMode(config, options, requestText);
9335
+ if (autoMode && options.approve) {
9336
+ throw createCliError(
9337
+ "INVALID_ARGUMENT",
9338
+ "Auto mode cannot be combined with `--approve`."
9339
+ );
9340
+ }
9341
+ if (autoMode && options.execute) {
9342
+ throw createCliError(
9343
+ "INVALID_ARGUMENT",
9344
+ "Auto mode cannot be combined with `--execute`."
9345
+ );
9346
+ }
9347
+ if (requestText && !autoMode) {
9348
+ throw createCliError(
9349
+ "INVALID_ARGUMENT",
9350
+ "`--request` requires auto mode. Use `--auto-until-category`, `--auto-preset`, or configure `workflow.auto.defaultPreset`."
9351
+ );
9352
+ }
9353
+ if (autoMode && !featureName) {
9354
+ throw createCliError(
9355
+ "CONTEXT_SELECTION_REQUIRED",
9356
+ "Auto mode requires explicit <feature-name> (e.g. F004)."
9357
+ );
9358
+ }
8844
9359
  const selectedComponent = resolveComponentOption(options.component);
8845
9360
  const selectionOptions = {
8846
9361
  component: selectedComponent,
@@ -8849,9 +9364,19 @@ async function runFlow(featureName, options) {
8849
9364
  };
8850
9365
  const componentHint = selectedComponent ? ` --component ${selectedComponent}` : "";
8851
9366
  const before = await resolveContextSelection(config, featureName, selectionOptions);
8852
- const contextArgs = ["context", ...buildSelectionArgs(featureName, selectionOptions)];
8853
9367
  let approvalResult = null;
8854
- if (options.approve) {
9368
+ let autoRun = null;
9369
+ const contextArgs = ["context", ...buildSelectionArgs(featureName, selectionOptions)];
9370
+ if (autoMode) {
9371
+ autoRun = await runAutoUntilCategory(
9372
+ config,
9373
+ featureName,
9374
+ selectionOptions,
9375
+ autoMode.untilCategories,
9376
+ requestText,
9377
+ { preset: autoMode.preset, source: autoMode.source }
9378
+ );
9379
+ } else if (options.approve) {
8855
9380
  const approveArgs = [...contextArgs, "--approve", options.approve];
8856
9381
  const selected = runSelfCliJson(approveArgs, true);
8857
9382
  if (options.execute) {
@@ -8921,6 +9446,7 @@ async function runFlow(featureName, options) {
8921
9446
  }
8922
9447
  },
8923
9448
  approval: approvalResult,
9449
+ autoRun,
8924
9450
  statusReport,
8925
9451
  doctorReport,
8926
9452
  strictChecks,
@@ -8944,6 +9470,14 @@ async function runFlow(featureName, options) {
8944
9470
  )
8945
9471
  );
8946
9472
  }
9473
+ if (autoRun) {
9474
+ const presetSuffix = autoRun.preset ? `, preset ${autoRun.preset}` : "";
9475
+ console.log(
9476
+ chalk6.gray(
9477
+ `- Auto: ${autoRun.status} (${autoRun.reasonCode}), iterations ${autoRun.iterations}, executions ${autoRun.executions.length}${presetSuffix}`
9478
+ )
9479
+ );
9480
+ }
8947
9481
  const statusCounts = statusReport.counts;
8948
9482
  const doctorCounts = doctorReport.counts;
8949
9483
  console.log(chalk6.gray(`- Status features: ${statusCounts?.features ?? 0}`));
@@ -8957,6 +9491,13 @@ async function runFlow(featureName, options) {
8957
9491
  console.log(chalk6.gray(`- Strict checks: ${strictLabel}`));
8958
9492
  }
8959
9493
  console.log();
9494
+ if (autoRun?.status === "gate_reached" && autoRun.gate?.userFacingLines?.length) {
9495
+ for (const line of autoRun.gate.userFacingLines) {
9496
+ console.log(line);
9497
+ }
9498
+ console.log(chalk6.gray("Auto gate reached. Reply with one of the labels shown above (example: A OK)."));
9499
+ console.log();
9500
+ }
8960
9501
  if (after.matchedFeature) {
8961
9502
  console.log(
8962
9503
  chalk6.blue(
@@ -10439,9 +10980,11 @@ function githubCommand(program2) {
10439
10980
  const overview = resolveOverviewFromSpec(specContent, feature, config.lang);
10440
10981
  const defaultTitle = feature.issueNumber ? tg(config.lang, "prDefaultTitleWithIssue", {
10441
10982
  issue: feature.issueNumber,
10442
- slug: feature.slug
10983
+ slug: feature.slug,
10984
+ featureRef: feature.folderName
10443
10985
  }) : tg(config.lang, "prDefaultTitleNoIssue", {
10444
- slug: feature.slug
10986
+ slug: feature.slug,
10987
+ featureRef: feature.folderName
10445
10988
  });
10446
10989
  const artifactPolicy = resolvePrArtifactPolicy(config, options);
10447
10990
  const generatedBody = buildPrBody(