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/README.en.md +45 -7
- package/README.md +45 -7
- package/dist/index.js +805 -262
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/en/common/agents/skills/create-pr.md +2 -2
- package/templates/en/common/features/README.md +3 -3
- package/templates/en/common/features/feature-base/tasks.md +4 -4
- package/templates/ko/common/agents/skills/create-pr.md +2 -2
- package/templates/ko/common/features/README.md +3 -3
- package/templates/ko/common/features/feature-base/tasks.md +4 -4
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 \
|
|
159
|
-
"context.actionOptionHint": "\
|
|
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 \
|
|
162
|
-
"context.finalLabelPromptWithRequest": "\uD604\uC7AC \uC120\uD0DD \uAC00\uB2A5\uD55C \uB77C\uBCA8: {labels}. \uB77C\uBCA8 \
|
|
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 \
|
|
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 \
|
|
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 \
|
|
173
|
-
"context.actionDetail.issueCreate": "\uC774\uC288 \
|
|
174
|
-
"context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C
|
|
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": "
|
|
177
|
-
"context.actionDetail.prCreate": "PR\uC744 \
|
|
178
|
-
"context.actionDetail.prStatusUpdate": "tasks.md\uC758 PR \uC0C1\uD0DC \
|
|
179
|
-
"context.actionDetail.codeReview": "\uB9AC\uBDF0 \
|
|
180
|
-
"context.actionDetail.worktreeCleanup": "
|
|
181
|
-
"context.actionDetail.prMetadataMigrate": "tasks.md\uC758 PR \
|
|
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 \
|
|
184
|
-
"context.actionDetail.fallback": "\uD604\uC7AC \
|
|
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.
|
|
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.
|
|
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
|
|
330
|
-
"github.prDefaultTitleNoIssue": "feat: {slug} (\uAD6C\uD604
|
|
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
|
-
|
|
502
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
644
|
-
"context.actionOptionHint": "
|
|
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
|
|
647
|
-
"context.finalLabelPromptWithRequest": "Available labels now: {labels}. Reply
|
|
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": "
|
|
657
|
+
"context.actionDetail.specApprove": "Approve spec.md",
|
|
654
658
|
"context.actionDetail.planWrite": "Write or refine plan.md and set status",
|
|
655
|
-
"context.actionDetail.planApprove": "
|
|
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": "
|
|
658
|
-
"context.actionDetail.issueCreate": "
|
|
659
|
-
"context.actionDetail.taskExecute": "Proceed with the current task
|
|
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": "
|
|
662
|
-
"context.actionDetail.prCreate": "
|
|
663
|
-
"context.actionDetail.prStatusUpdate": "
|
|
664
|
-
"context.actionDetail.codeReview": "Address review
|
|
665
|
-
"context.actionDetail.worktreeCleanup": "
|
|
666
|
-
"context.actionDetail.prMetadataMigrate": "
|
|
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
|
|
669
|
-
"context.actionDetail.fallback": "
|
|
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.
|
|
692
|
+
"context.list.addPrePrDecision": "Add Pre-PR Decision",
|
|
690
693
|
"context.list.addPrReviewEvidence": "Add PR Review Evidence summary",
|
|
691
|
-
"context.list.
|
|
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
|
|
815
|
-
"github.prDefaultTitleNoIssue": "feat: {slug} (implementation
|
|
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
|
-
|
|
987
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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", "
|
|
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.
|
|
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", "
|
|
3960
|
+
message: tr(lang, "messages", "prReviewEvidenceFieldMissing")
|
|
3997
3961
|
}
|
|
3998
3962
|
];
|
|
3999
3963
|
}
|
|
4000
|
-
if (!f.prReview.
|
|
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", "
|
|
3970
|
+
message: tr(lang, "messages", "prReviewEvidenceMissing")
|
|
4007
3971
|
}
|
|
4008
3972
|
];
|
|
4009
3973
|
}
|
|
4010
|
-
if (!f.docs.
|
|
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", "
|
|
3980
|
+
message: tr(lang, "messages", "prReviewDecisionFieldMissing")
|
|
4017
3981
|
}
|
|
4018
3982
|
];
|
|
4019
3983
|
}
|
|
4020
|
-
if (
|
|
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", "
|
|
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
|
-
|
|
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")
|
|
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 (
|
|
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 {
|
|
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 (
|
|
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 &&
|
|
5139
|
-
warnings.push(tr(lang, "warnings", "
|
|
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
|
-
|
|
5177
|
-
|
|
5235
|
+
prePrEvidenceFieldExists,
|
|
5236
|
+
prePrDecisionFieldExists
|
|
5178
5237
|
},
|
|
5179
5238
|
prePrReview: {
|
|
5180
5239
|
status: prePrReviewStatus,
|
|
5181
|
-
|
|
5182
|
-
|
|
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 (!
|
|
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 (
|
|
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
|
-
|
|
6229
|
-
if (
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
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
|
|
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
|
|
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
|
|
6323
|
+
return tr(lang, "cli", "context.commandDetail.branchCreateWithBranch", {
|
|
6324
|
+
scope: action.scope,
|
|
6325
|
+
branch
|
|
6326
|
+
});
|
|
6267
6327
|
}
|
|
6268
|
-
return
|
|
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
|
|
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
|
|
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 &&
|
|
7113
|
-
return tr(lang, "cli", "context.list.
|
|
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.
|
|
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
|
-
"
|
|
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
|
-
|
|
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(
|