lee-spec-kit 0.6.42 → 0.6.43
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 +219 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -497,7 +497,8 @@ var koContext = {
|
|
|
497
497
|
"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",
|
|
498
498
|
"context.actionDetail.taskExecute": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC9C4\uD589\uD558\uC138\uC694",
|
|
499
499
|
"context.actionDetail.taskExecuteRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD558\uACE0 \uD0DC\uC2A4\uD06C\uB97C \uC2DC\uC791\uD558\uC138\uC694: {task}. (TODO\uBA74 DOING\uC73C\uB85C \uBCC0\uACBD)",
|
|
500
|
-
"context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \
|
|
500
|
+
"context.actionDetail.taskExecuteContinue": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent) \uC791\uC5C5 handoff\uB97C \uC900\uBE44\uD574 \uC9C4\uD589 \uC911\uC778 \uD0DC\uC2A4\uD06C\uB97C \uB9C8\uBB34\uB9AC\uD558\uC138\uC694: {task}. (\uC644\uB8CC \uD6C4 \uACB0\uACFC/\uAC80\uC99D\uC744 \uACF5\uC720\uD558\uACE0 DONE\uC73C\uB85C \uBCC0\uACBD)",
|
|
501
|
+
"context.actionDetail.taskExecuteComplete": "\uD604\uC7AC \uD0DC\uC2A4\uD06C\uB97C \uC644\uB8CC \uCC98\uB9AC\uD558\uC138\uC694: {task}. (DOING\uC744 DONE\uC73C\uB85C \uBCC0\uACBD)",
|
|
501
502
|
"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",
|
|
502
503
|
"context.actionDetail.prePrReviewRun": "\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8(sub-agent)\uB85C PR \uC804 \uB9AC\uBDF0\uB97C \uC2E4\uD589\uD574 `review-trace.json`\uC744 \uC900\uBE44\uD558\uC138\uC694",
|
|
503
504
|
"context.actionDetail.prePrReviewRecord": "PR \uC804 \uB9AC\uBDF0 evidence\uB97C decisions.md\uC640 tasks.md\uC5D0 \uAE30\uB85D\uD558\uC138\uC694",
|
|
@@ -1049,7 +1050,8 @@ var enContext = {
|
|
|
1049
1050
|
"context.actionDetail.issueCreateFromDoc": "Create GitHub Issue from ready issue.md and sync Issue",
|
|
1050
1051
|
"context.actionDetail.taskExecute": "Proceed with the current task",
|
|
1051
1052
|
"context.actionDetail.taskExecuteRun": "Prepare helper agent/sub-agent task handoff and start the task: {task}. (TODO becomes DOING)",
|
|
1052
|
-
"context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and
|
|
1053
|
+
"context.actionDetail.taskExecuteContinue": "Prepare helper agent/sub-agent handoff and wrap up the in-progress task: {task}. (Share outcome/verification, then mark it DONE)",
|
|
1054
|
+
"context.actionDetail.taskExecuteComplete": "Mark the current task as complete: {task}. (Change DOING to DONE)",
|
|
1053
1055
|
"context.actionDetail.reviewFixCommit": "Create a review-fix commit with resolved feedback summary",
|
|
1054
1056
|
"context.actionDetail.prePrReviewRun": "Run the pre-PR review via a helper agent/sub-agent and prepare `review-trace.json`",
|
|
1055
1057
|
"context.actionDetail.prePrReviewRecord": "Record pre-PR review evidence into decisions.md and tasks.md",
|
|
@@ -3553,6 +3555,7 @@ function resolvePrePrReviewPolicy(workflow) {
|
|
|
3553
3555
|
function getPrePrReviewPrompt(lang, skills, fallbackText) {
|
|
3554
3556
|
if (lang === "ko") {
|
|
3555
3557
|
return `PR \uC0DD\uC131 \uC804 \uC0AC\uC804 \uCF54\uB4DC\uB9AC\uBDF0\uB97C \uC9C4\uD589\uD558\uC138\uC694.
|
|
3558
|
+
0. \uAC19\uC740 feature/pre-PR \uB9AC\uBDF0\uB97C \uB2F4\uB2F9\uD558\uB358 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC774\uBBF8 \uC788\uC73C\uBA74 \uC0C8\uB85C \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0 \uC7AC\uC0AC\uC6A9\uD558\uC138\uC694. \uAE30\uBCF8\uC740 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 1\uAC1C\uC785\uB2C8\uB2E4.
|
|
3556
3559
|
1. \`spec.md\`, \`plan.md\`, \`tasks.md\`\uB97C \uC77D\uACE0 feature \uBAA9\uD45C/\uBC94\uC704/\uC644\uB8CC \uAE30\uC900\uC744 \uBA3C\uC800 \uC694\uC57D\uD558\uC138\uC694.
|
|
3557
3560
|
2. \uB9AC\uBDF0 \uBC94\uC704\uB97C \uBD84\uB9AC\uD574 \uD655\uC778\uD558\uC138\uC694.
|
|
3558
3561
|
- main \uAE30\uC900: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
|
|
@@ -3561,11 +3564,14 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
|
|
|
3561
3564
|
4. \uD655\uC778\uB41C \uAC01 \uD30C\uC77C\uC5D0 \uB300\uD574 risk, security, perf, maintainability \uD3C9\uAC00\uC640 \uAD6C\uCCB4\uC801\uC778 fileLine \uC704\uCE58\uAC00 \uD3EC\uD568\uB41C 'review-trace.json' \uC99D\uAC70 \uD30C\uC77C\uC744 \uC0DD\uC131\uD558\uC138\uC694.
|
|
3562
3565
|
5. \uAE30\uBCF8 \uBCA0\uC774\uC2A4\uB77C\uC778\uC740 '${fallbackText}'\uC774\uBA70, 'create-pr' \uBB38\uC11C\uC758 'Pre-PR \uAE30\uBCF8 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8' \uC139\uC158\uC744 \uC218\uD589\uD558\uC138\uC694.
|
|
3563
3566
|
6. \uC6B0\uC120\uC21C\uC704 \uC2A4\uD0AC: ${skills.length > 0 ? skills.join(", ") : "\uC5C6\uC74C"} \uB85C \uC2EC\uD654 \uAC80\uD1A0\uB97C \uC9C4\uD589\uD558\uC138\uC694.
|
|
3564
|
-
7. \uCD94\uAC00 \uAC80\uC99D\uC774 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC audit/\uD0C0\uAE43 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\
|
|
3565
|
-
8. \
|
|
3566
|
-
9. \
|
|
3567
|
+
7. \uCD94\uAC00 \uAC80\uC99D\uC774 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC audit/\uD0C0\uAE43 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694. \uBCC4\uB3C4 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uCD94\uAC00 \uC0DD\uC131\uB3C4 \uAF2D \uD544\uC694\uD560 \uB54C\uB9CC \uD558\uC138\uC694.
|
|
3568
|
+
8. \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uACE0, \uC774\uBBF8 \uC218\uC9D1\uD55C \uACB0\uACFC\uB9CC \uC815\uB9AC\uD574\uB3C4 \uB429\uB2C8\uB2E4.
|
|
3569
|
+
9. \uC2E4\uD589\uD55C \uBA85\uB839\uC774 \uC788\uC73C\uBA74 \`commandsExecuted\`\uC5D0 \uAE30\uB85D\uD558\uC138\uC694.
|
|
3570
|
+
10. \uC9C0\uC801\uC0AC\uD56D\uC774 \uB0A8\uC544 \uC788\uC73C\uBA74 \uBA3C\uC800 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested' \uB85C \uAE30\uB85D\uD558\uC138\uC694. \uB2E8, \`workflow.prePrReview.evidenceMode=any\` \uC774\uACE0 \uC2E4\uD589 \uC99D\uAC70 \uAC15\uC81C\uAC00 \uC5C6\uC73C\uBA74 \`--evidence\` \uC5C6\uC774 \uC9C1\uC811 \uAE30\uB85D\uD574\uB3C4 \uB429\uB2C8\uB2E4.
|
|
3571
|
+
11. \uC218\uC815/\uC7AC\uAC80\uC99D \uD6C4 \uCD5C\uC885 \uC2B9\uC778 \uC2DC\uC810\uC5D0 'npx lee-spec-kit pre-pr-review <feature> --decision approve' \uB97C \uC2E4\uD589\uD558\uC138\uC694. \`path_required\` \uC815\uCC45\uC77C \uB54C\uB9CC \`--evidence review-trace.json\` \uC744 \uD568\uAED8 \uBD99\uC774\uC138\uC694.`;
|
|
3567
3572
|
}
|
|
3568
3573
|
return `Conduct a pre-PR code review.
|
|
3574
|
+
0. Reuse the existing helper/sub-agent for this feature review if one already exists. Default to a single helper agent.
|
|
3569
3575
|
1. Read \`spec.md\`, \`plan.md\`, and \`tasks.md\` first, then summarize the feature goal, scope, and done criteria.
|
|
3570
3576
|
2. Split and check the review scope.
|
|
3571
3577
|
- Main scope: 'git diff --name-only $(git merge-base HEAD origin/main)..HEAD'
|
|
@@ -3574,15 +3580,17 @@ function getPrePrReviewPrompt(lang, skills, fallbackText) {
|
|
|
3574
3580
|
4. Generate a 'review-trace.json' file for all changed files, including \`findingCount\`, \`blockingFindings\`, evaluations for risk, security, perf, maintainability, and specific fileLine locators.
|
|
3575
3581
|
5. The baseline is '${fallbackText}'. Always perform the 'Pre-PR Core Checklist' section of the 'create-pr' document.
|
|
3576
3582
|
6. Priority skills: ${skills.length > 0 ? skills.join(", ") : "None"} for deeper technical review.
|
|
3577
|
-
7. Run extra audit/targeted verification only when the review needs more evidence
|
|
3578
|
-
8. If
|
|
3579
|
-
9.
|
|
3583
|
+
7. Run extra audit/targeted verification only when the review truly needs more evidence. Spawn additional helper agents only when necessary.
|
|
3584
|
+
8. If helper-agent quota is exhausted, continue the review in the main agent and just keep the evidence consistent.
|
|
3585
|
+
9. Record commands in \`commandsExecuted\` only when you actually ran them.
|
|
3586
|
+
10. If unresolved findings remain, first record them with 'npx lee-spec-kit pre-pr-review <feature> --evidence review-trace.json --decision changes_requested'. When \`workflow.prePrReview.evidenceMode=any\` and execution evidence is not enforced, direct record mode without \`--evidence\` is also valid.
|
|
3587
|
+
11. After fixes and re-validation, run 'npx lee-spec-kit pre-pr-review <feature> --decision approve' for final pre-PR approval. Add \`--evidence review-trace.json\` only when the active evidence policy requires a path.`;
|
|
3580
3588
|
}
|
|
3581
3589
|
function getCodeReviewPrompt(lang) {
|
|
3582
3590
|
if (lang === "ko") {
|
|
3583
|
-
return `\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 \uBA85\uC2DC\uC801\uC778 \uBA38\uC9C0 \uC2B9\uC778(\uB77C\uBCA8) \uD6C4, \uB85C\uCEEC \uBE0C\uB79C\uCE58\uAC00 upstream\uBCF4\uB2E4 \uC55E\uC120 \uACBD\uC6B0\uC5D0\uB9CC \uC9C4\uD589\uD558\uC138\uC694.`;
|
|
3591
|
+
return `\uB9AC\uBDF0 \uCF54\uBA58\uD2B8\uB97C \uD655\uC778/\uBD84\uC11D\uD55C \uB4A4 \uD544\uC694\uD55C \uC218\uC815\uC744 \uC9C4\uD589\uD558\uC138\uC694. \uAE30\uC874 review \uB2F4\uB2F9 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694. \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uC774\uC5B4\uAC00\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 \uBA85\uC2DC\uC801\uC778 \uBA38\uC9C0 \uC2B9\uC778(\uB77C\uBCA8) \uD6C4, \uB85C\uCEEC \uBE0C\uB79C\uCE58\uAC00 upstream\uBCF4\uB2E4 \uC55E\uC120 \uACBD\uC6B0\uC5D0\uB9CC \uC9C4\uD589\uD558\uC138\uC694.`;
|
|
3584
3592
|
}
|
|
3585
|
-
return `Review and analyze comments, then make necessary fixes. Keep PR status as Review and record the latest 'PR Review Evidence/Decision'. Push changes only after explicit approval (label) and only if the local branch is ahead of upstream.`;
|
|
3593
|
+
return `Review and analyze comments, then make necessary fixes. Reuse the existing review helper agent if one already exists, and default to a single helper agent. If helper-agent quota is exhausted, continue in the main agent. Keep PR status as Review and record the latest 'PR Review Evidence/Decision'. Push changes only after explicit approval (label) and only if the local branch is ahead of upstream.`;
|
|
3586
3594
|
}
|
|
3587
3595
|
|
|
3588
3596
|
// src/utils/context/steps.ts
|
|
@@ -3694,6 +3702,13 @@ function buildTaskRunCommandArgs(feature, taskId) {
|
|
|
3694
3702
|
}
|
|
3695
3703
|
return commandArgs;
|
|
3696
3704
|
}
|
|
3705
|
+
function buildTaskCompleteCommandArgs(feature, taskId) {
|
|
3706
|
+
const commandArgs = ["task-complete", feature.folderName, "--task", taskId];
|
|
3707
|
+
if (feature.type && feature.type !== "single") {
|
|
3708
|
+
commandArgs.push("--component", feature.type);
|
|
3709
|
+
}
|
|
3710
|
+
return commandArgs;
|
|
3711
|
+
}
|
|
3697
3712
|
function buildCodeReviewRunCommandArgs(feature) {
|
|
3698
3713
|
const commandArgs = ["code-review-run", feature.folderName];
|
|
3699
3714
|
if (feature.type && feature.type !== "single") {
|
|
@@ -3849,7 +3864,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
|
|
|
3849
3864
|
if (!diff.trim()) return 0;
|
|
3850
3865
|
const removedByTask = /* @__PURE__ */ new Map();
|
|
3851
3866
|
const addedByTask = /* @__PURE__ */ new Map();
|
|
3852
|
-
const
|
|
3867
|
+
const parseTaskLine3 = (line) => {
|
|
3853
3868
|
const match = line.match(
|
|
3854
3869
|
/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\s+(.+?)\s*$/i
|
|
3855
3870
|
);
|
|
@@ -3864,7 +3879,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
|
|
|
3864
3879
|
for (const line of diff.split("\n")) {
|
|
3865
3880
|
if (line.startsWith("---") || line.startsWith("+++")) continue;
|
|
3866
3881
|
if (line.startsWith("-")) {
|
|
3867
|
-
const parsed =
|
|
3882
|
+
const parsed = parseTaskLine3(line.slice(1));
|
|
3868
3883
|
if (!parsed) continue;
|
|
3869
3884
|
const existing = removedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
|
|
3870
3885
|
existing.add(parsed.status);
|
|
@@ -3872,7 +3887,7 @@ function countDoneTransitionsInLatestTasksCommit(ctx, feature) {
|
|
|
3872
3887
|
continue;
|
|
3873
3888
|
}
|
|
3874
3889
|
if (line.startsWith("+")) {
|
|
3875
|
-
const parsed =
|
|
3890
|
+
const parsed = parseTaskLine3(line.slice(1));
|
|
3876
3891
|
if (!parsed) continue;
|
|
3877
3892
|
const existing = addedByTask.get(parsed.key) || /* @__PURE__ */ new Set();
|
|
3878
3893
|
existing.add(parsed.status);
|
|
@@ -4073,14 +4088,14 @@ function getStepDefinitions(ctx) {
|
|
|
4073
4088
|
operationType: "local",
|
|
4074
4089
|
requiresUserCheck: true,
|
|
4075
4090
|
taskExecutePhase: "complete",
|
|
4076
|
-
uiDetailKey: "context.actionDetail.
|
|
4091
|
+
uiDetailKey: "context.actionDetail.taskExecuteComplete",
|
|
4077
4092
|
uiDetailParams: {
|
|
4078
4093
|
task: resolveTaskUiLabel(f.activeTask)
|
|
4079
4094
|
},
|
|
4080
4095
|
scope: "docs",
|
|
4081
4096
|
cwd: f.git.docsGitCwd,
|
|
4082
4097
|
cmd: buildSelfCliCommand(
|
|
4083
|
-
|
|
4098
|
+
buildTaskCompleteCommandArgs(
|
|
4084
4099
|
f,
|
|
4085
4100
|
f.activeTask?.id || `T-${f.folderName}-active`
|
|
4086
4101
|
)
|
|
@@ -4747,9 +4762,9 @@ ${tr(lang, "messages", "prePrReviewDecisionReconfirm", {
|
|
|
4747
4762
|
actions: (f) => getTaskExecuteFinalizeActions(f)
|
|
4748
4763
|
},
|
|
4749
4764
|
{
|
|
4750
|
-
id: "
|
|
4751
|
-
phase: "
|
|
4752
|
-
owner: "
|
|
4765
|
+
id: "task_complete",
|
|
4766
|
+
phase: "finalize",
|
|
4767
|
+
owner: "main",
|
|
4753
4768
|
category: "task_execute",
|
|
4754
4769
|
when: (f) => isTaskExecuteCurrent(f) && !!f.activeTask,
|
|
4755
4770
|
actions: (f) => getTaskExecuteRunningActions(f)
|
|
@@ -5206,7 +5221,7 @@ function applyApprovalPolicy(step, actions, approval, currentSubstatePhase) {
|
|
|
5206
5221
|
function applyTaskExecutePhaseCheck(action, requiresUserCheck, policy, explicitlyRequired = false, currentSubstatePhase) {
|
|
5207
5222
|
if (policy !== "start_only") return requiresUserCheck;
|
|
5208
5223
|
if (action.category !== "task_execute") return requiresUserCheck;
|
|
5209
|
-
const isCompletionPhase = currentSubstatePhase === "running" || !currentSubstatePhase && action.taskExecutePhase === "complete";
|
|
5224
|
+
const isCompletionPhase = currentSubstatePhase === "running" || currentSubstatePhase === "finalize" || !currentSubstatePhase && action.taskExecutePhase === "complete";
|
|
5210
5225
|
if (!isCompletionPhase) return requiresUserCheck;
|
|
5211
5226
|
if (explicitlyRequired) return requiresUserCheck;
|
|
5212
5227
|
return false;
|
|
@@ -8271,7 +8286,7 @@ function toActionOptions(actions, lang) {
|
|
|
8271
8286
|
const summary = getActionSummary(action, lang);
|
|
8272
8287
|
const detail = buildActionDetail(action, lang);
|
|
8273
8288
|
const requiresRequestText = action.category === "user_request_replan";
|
|
8274
|
-
const replyExample = requiresRequestText ? `${label}, <your request>` :
|
|
8289
|
+
const replyExample = requiresRequestText ? `${label}, <your request>` : label;
|
|
8275
8290
|
return {
|
|
8276
8291
|
label,
|
|
8277
8292
|
summary,
|
|
@@ -15928,6 +15943,9 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
15928
15943
|
fallback: policy.fallback,
|
|
15929
15944
|
handoffOnly: true,
|
|
15930
15945
|
advancesWorkflow: false,
|
|
15946
|
+
reuseKey: `pre-pr:${featureRef}`,
|
|
15947
|
+
suggestedParallelism: 1,
|
|
15948
|
+
fallbackToMainAgentWhenQuotaExceeded: true,
|
|
15931
15949
|
nextStepRequirement: "generate_review_trace_then_record",
|
|
15932
15950
|
evidenceFile: "review-trace.json",
|
|
15933
15951
|
prompt,
|
|
@@ -15949,6 +15967,18 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
15949
15967
|
config.lang === "ko" ? "\uC774 \uBA85\uB839\uC740 \uB9AC\uBDF0 handoff\uB9CC \uC900\uBE44\uD569\uB2C8\uB2E4. review-trace.json\uC744 \uC9C1\uC811 \uC0DD\uC131\uD558\uAC70\uB098 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : "This command only prepares the review handoff. It does not generate review-trace.json or advance workflow state by itself."
|
|
15950
15968
|
)
|
|
15951
15969
|
);
|
|
15970
|
+
console.log(
|
|
15971
|
+
chalk8.gray(
|
|
15972
|
+
config.lang === "ko" ? "- \uAE30\uC874 pre-PR \uB9AC\uBDF0 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694." : "- Reuse the existing pre-PR helper agent if one already exists; default to a single helper agent."
|
|
15973
|
+
)
|
|
15974
|
+
);
|
|
15975
|
+
console.log(
|
|
15976
|
+
chalk8.gray(
|
|
15977
|
+
config.lang === "ko" ? "- \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uB9AC\uBDF0\uB97C \uC774\uC5B4\uAC00\uC138\uC694." : "- If helper-agent quota is exhausted, continue the review in the main agent."
|
|
15978
|
+
)
|
|
15979
|
+
);
|
|
15980
|
+
console.log(`Reuse key: pre-pr:${featureRef}`);
|
|
15981
|
+
console.log(`Suggested parallelism: 1`);
|
|
15952
15982
|
console.log(`Evidence file: review-trace.json`);
|
|
15953
15983
|
console.log(`Record changes requested: ${changesRequestedCommand}`);
|
|
15954
15984
|
console.log(`Record approval: ${approveCommand}`);
|
|
@@ -16181,6 +16211,9 @@ async function runCodeReviewRun(featureName, options) {
|
|
|
16181
16211
|
owner: "subagent",
|
|
16182
16212
|
handoffOnly: true,
|
|
16183
16213
|
advancesWorkflow: false,
|
|
16214
|
+
reuseKey: `code-review:${feature.folderName}`,
|
|
16215
|
+
suggestedParallelism: 1,
|
|
16216
|
+
fallbackToMainAgentWhenQuotaExceeded: true,
|
|
16184
16217
|
nextMainState: "code_review_finalize",
|
|
16185
16218
|
tasksPath: path12.join(feature.path, "tasks.md"),
|
|
16186
16219
|
decisionsPath: path12.join(feature.path, "decisions.md"),
|
|
@@ -16200,6 +16233,13 @@ async function runCodeReviewRun(featureName, options) {
|
|
|
16200
16233
|
);
|
|
16201
16234
|
console.log(chalk8.gray(`- substate: ${payload.substateId}`));
|
|
16202
16235
|
console.log(chalk8.gray(`- owner: ${payload.owner}`));
|
|
16236
|
+
console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
|
|
16237
|
+
console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
|
|
16238
|
+
console.log(
|
|
16239
|
+
chalk8.gray(
|
|
16240
|
+
`- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
|
|
16241
|
+
)
|
|
16242
|
+
);
|
|
16203
16243
|
console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
|
|
16204
16244
|
console.log(chalk8.gray(`- tasks.md: ${payload.tasksPath}`));
|
|
16205
16245
|
console.log(chalk8.gray(`- decisions.md: ${payload.decisionsPath}`));
|
|
@@ -16451,9 +16491,10 @@ function parseTaskLine(line) {
|
|
|
16451
16491
|
function buildTaskRunPrompt(input) {
|
|
16452
16492
|
const shared = [
|
|
16453
16493
|
"Read `spec.md`, `plan.md`, and `tasks.md` before editing code.",
|
|
16454
|
-
"
|
|
16455
|
-
"
|
|
16494
|
+
"Reuse the existing helper/sub-agent for this task if one already exists. Default to a single helper agent.",
|
|
16495
|
+
"Use additional helper agents only when parallel analysis is clearly worth the extra slot cost.",
|
|
16456
16496
|
"Keep one writer for overlapping files; do not let multiple sub-agents edit the same files concurrently.",
|
|
16497
|
+
"If helper-agent quota is exhausted, continue the task in the main agent instead of blocking progress.",
|
|
16457
16498
|
"Update the assigned task status and verification notes in `tasks.md` before leaving this task.",
|
|
16458
16499
|
"Mark the task `DONE` only after code changes and verification are complete."
|
|
16459
16500
|
];
|
|
@@ -16464,9 +16505,10 @@ function buildTaskRunPrompt(input) {
|
|
|
16464
16505
|
`- Task: ${input.taskId} ${input.title}`,
|
|
16465
16506
|
input.mode === "start" ? "- \uC774 \uBA85\uB839\uC740 `tasks.md`\uC758 \uD604\uC7AC task\uB97C `DOING`\uC73C\uB85C \uBC14\uAFB8\uACE0, \uC774\uD6C4 \uAD6C\uD604 handoff prompt\uB97C \uC900\uBE44\uD569\uB2C8\uB2E4." : "- \uC774 \uBA85\uB839\uC740 \uC9C4\uD589 \uC911 task\uC758 \uAD6C\uD604 handoff prompt\uB97C \uB2E4\uC2DC \uC900\uBE44\uD569\uB2C8\uB2E4.",
|
|
16466
16507
|
"- \uBA3C\uC800 `spec.md`, `plan.md`, `tasks.md`\uB97C \uC77D\uACE0 \uBC94\uC704\uC640 \uC644\uB8CC \uAE30\uC900\uC744 \uC815\uB9AC\uD558\uC138\uC694.",
|
|
16467
|
-
"- \
|
|
16468
|
-
"- \uC601\uD5A5 \uBC94\uC704 \uBD84\uC11D, \uD14C\uC2A4\uD2B8 \uC704\uCE58 \uD0D0\uC0C9, \uAE30\uC874 \uD328\uD134 \uC870\uC0AC\
|
|
16508
|
+
"- \uAE30\uC874\uC5D0 \uC774 task\uB97C \uB9E1\uB358 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9\uD558\uACE0, \uAE30\uBCF8\uC740 1\uAC1C\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
16509
|
+
"- \uC601\uD5A5 \uBC94\uC704 \uBD84\uC11D, \uD14C\uC2A4\uD2B8 \uC704\uCE58 \uD0D0\uC0C9, \uAE30\uC874 \uD328\uD134 \uC870\uC0AC\uAC00 \uC815\uB9D0 \uB3C5\uB9BD\uC801\uC77C \uB54C\uB9CC \uCD94\uAC00 \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uB97C \uC0AC\uC6A9\uD558\uC138\uC694.",
|
|
16469
16510
|
"- \uAC19\uC740 \uD30C\uC77C\uAD70\uC744 \uC218\uC815\uD558\uB294 \uC791\uC131\uC790\uB294 \uD55C \uBA85\uB9CC \uB450\uC138\uC694.",
|
|
16511
|
+
"- \uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8 \uD55C\uB3C4\uC5D0 \uAC78\uB9AC\uBA74 \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uAD6C\uD604\uC744 \uC774\uC5B4\uAC00\uC138\uC694.",
|
|
16470
16512
|
"- \uC774 task\uB97C \uB9C8\uCE58\uAE30 \uC804 `tasks.md`\uC5D0 \uC0C1\uD0DC\uC640 \uAC80\uC99D \uBA54\uBAA8\uB97C \uBC18\uC601\uD558\uC138\uC694.",
|
|
16471
16513
|
"- \uCF54\uB4DC \uBCC0\uACBD\uACFC \uAC80\uC99D\uC774 \uB05D\uB0AC\uC744 \uB54C\uB9CC task\uB97C `DONE`\uC73C\uB85C \uD45C\uC2DC\uD558\uC138\uC694."
|
|
16472
16514
|
].join("\n");
|
|
@@ -16565,7 +16607,11 @@ async function runTaskRun(featureName, options) {
|
|
|
16565
16607
|
mode,
|
|
16566
16608
|
substateId: mode === "start" ? "task_run" : "task_running",
|
|
16567
16609
|
owner: "subagent",
|
|
16568
|
-
|
|
16610
|
+
handoffOnly: true,
|
|
16611
|
+
reuseKey: `task:${feature.folderName}:${resolvedTask.taskId}`,
|
|
16612
|
+
suggestedParallelism: 1,
|
|
16613
|
+
fallbackToMainAgentWhenQuotaExceeded: true,
|
|
16614
|
+
nextMainState: "task_complete",
|
|
16569
16615
|
tasksUpdated,
|
|
16570
16616
|
tasksPath,
|
|
16571
16617
|
prompt,
|
|
@@ -16579,6 +16625,13 @@ async function runTaskRun(featureName, options) {
|
|
|
16579
16625
|
console.log();
|
|
16580
16626
|
console.log(chalk8.gray(`- substate: ${payload.substateId}`));
|
|
16581
16627
|
console.log(chalk8.gray(`- owner: ${payload.owner}`));
|
|
16628
|
+
console.log(chalk8.gray(`- reuse key: ${payload.reuseKey}`));
|
|
16629
|
+
console.log(chalk8.gray(`- suggested parallelism: ${payload.suggestedParallelism}`));
|
|
16630
|
+
console.log(
|
|
16631
|
+
chalk8.gray(
|
|
16632
|
+
`- quota fallback: ${payload.fallbackToMainAgentWhenQuotaExceeded ? "continue in main agent" : "none"}`
|
|
16633
|
+
)
|
|
16634
|
+
);
|
|
16582
16635
|
console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
|
|
16583
16636
|
if (tasksUpdated) {
|
|
16584
16637
|
console.log();
|
|
@@ -16614,6 +16667,146 @@ function taskRunCommand(program2) {
|
|
|
16614
16667
|
}
|
|
16615
16668
|
});
|
|
16616
16669
|
}
|
|
16670
|
+
function parseTaskLine2(line) {
|
|
16671
|
+
const match = line.match(
|
|
16672
|
+
/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]\[[^\]]+\](?:\[[^\]]+\])*\s+(T-[A-Za-z0-9-]+)\s+(.+?)\s*$/
|
|
16673
|
+
);
|
|
16674
|
+
if (!match) return null;
|
|
16675
|
+
return {
|
|
16676
|
+
index: -1,
|
|
16677
|
+
raw: line,
|
|
16678
|
+
status: match[1],
|
|
16679
|
+
taskId: match[2],
|
|
16680
|
+
title: match[3]
|
|
16681
|
+
};
|
|
16682
|
+
}
|
|
16683
|
+
function setTaskStatus2(line, nextStatus) {
|
|
16684
|
+
return line.raw.replace(
|
|
16685
|
+
/^\s*-\s*\[(TODO|DOING|DONE|REVIEW)\]/,
|
|
16686
|
+
`- [${nextStatus}]`
|
|
16687
|
+
);
|
|
16688
|
+
}
|
|
16689
|
+
async function resolveTaskCompleteContext(featureName, options) {
|
|
16690
|
+
const config = await getConfig(process.cwd());
|
|
16691
|
+
if (!config) {
|
|
16692
|
+
throw createCliError(
|
|
16693
|
+
"CONFIG_NOT_FOUND",
|
|
16694
|
+
"No lee-spec-kit config found in this workspace."
|
|
16695
|
+
);
|
|
16696
|
+
}
|
|
16697
|
+
const ctx = await createCliContext({ cwd: process.cwd() });
|
|
16698
|
+
const state = await resolveContextSelection(ctx, featureName, {
|
|
16699
|
+
component: resolveComponentOption(options.component)
|
|
16700
|
+
});
|
|
16701
|
+
if (state.status !== "single_matched" || !state.matchedFeature) {
|
|
16702
|
+
throw createCliError(
|
|
16703
|
+
"CONTEXT_SELECTION_REQUIRED",
|
|
16704
|
+
"task-complete requires a single matched feature. Pass <feature-name> explicitly."
|
|
16705
|
+
);
|
|
16706
|
+
}
|
|
16707
|
+
return {
|
|
16708
|
+
config,
|
|
16709
|
+
feature: state.matchedFeature
|
|
16710
|
+
};
|
|
16711
|
+
}
|
|
16712
|
+
async function runTaskComplete(featureName, options) {
|
|
16713
|
+
const { feature } = await resolveTaskCompleteContext(featureName, options);
|
|
16714
|
+
const tasksPath = path12.join(feature.path, "tasks.md");
|
|
16715
|
+
if (!await fs.pathExists(tasksPath)) {
|
|
16716
|
+
throw createCliError(
|
|
16717
|
+
"PRECONDITION_FAILED",
|
|
16718
|
+
`tasks.md not found for feature: ${feature.folderName}`
|
|
16719
|
+
);
|
|
16720
|
+
}
|
|
16721
|
+
const content = await fs.readFile(tasksPath, "utf-8");
|
|
16722
|
+
const lines = content.split("\n");
|
|
16723
|
+
const requestedTaskId = options.task?.trim() || feature.activeTask?.id || feature.nextTodoTask?.id;
|
|
16724
|
+
if (!requestedTaskId) {
|
|
16725
|
+
throw createCliError(
|
|
16726
|
+
"PRECONDITION_FAILED",
|
|
16727
|
+
"No active task is available for task-complete."
|
|
16728
|
+
);
|
|
16729
|
+
}
|
|
16730
|
+
const resolvedTask = lines.map((line, index) => {
|
|
16731
|
+
const parsed = parseTaskLine2(line);
|
|
16732
|
+
return parsed ? { ...parsed, index } : null;
|
|
16733
|
+
}).find((entry) => entry?.taskId === requestedTaskId);
|
|
16734
|
+
if (!resolvedTask) {
|
|
16735
|
+
throw createCliError(
|
|
16736
|
+
"INVALID_ARGUMENT",
|
|
16737
|
+
`Task "${requestedTaskId}" was not found in tasks.md.`
|
|
16738
|
+
);
|
|
16739
|
+
}
|
|
16740
|
+
if (resolvedTask.status === "DONE") {
|
|
16741
|
+
throw createCliError(
|
|
16742
|
+
"PRECONDITION_FAILED",
|
|
16743
|
+
`Task "${requestedTaskId}" is already DONE.`
|
|
16744
|
+
);
|
|
16745
|
+
}
|
|
16746
|
+
if (resolvedTask.status !== "DOING" && resolvedTask.status !== "REVIEW") {
|
|
16747
|
+
throw createCliError(
|
|
16748
|
+
"PRECONDITION_FAILED",
|
|
16749
|
+
`Task "${requestedTaskId}" must be DOING/REVIEW before marking it DONE.`
|
|
16750
|
+
);
|
|
16751
|
+
}
|
|
16752
|
+
lines[resolvedTask.index] = setTaskStatus2(resolvedTask, "DONE");
|
|
16753
|
+
await fs.writeFile(tasksPath, lines.join("\n"), "utf-8");
|
|
16754
|
+
const payload = {
|
|
16755
|
+
status: "ok",
|
|
16756
|
+
reasonCode: "TASK_COMPLETED",
|
|
16757
|
+
feature: feature.folderName,
|
|
16758
|
+
taskId: resolvedTask.taskId,
|
|
16759
|
+
title: resolvedTask.title,
|
|
16760
|
+
previousStatus: resolvedTask.status,
|
|
16761
|
+
nextStatus: "DONE",
|
|
16762
|
+
substateId: "task_complete",
|
|
16763
|
+
owner: "main",
|
|
16764
|
+
nextMainState: "task_finalize",
|
|
16765
|
+
tasksUpdated: true,
|
|
16766
|
+
tasksPath,
|
|
16767
|
+
recordedAt: getLocalDateString()
|
|
16768
|
+
};
|
|
16769
|
+
if (options.json) {
|
|
16770
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
16771
|
+
return;
|
|
16772
|
+
}
|
|
16773
|
+
console.log(
|
|
16774
|
+
chalk8.green(
|
|
16775
|
+
`Marked task ${resolvedTask.taskId} as DONE for ${feature.folderName}.`
|
|
16776
|
+
)
|
|
16777
|
+
);
|
|
16778
|
+
console.log(chalk8.gray(`- tasks.md updated: ${tasksPath}`));
|
|
16779
|
+
console.log(chalk8.gray(`- status: ${resolvedTask.status} -> DONE`));
|
|
16780
|
+
console.log(chalk8.gray(`- next main state: ${payload.nextMainState}`));
|
|
16781
|
+
}
|
|
16782
|
+
function taskCompleteCommand(program2) {
|
|
16783
|
+
program2.command("task-complete [feature-name]").description("Mark the active DOING/REVIEW task as DONE").option("--component <component>", "Component name for multi projects").option("--task <task-id>", "Explicit task id to mark DONE").option("--json", "Output JSON").action(
|
|
16784
|
+
async (featureName, options) => {
|
|
16785
|
+
try {
|
|
16786
|
+
await runTaskComplete(featureName, options);
|
|
16787
|
+
} catch (error) {
|
|
16788
|
+
const config = await getConfig(process.cwd());
|
|
16789
|
+
const lang = config?.lang ?? DEFAULT_LANG;
|
|
16790
|
+
const cliError = toCliError(error);
|
|
16791
|
+
const suggestions = getCliErrorSuggestions(cliError.code, lang);
|
|
16792
|
+
if (options.json) {
|
|
16793
|
+
console.log(
|
|
16794
|
+
JSON.stringify({
|
|
16795
|
+
status: "error",
|
|
16796
|
+
reasonCode: cliError.code,
|
|
16797
|
+
error: cliError.message,
|
|
16798
|
+
suggestions
|
|
16799
|
+
})
|
|
16800
|
+
);
|
|
16801
|
+
} else {
|
|
16802
|
+
console.error(chalk8.red(`[${cliError.code}] ${cliError.message}`));
|
|
16803
|
+
printCliErrorSuggestions(suggestions, lang);
|
|
16804
|
+
}
|
|
16805
|
+
process.exitCode = 1;
|
|
16806
|
+
}
|
|
16807
|
+
}
|
|
16808
|
+
);
|
|
16809
|
+
}
|
|
16617
16810
|
function isBannerDisabled() {
|
|
16618
16811
|
const v = (process.env.LEE_SPEC_KIT_NO_BANNER || "").trim();
|
|
16619
16812
|
return v === "1";
|
|
@@ -16797,6 +16990,7 @@ onboardCommand(program);
|
|
|
16797
16990
|
prePrReviewCommand(program);
|
|
16798
16991
|
codeReviewRunCommand(program);
|
|
16799
16992
|
taskRunCommand(program);
|
|
16993
|
+
taskCompleteCommand(program);
|
|
16800
16994
|
requirementsCommand(program);
|
|
16801
16995
|
await program.parseAsync();
|
|
16802
16996
|
//# sourceMappingURL=index.js.map
|