lee-spec-kit 0.6.28 → 0.6.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +208 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/en/common/agents/agents.md +3 -0
- package/templates/en/common/agents/skills/create-issue.md +1 -1
- package/templates/en/common/agents/skills/execute-task.md +3 -0
- package/templates/ko/common/agents/agents.md +3 -0
- package/templates/ko/common/agents/skills/create-issue.md +1 -1
- package/templates/ko/common/agents/skills/execute-task.md +3 -0
package/dist/index.js
CHANGED
|
@@ -186,7 +186,7 @@ var ko = {
|
|
|
186
186
|
"context.actionDetail.tasksWriteImprove": "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C \uC815\uB82C\uD558\uC138\uC694",
|
|
187
187
|
"context.actionDetail.tasksApprove": "tasks.md\uB97C \uC2B9\uC778\uD569\uB2C8\uB2E4",
|
|
188
188
|
"context.actionDetail.issueCreate": "\uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 tasks.md\uC758 \uC774\uC288 \uC815\uBCF4\uB97C \uB9DE\uCD94\uC138\uC694",
|
|
189
|
-
"context.actionDetail.issueCreateAndWrite": "\uC774\uC288 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC2B9\uC778(OK) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD574 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
|
|
189
|
+
"context.actionDetail.issueCreateAndWrite": "\uC774\uC288 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uB77C\uBCA8 \uC2B9\uC778(`A` \uB610\uB294 `A OK`) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD574 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
|
|
190
190
|
"context.actionDetail.issueCreatePrepareFromDoc": "issue.md \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uC0C1\uD0DC\uB97C Ready\uB85C \uC124\uC815\uD558\uC138\uC694",
|
|
191
191
|
"context.actionDetail.issueCreateFromDoc": "Ready \uC0C1\uD0DC issue.md\uB85C \uC774\uC288\uB97C \uC0DD\uC131\uD558\uACE0 \uBC88\uD638\uB97C \uB3D9\uAE30\uD654\uD558\uC138\uC694",
|
|
192
192
|
"context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
@@ -504,8 +504,8 @@ var ko = {
|
|
|
504
504
|
tasksImprove: "tasks.md\uB97C \uBCF4\uC644\uD558\uACE0 \uBB38\uC11C \uC0C1\uD0DC\uB97C Review\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
505
505
|
tasksApproval: "tasks.md \uB0B4\uC6A9\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uACF5\uC720\uD558\uACE0 \uC9C4\uD589 \uC2B9\uC778(`A` \uB610\uB294 `A OK` \uD615\uC2DD)\uC744 \uBC1B\uC73C\uC138\uC694. (\uC2B9\uC778 \uD6C4 \uBB38\uC11C \uC0C1\uD0DC\uB97C Approved\uB85C \uBCC0\uACBD)",
|
|
506
506
|
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} \uAE30\uD68D \uBB38\uC11C"',
|
|
507
|
-
issueCreateAndWrite: "\uC774\uC288 \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \
|
|
508
|
-
issuePrepareFromDoc: "`issue.md`\uB97C \uAE30\uC900\uC73C\uB85C \uC774\uC288 \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \
|
|
507
|
+
issueCreateAndWrite: "\uC774\uC288 \uBCF8\uBB38 \uD15C\uD50C\uB9BF\uC744 \uC0DD\uC131\uD574 \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0, \uB77C\uBCA8 \uC2B9\uC778(`A` \uB610\uB294 `A OK`) \uD6C4 \uC774\uC288\uB97C \uC0DD\uC131\uD558\uC138\uC694. \uC774\uD6C4 tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694.",
|
|
508
|
+
issuePrepareFromDoc: "`issue.md`\uB97C \uAE30\uC900\uC73C\uB85C \uC774\uC288 \uC81C\uBAA9/\uBCF8\uBB38/\uB77C\uBCA8 \uCD08\uC548\uC744 \uBCF4\uC644\uD558\uACE0 \uB77C\uBCA8 \uC2B9\uC778(`A` \uB610\uB294 `A OK`)\uC744 \uBC1B\uC544 \uC0C1\uD0DC\uB97C `Ready`\uB85C \uBCC0\uACBD\uD558\uC138\uC694.",
|
|
509
509
|
issueCreateFromDoc: "`issue.md` \uC0C1\uD0DC\uAC00 `Ready`\uC774\uBA74 GitHub Issue\uB97C \uC0DD\uC131\uD558\uACE0, \uC0DD\uC131\uB41C \uC774\uC288 \uBC88\uD638\uB97C `tasks.md`\uC5D0 \uBC18\uC601\uD558\uC138\uC694.",
|
|
510
510
|
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
|
|
511
511
|
docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
|
|
@@ -529,7 +529,7 @@ var ko = {
|
|
|
529
529
|
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",
|
|
530
530
|
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)",
|
|
531
531
|
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)",
|
|
532
|
-
prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC2E4\uC81C \uD30C\uC77C \uACBD\uB85C\uC640 `Pre-PR Review Log`(\uB610\uB294 `PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`)\
|
|
532
|
+
prePrReviewEvidenceMissing: "tasks.md\uC758 `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC2E4\uC81C \uD30C\uC77C \uACBD\uB85C\uC640 `Pre-PR Review Log`(\uB610\uB294 `PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`)\uC5D0 placeholder\uAC00 \uC544\uB2CC `Summary`/`Decision`/`Findings`(\uB610\uB294 \uBA85\uC2DC\uC801 `0 findings`)/`Residual Risks`/`Tests Run`\uC744 \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
533
533
|
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)",
|
|
534
534
|
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.",
|
|
535
535
|
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)",
|
|
@@ -588,7 +588,7 @@ var ko = {
|
|
|
588
588
|
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.",
|
|
589
589
|
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.)",
|
|
590
590
|
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.)",
|
|
591
|
-
workflowPrePrEvidenceMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`Pre-PR Review Log`/`PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`\
|
|
591
|
+
workflowPrePrEvidenceMissing: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Evidence`\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. (`Pre-PR Review Log`/`PR \uC804 \uB9AC\uBDF0 \uB85C\uADF8`\uC5D0 placeholder\uAC00 \uC544\uB2CC `Summary`/`Decision`/`Findings`(\uB610\uB294 \uBA85\uC2DC\uC801 `0 findings`)/`Residual Risks`/`Tests Run`\uC774 \uC788\uB294 \uC2E4\uC81C \uACBD\uB85C\uB97C \uAE30\uB85D\uD558\uC138\uC694.)",
|
|
592
592
|
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. (`decision: approve|changes_requested|blocked ...` \uD615\uC2DD)",
|
|
593
593
|
workflowPrePrDecisionNotApproved: "\uC644\uB8CC \uC0C1\uD0DC\uC774\uC9C0\uB9CC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{outcome}`\uC785\uB2C8\uB2E4. \uB9AC\uBDF0 \uB9AC\uC2A4\uD06C\uB97C \uD574\uC18C\uD55C \uB4A4 pre-pr-review\uB97C \uC7AC\uC2E4\uD589\uD574 `approve`\uB85C \uB9DE\uCD94\uC138\uC694."
|
|
594
594
|
}
|
|
@@ -1015,8 +1015,8 @@ var en = {
|
|
|
1015
1015
|
tasksImprove: "Improve tasks.md and change Doc Status to Review.",
|
|
1016
1016
|
tasksApproval: "Share tasks.md with the user and get progress approval (`A` or `A OK` format). (Then set Doc Status to Approved)",
|
|
1017
1017
|
docsCommitPlanning: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(planning): {folderName} planning docs"',
|
|
1018
|
-
issueCreateAndWrite: "Generate the issue body template, refine goals/completion criteria, get
|
|
1019
|
-
issuePrepareFromDoc: "Use `issue.md` to refine issue title/body/labels draft, get
|
|
1018
|
+
issueCreateAndWrite: "Generate the issue body template, refine goals/completion criteria, get label approval (`A` or `A OK`), create the issue, then update issue number in tasks.md and prepare a docs commit.",
|
|
1019
|
+
issuePrepareFromDoc: "Use `issue.md` to refine issue title/body/labels draft, get label approval (`A` or `A OK`), then set status to `Ready`.",
|
|
1020
1020
|
issueCreateFromDoc: "When `issue.md` status is `Ready`, create the GitHub Issue and sync the created issue number into `tasks.md`.",
|
|
1021
1021
|
docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
|
|
1022
1022
|
docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} docs update"',
|
|
@@ -1040,7 +1040,7 @@ var en = {
|
|
|
1040
1040
|
taskCommitGateReasonMismatchLastDone: "The latest project code commit does not match the last completed task",
|
|
1041
1041
|
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
|
|
1042
1042
|
prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Done` and run context again. (CHECK required)",
|
|
1043
|
-
prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty/invalid. Point to a real file and include a `Pre-PR Review Log` section with non-placeholder `Summary` and `
|
|
1043
|
+
prePrReviewEvidenceMissing: "tasks.md `Pre-PR Evidence` is empty/invalid. Point to a real file and include a `Pre-PR Review Log` section with non-placeholder `Summary`, `Decision`, `Findings` (or explicit `0 findings`), `Residual Risks`, and `Tests Run`. (CHECK required)",
|
|
1044
1044
|
prePrReviewDecisionMissing: "tasks.md `Pre-PR Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
|
|
1045
1045
|
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.",
|
|
1046
1046
|
prReviewEvidenceFieldMissing: "tasks.md is missing the `PR Review Evidence` field. Add `- **PR Review Evidence**: -` and continue. (CHECK required)",
|
|
@@ -1099,7 +1099,7 @@ var en = {
|
|
|
1099
1099
|
workflowPrRemoteChecksPending: "Remote PR has {count} pending check(s). Wait for checks to complete, then re-check.",
|
|
1100
1100
|
workflowPrePrReviewMissing: "Implementation is done but `Pre-PR Review` is missing. (Add `- **Pre-PR Review**: Pending | Done` in tasks.md.)",
|
|
1101
1101
|
workflowPrePrReviewNotDone: "Implementation is done but `Pre-PR Review` is not Done. (Run pre-PR review, then update it to Done.)",
|
|
1102
|
-
workflowPrePrEvidenceMissing: "Implementation is done but `Pre-PR Evidence` is empty/invalid. (Point to an existing file and include `Pre-PR Review Log` with non-placeholder `Summary` and `
|
|
1102
|
+
workflowPrePrEvidenceMissing: "Implementation is done but `Pre-PR Evidence` is empty/invalid. (Point to an existing file and include `Pre-PR Review Log` with non-placeholder `Summary`, `Decision`, `Findings` (or explicit `0 findings`), `Residual Risks`, and `Tests Run`.)",
|
|
1103
1103
|
workflowPrePrDecisionMissing: "Implementation is done but `Pre-PR Decision` is empty/invalid. (Use `decision: approve|changes_requested|blocked ...`.)",
|
|
1104
1104
|
workflowPrePrDecisionNotApproved: "Implementation is done but `Pre-PR Decision` is `{outcome}`. Resolve review risks and re-run pre-PR review until decision becomes `approve`."
|
|
1105
1105
|
}
|
|
@@ -4699,17 +4699,62 @@ function hasReviewLogQuality(content, headerRegex, summaryKeys, decisionKeys) {
|
|
|
4699
4699
|
}
|
|
4700
4700
|
return false;
|
|
4701
4701
|
}
|
|
4702
|
+
function isExplicitZeroFindingsEntry(value) {
|
|
4703
|
+
const trimmed = value.trim().toLowerCase();
|
|
4704
|
+
if (!trimmed) return false;
|
|
4705
|
+
return /^0+\s*findings?\b/.test(trimmed) || /^no\s+findings?\b/.test(trimmed) || /^findings?\s*[::]\s*0+\b/.test(trimmed) || /^지적\s*사항?\s*[::]?\s*0+\b/.test(trimmed) || /^지적\s*없음\b/.test(trimmed);
|
|
4706
|
+
}
|
|
4707
|
+
function hasPrePrReviewLogQuality(content) {
|
|
4708
|
+
const sections = splitReviewLogSections(content, PRE_PR_REVIEW_LOG_HEADER);
|
|
4709
|
+
for (const section of sections) {
|
|
4710
|
+
const summaryEntries = collectStructuredReviewEntries(section, [
|
|
4711
|
+
"Summary",
|
|
4712
|
+
"\uC694\uC57D",
|
|
4713
|
+
"Note",
|
|
4714
|
+
"\uB178\uD2B8"
|
|
4715
|
+
]);
|
|
4716
|
+
if (!hasValidReviewLogEntries(summaryEntries)) continue;
|
|
4717
|
+
const decisionEntries = collectStructuredReviewEntries(section, [
|
|
4718
|
+
"Decision",
|
|
4719
|
+
"\uACB0\uC815"
|
|
4720
|
+
]);
|
|
4721
|
+
if (!hasValidReviewLogEntries(decisionEntries)) continue;
|
|
4722
|
+
const findingsEntries = collectStructuredReviewEntries(section, [
|
|
4723
|
+
"Findings",
|
|
4724
|
+
"\uC9C0\uC801\uC0AC\uD56D",
|
|
4725
|
+
"\uC9C0\uC801 \uC0AC\uD56D"
|
|
4726
|
+
]);
|
|
4727
|
+
const hasActionableFindings = findingsEntries.map((entry) => entry.trim()).some(
|
|
4728
|
+
(entry) => entry.length > 0 && !isReviewDraftPlaceholder(entry) && !isPlaceholderReviewEvidence(entry) && /\S+:\d+/.test(entry)
|
|
4729
|
+
);
|
|
4730
|
+
const hasExplicitZeroFindings = findingsEntries.some(
|
|
4731
|
+
(entry) => isExplicitZeroFindingsEntry(entry)
|
|
4732
|
+
);
|
|
4733
|
+
if (!hasActionableFindings && !hasExplicitZeroFindings) continue;
|
|
4734
|
+
const residualRiskEntries = collectStructuredReviewEntries(section, [
|
|
4735
|
+
"Residual Risks",
|
|
4736
|
+
"Residual Risk",
|
|
4737
|
+
"\uC794\uC5EC \uB9AC\uC2A4\uD06C",
|
|
4738
|
+
"\uC794\uC5EC \uC704\uD5D8"
|
|
4739
|
+
]);
|
|
4740
|
+
if (!hasValidReviewLogEntries(residualRiskEntries)) continue;
|
|
4741
|
+
const testsRunEntries = collectStructuredReviewEntries(section, [
|
|
4742
|
+
"Tests Run",
|
|
4743
|
+
"Test Run",
|
|
4744
|
+
"\uC2E4\uD589 \uD14C\uC2A4\uD2B8",
|
|
4745
|
+
"\uD14C\uC2A4\uD2B8 \uC2E4\uD589"
|
|
4746
|
+
]);
|
|
4747
|
+
if (!hasValidReviewLogEntries(testsRunEntries)) continue;
|
|
4748
|
+
return true;
|
|
4749
|
+
}
|
|
4750
|
+
return false;
|
|
4751
|
+
}
|
|
4702
4752
|
var PRE_PR_REVIEW_LOG_HEADER = /^##\s+(?:Pre-PR Review Log|PR 전 리뷰 로그)\b.*$/gim;
|
|
4703
4753
|
var PR_REVIEW_LOG_HEADER = /^##\s+(?:PR Review Log|PR 리뷰 로그)\b.*$/gim;
|
|
4704
4754
|
async function hasPrePrReviewLogEvidence(candidatePath) {
|
|
4705
4755
|
try {
|
|
4706
4756
|
const content = await fs17.readFile(candidatePath, "utf-8");
|
|
4707
|
-
return
|
|
4708
|
-
content,
|
|
4709
|
-
PRE_PR_REVIEW_LOG_HEADER,
|
|
4710
|
-
["Summary", "\uC694\uC57D", "Note", "\uB178\uD2B8"],
|
|
4711
|
-
["Decision", "\uACB0\uC815"]
|
|
4712
|
-
);
|
|
4757
|
+
return hasPrePrReviewLogQuality(content);
|
|
4713
4758
|
} catch {
|
|
4714
4759
|
return false;
|
|
4715
4760
|
}
|
|
@@ -6862,7 +6907,7 @@ function getApprovalSessionId() {
|
|
|
6862
6907
|
if (explicit) return explicit;
|
|
6863
6908
|
const terminalSession = (process.env.TERM_SESSION_ID || process.env.WT_SESSION || process.env.TMUX_PANE || "").trim();
|
|
6864
6909
|
if (terminalSession) return terminalSession;
|
|
6865
|
-
return
|
|
6910
|
+
return "";
|
|
6866
6911
|
}
|
|
6867
6912
|
function getApprovalTicketPaths(config) {
|
|
6868
6913
|
return {
|
|
@@ -7004,7 +7049,7 @@ async function consumeApprovalTicket(config, token, expected) {
|
|
|
7004
7049
|
"Approval ticket expired. Run `context` again and re-approve."
|
|
7005
7050
|
);
|
|
7006
7051
|
}
|
|
7007
|
-
if (record.sessionId !== sessionId) {
|
|
7052
|
+
if (record.sessionId && record.sessionId !== sessionId) {
|
|
7008
7053
|
throw createCliError(
|
|
7009
7054
|
"INVALID_APPROVAL",
|
|
7010
7055
|
"Approval ticket session mismatch. Re-run `context` in the current session and approve again."
|
|
@@ -7198,17 +7243,38 @@ var LONG_RUNNING_DELEGATION_CATEGORIES = [
|
|
|
7198
7243
|
"review_fix_commit",
|
|
7199
7244
|
"pre_pr_review"
|
|
7200
7245
|
];
|
|
7201
|
-
function
|
|
7202
|
-
|
|
7246
|
+
function isTaskExecuteProjectCommitCommand(option) {
|
|
7247
|
+
if (!option || option.action.type !== "command") return false;
|
|
7248
|
+
if (option.action.category !== "task_execute") return false;
|
|
7249
|
+
if (option.action.scope !== "project") return false;
|
|
7250
|
+
return /\bgit\s+commit\b/i.test(option.action.cmd);
|
|
7251
|
+
}
|
|
7252
|
+
function shouldDelegateCurrentAction(actionOptions) {
|
|
7253
|
+
const primaryOption = actionOptions[0];
|
|
7254
|
+
const primaryCategory = primaryOption?.action?.category || null;
|
|
7203
7255
|
const longRunningSet = new Set(LONG_RUNNING_DELEGATION_CATEGORIES);
|
|
7204
|
-
const shouldDelegate =
|
|
7256
|
+
const shouldDelegate = !!primaryCategory && longRunningSet.has(primaryCategory) && !isTaskExecuteProjectCommitCommand(primaryOption);
|
|
7205
7257
|
return {
|
|
7206
7258
|
shouldDelegate,
|
|
7207
7259
|
category: primaryCategory
|
|
7208
7260
|
};
|
|
7209
7261
|
}
|
|
7210
|
-
function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable) {
|
|
7211
|
-
const delegation = shouldDelegateCurrentAction(actionOptions
|
|
7262
|
+
function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable, autoRunCommand, featureRef) {
|
|
7263
|
+
const delegation = shouldDelegateCurrentAction(actionOptions);
|
|
7264
|
+
const primaryOption = actionOptions[0];
|
|
7265
|
+
const delegatedCommandOption = primaryOption && primaryOption.action.type === "command" && delegation.shouldDelegate ? primaryOption : null;
|
|
7266
|
+
const handoffMode = delegatedCommandOption ? "command" : autoRunAvailable ? "auto_run" : null;
|
|
7267
|
+
const handoffCwd = delegatedCommandOption?.action.cwd || (autoRunAvailable ? process.cwd() : null);
|
|
7268
|
+
const handoffCmd = delegatedCommandOption?.action.cmd || (autoRunAvailable ? autoRunCommand : null);
|
|
7269
|
+
const handoffRequired = !!handoffMode && !!handoffCwd && !!handoffCmd;
|
|
7270
|
+
const verifyCacheKey = handoffRequired ? createHash("sha1").update(
|
|
7271
|
+
[
|
|
7272
|
+
handoffMode,
|
|
7273
|
+
featureRef || "",
|
|
7274
|
+
handoffCwd || "",
|
|
7275
|
+
handoffCmd || ""
|
|
7276
|
+
].join("|")
|
|
7277
|
+
).digest("hex").slice(0, 12) : "";
|
|
7212
7278
|
return {
|
|
7213
7279
|
mode: "main_orchestrates_subagent_execution",
|
|
7214
7280
|
delegationPolicy: "prefer_main_delegate_long_running_fallback_main",
|
|
@@ -7217,6 +7283,7 @@ function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable) {
|
|
|
7217
7283
|
fallbackToMainAgentWhenSubAgentUnavailable: true,
|
|
7218
7284
|
longRunningCategories: [...LONG_RUNNING_DELEGATION_CATEGORIES],
|
|
7219
7285
|
currentActionShouldDelegate: delegation.shouldDelegate,
|
|
7286
|
+
autoRunShouldDelegate: autoRunAvailable,
|
|
7220
7287
|
currentActionCategory: delegation.category,
|
|
7221
7288
|
mainAgentResponsibilities: [
|
|
7222
7289
|
"Keep user conversation state and approval boundaries",
|
|
@@ -7239,7 +7306,23 @@ function buildAgentOrchestrationPolicy(actionOptions, autoRunAvailable) {
|
|
|
7239
7306
|
"flow --resume <RUN_ID>",
|
|
7240
7307
|
"autoRun.resume.flowCommand",
|
|
7241
7308
|
"context --json-compact"
|
|
7242
|
-
]
|
|
7309
|
+
],
|
|
7310
|
+
subAgentHandoff: {
|
|
7311
|
+
required: handoffRequired,
|
|
7312
|
+
mode: handoffMode,
|
|
7313
|
+
featureRef,
|
|
7314
|
+
category: delegation.category,
|
|
7315
|
+
cwd: handoffCwd,
|
|
7316
|
+
cmd: handoffCmd,
|
|
7317
|
+
verify: handoffRequired ? {
|
|
7318
|
+
runOncePerSession: true,
|
|
7319
|
+
cacheKey: verifyCacheKey,
|
|
7320
|
+
expectedCwd: handoffCwd,
|
|
7321
|
+
commands: ["pwd", "git rev-parse --show-toplevel"],
|
|
7322
|
+
onMismatch: "stop_and_report",
|
|
7323
|
+
collectDetailedLogsOnMismatchOnly: true
|
|
7324
|
+
} : null
|
|
7325
|
+
}
|
|
7243
7326
|
};
|
|
7244
7327
|
}
|
|
7245
7328
|
async function resolveContextState(config, featureName, options) {
|
|
@@ -7791,7 +7874,9 @@ async function runContext(featureName, options) {
|
|
|
7791
7874
|
);
|
|
7792
7875
|
const agentOrchestration = buildAgentOrchestrationPolicy(
|
|
7793
7876
|
state.actionOptions,
|
|
7794
|
-
autoRunPlan.available
|
|
7877
|
+
autoRunPlan.available,
|
|
7878
|
+
autoRunPlan.command,
|
|
7879
|
+
state.matchedFeature?.folderName || null
|
|
7795
7880
|
);
|
|
7796
7881
|
if (options.approve || options.execute) {
|
|
7797
7882
|
await runApprovedOption(
|
|
@@ -8224,10 +8309,7 @@ async function runContext(featureName, options) {
|
|
|
8224
8309
|
}
|
|
8225
8310
|
const actionOptions = state.actionOptions;
|
|
8226
8311
|
const hasCommandOption = actionOptions.some((option) => option.action.type === "command");
|
|
8227
|
-
const longRunningDelegation = shouldDelegateCurrentAction(
|
|
8228
|
-
actionOptions,
|
|
8229
|
-
autoRunPlan.available
|
|
8230
|
-
);
|
|
8312
|
+
const longRunningDelegation = shouldDelegateCurrentAction(actionOptions);
|
|
8231
8313
|
console.log(chalk6.green(chalk6.bold("\u{1F449} Next Options (Atomic):")));
|
|
8232
8314
|
let hasDocsCommand = false;
|
|
8233
8315
|
actionOptions.forEach((option) => {
|
|
@@ -9614,8 +9696,12 @@ function toFlowRunStatus(status) {
|
|
|
9614
9696
|
return "failed";
|
|
9615
9697
|
}
|
|
9616
9698
|
}
|
|
9617
|
-
function buildAgentOrchestrationPolicy2(autoRun) {
|
|
9699
|
+
function buildAgentOrchestrationPolicy2(autoRun, featureRef) {
|
|
9618
9700
|
const preferredResumeCommand = autoRun?.run?.resumeCommand || autoRun?.resume?.flowCommand || null;
|
|
9701
|
+
const handoffRequired = !!autoRun && !!preferredResumeCommand;
|
|
9702
|
+
const verifyCacheKey = handoffRequired ? `${(featureRef || "unknown").toLowerCase()}|${Buffer.from(
|
|
9703
|
+
preferredResumeCommand
|
|
9704
|
+
).toString("base64").slice(0, 12)}` : "";
|
|
9619
9705
|
return {
|
|
9620
9706
|
mode: "main_orchestrates_subagent_execution",
|
|
9621
9707
|
delegationPolicy: "prefer_main_delegate_long_running_fallback_main",
|
|
@@ -9640,7 +9726,23 @@ function buildAgentOrchestrationPolicy2(autoRun) {
|
|
|
9640
9726
|
"AUTO_MANUAL_REQUIRED",
|
|
9641
9727
|
"command execution error"
|
|
9642
9728
|
],
|
|
9643
|
-
preferredResumeCommand
|
|
9729
|
+
preferredResumeCommand,
|
|
9730
|
+
subAgentHandoff: {
|
|
9731
|
+
required: handoffRequired,
|
|
9732
|
+
mode: handoffRequired ? "auto_run" : null,
|
|
9733
|
+
featureRef,
|
|
9734
|
+
category: null,
|
|
9735
|
+
cwd: handoffRequired ? process.cwd() : null,
|
|
9736
|
+
cmd: handoffRequired ? preferredResumeCommand : null,
|
|
9737
|
+
verify: handoffRequired ? {
|
|
9738
|
+
runOncePerSession: true,
|
|
9739
|
+
cacheKey: verifyCacheKey,
|
|
9740
|
+
expectedCwd: process.cwd(),
|
|
9741
|
+
commands: ["pwd", "git rev-parse --show-toplevel"],
|
|
9742
|
+
onMismatch: "stop_and_report",
|
|
9743
|
+
collectDetailedLogsOnMismatchOnly: true
|
|
9744
|
+
} : null
|
|
9745
|
+
}
|
|
9644
9746
|
};
|
|
9645
9747
|
}
|
|
9646
9748
|
function getFeatureRef2(feature) {
|
|
@@ -10291,7 +10393,10 @@ async function runFlow(featureName, options) {
|
|
|
10291
10393
|
const jsonMode = !!options.json || !!options.jsonCompact;
|
|
10292
10394
|
if (jsonMode) {
|
|
10293
10395
|
const autoRunFailed = !!(autoRun && isAutoRunFailureStatus(autoRun.status));
|
|
10294
|
-
const agentOrchestration2 = buildAgentOrchestrationPolicy2(
|
|
10396
|
+
const agentOrchestration2 = buildAgentOrchestrationPolicy2(
|
|
10397
|
+
autoRun,
|
|
10398
|
+
resolvedFeatureName || null
|
|
10399
|
+
);
|
|
10295
10400
|
const status = autoRunFailed ? "error" : "ok";
|
|
10296
10401
|
const reasonCode = autoRunFailed ? autoRun?.reasonCode || "AUTO_EXECUTION_FAILED" : "FLOW_SUMMARY";
|
|
10297
10402
|
if (options.jsonCompact) {
|
|
@@ -10386,7 +10491,10 @@ async function runFlow(featureName, options) {
|
|
|
10386
10491
|
console.log(chalk6.gray(`- Resume with: ${autoRun.run.resumeCommand}`));
|
|
10387
10492
|
}
|
|
10388
10493
|
}
|
|
10389
|
-
const agentOrchestration = buildAgentOrchestrationPolicy2(
|
|
10494
|
+
const agentOrchestration = buildAgentOrchestrationPolicy2(
|
|
10495
|
+
autoRun,
|
|
10496
|
+
resolvedFeatureName || null
|
|
10497
|
+
);
|
|
10390
10498
|
console.log(
|
|
10391
10499
|
chalk6.gray(
|
|
10392
10500
|
`- Orchestration: ${agentOrchestration.mode}, delegate long-running loops to sub-agent`
|
|
@@ -11485,6 +11593,54 @@ ${mermaidSection}
|
|
|
11485
11593
|
- **Spec**: \`${bodyPaths.specPath}\`
|
|
11486
11594
|
- **Tasks**: \`${bodyPaths.tasksPath}\`${closes}`;
|
|
11487
11595
|
}
|
|
11596
|
+
function stripMarkdownCodeContexts(body) {
|
|
11597
|
+
const lines = body.split("\n");
|
|
11598
|
+
const out = [];
|
|
11599
|
+
let inFence = false;
|
|
11600
|
+
let fenceChar = "";
|
|
11601
|
+
let fenceLength = 0;
|
|
11602
|
+
for (const line of lines) {
|
|
11603
|
+
const fenceStartMatch = line.match(/^\s*(`{3,}|~{3,})/);
|
|
11604
|
+
if (fenceStartMatch) {
|
|
11605
|
+
const marker = fenceStartMatch[1];
|
|
11606
|
+
const markerChar = marker[0];
|
|
11607
|
+
const markerLength = marker.length;
|
|
11608
|
+
if (!inFence) {
|
|
11609
|
+
inFence = true;
|
|
11610
|
+
fenceChar = markerChar;
|
|
11611
|
+
fenceLength = markerLength;
|
|
11612
|
+
continue;
|
|
11613
|
+
}
|
|
11614
|
+
if (markerChar === fenceChar && markerLength >= fenceLength) {
|
|
11615
|
+
inFence = false;
|
|
11616
|
+
fenceChar = "";
|
|
11617
|
+
fenceLength = 0;
|
|
11618
|
+
}
|
|
11619
|
+
continue;
|
|
11620
|
+
}
|
|
11621
|
+
if (inFence) continue;
|
|
11622
|
+
out.push(line.replace(/`[^`\n]*`/g, ""));
|
|
11623
|
+
}
|
|
11624
|
+
return out.join("\n");
|
|
11625
|
+
}
|
|
11626
|
+
function hasIssueClosingKeyword(body, issueNumber) {
|
|
11627
|
+
if (!issueNumber) return false;
|
|
11628
|
+
const cleaned = stripMarkdownCodeContexts(body);
|
|
11629
|
+
const issue = escapeRegExp3(issueNumber);
|
|
11630
|
+
const closeKeywordRegex = new RegExp(
|
|
11631
|
+
`\\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\b\\s*(?:[a-zA-Z0-9_.-]+\\/)?#\\s*${issue}\\b`,
|
|
11632
|
+
"i"
|
|
11633
|
+
);
|
|
11634
|
+
return closeKeywordRegex.test(cleaned);
|
|
11635
|
+
}
|
|
11636
|
+
function ensureIssueClosingLine(body, issueNumber) {
|
|
11637
|
+
if (!issueNumber) return body;
|
|
11638
|
+
if (hasIssueClosingKeyword(body, issueNumber)) return body;
|
|
11639
|
+
const trimmed = body.trimEnd();
|
|
11640
|
+
const separator = trimmed.length > 0 ? "\n\n" : "";
|
|
11641
|
+
return `${trimmed}${separator}Closes #${issueNumber}
|
|
11642
|
+
`;
|
|
11643
|
+
}
|
|
11488
11644
|
function getRequiredIssueSections(lang) {
|
|
11489
11645
|
return getGithubDraftRequiredSections("issue", lang);
|
|
11490
11646
|
}
|
|
@@ -11938,8 +12094,8 @@ function githubCommand(program2) {
|
|
|
11938
12094
|
kindLabel: tg(config.lang, "kindPr"),
|
|
11939
12095
|
lang: config.lang
|
|
11940
12096
|
});
|
|
11941
|
-
|
|
11942
|
-
|
|
12097
|
+
let body = preparedBody.body;
|
|
12098
|
+
let bodyFile = preparedBody.bodyFile;
|
|
11943
12099
|
const title = options.title?.trim() || (preparedBody.source === "workflow-ready" ? preparedBody.draftMetadata?.title : void 0) || defaultTitle;
|
|
11944
12100
|
const labels = parseLabels(
|
|
11945
12101
|
optionLabels || (preparedBody.source === "workflow-ready" ? preparedBody.draftMetadata?.labels : void 0),
|
|
@@ -11954,6 +12110,18 @@ function githubCommand(program2) {
|
|
|
11954
12110
|
let syncChanged = false;
|
|
11955
12111
|
const pushDocsSync = shouldPushDocsSync(config);
|
|
11956
12112
|
if (options.create) {
|
|
12113
|
+
const normalizedBody = ensureIssueClosingLine(body, feature.issueNumber);
|
|
12114
|
+
if (normalizedBody !== body) {
|
|
12115
|
+
body = normalizedBody;
|
|
12116
|
+
const fallbackBodyFile = defaultBodyFile;
|
|
12117
|
+
if (preparedBody.source === "generated") {
|
|
12118
|
+
await fs17.writeFile(bodyFile, body, "utf-8");
|
|
12119
|
+
} else {
|
|
12120
|
+
await fs17.ensureDir(path23.dirname(fallbackBodyFile));
|
|
12121
|
+
await fs17.writeFile(fallbackBodyFile, body, "utf-8");
|
|
12122
|
+
bodyFile = fallbackBodyFile;
|
|
12123
|
+
}
|
|
12124
|
+
}
|
|
11957
12125
|
const projectGitCwd = resolveGithubProjectCwd(config, feature);
|
|
11958
12126
|
ensureNoTodoPlaceholders(body, tg(config.lang, "kindPr"), config.lang);
|
|
11959
12127
|
ensurePrArtifacts(body, artifactPolicy, config.lang);
|
|
@@ -12983,6 +13151,12 @@ function buildReportContent(input) {
|
|
|
12983
13151
|
- **Skills**: ${skills}
|
|
12984
13152
|
- **Decision**: ${input.decision}
|
|
12985
13153
|
- **Summary**: ${input.note}
|
|
13154
|
+
- **Findings**:
|
|
13155
|
+
- TODO: <file:line | severity: low|medium|high | fix: required|optional | note: ...> OR 0 findings
|
|
13156
|
+
- **Residual Risks**:
|
|
13157
|
+
- TODO: residual risk assessment after review
|
|
13158
|
+
- **Tests Run**:
|
|
13159
|
+
- TODO: commands/results verified during pre-PR review
|
|
12986
13160
|
- **Evidence**:
|
|
12987
13161
|
- TODO: review comments/paths/tests verified during pre-PR review
|
|
12988
13162
|
- **Trace**: pre-pr-review command executed and synced with tasks.md
|