lee-spec-kit 0.9.5 → 0.9.6
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 +37 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/en/common/README.md +2 -2
- package/templates/en/common/agents/agents.md +1 -1
- package/templates/en/common/agents/skills/create-feature.md +1 -1
- package/templates/en/common/agents/skills/create-pr.md +1 -1
- package/templates/en/common/agents/skills/execute-task.md +1 -1
- package/templates/en/common/features/feature-base/tasks.md +1 -1
- package/templates/ko/common/README.md +2 -2
- package/templates/ko/common/agents/agents.md +1 -1
- package/templates/ko/common/agents/skills/create-feature.md +1 -1
- package/templates/ko/common/agents/skills/create-pr.md +1 -1
- package/templates/ko/common/agents/skills/execute-task.md +1 -1
- package/templates/ko/common/features/feature-base/tasks.md +1 -1
package/dist/index.js
CHANGED
|
@@ -213,7 +213,7 @@ var koCli = {
|
|
|
213
213
|
"init.choice.taskAgent.on": "\uC0AC\uC6A9 - \uAC01 Task \uAD6C\uD604\uC744 \uC704\uC784",
|
|
214
214
|
"init.choice.taskAgent.off": "\uC0AC\uC6A9 \uC548 \uD568 - \uBA54\uC778 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC9C1\uC811 \uAD6C\uD604",
|
|
215
215
|
"init.prompt.reviews": "\uB3C5\uB9BD \uAC80\uC218 \uB2E8\uACC4\uB97C \uC120\uD0DD\uD558\uC138\uC694:",
|
|
216
|
-
"init.prompt.maxReviewRounds": "\
|
|
216
|
+
"init.prompt.maxReviewRounds": "\uC794\uC5EC \uC704\uD5D8\uC744 \uAE30\uB85D\uD558\uACE0 \uACC4\uC18D\uD558\uAE30 \uC804 \uB9AC\uBDF0 \uC9C0\uC801 \uC790\uB3D9 \uBC18\uC601 \uCD5C\uB300 \uD69F\uC218:",
|
|
217
217
|
"init.choice.review.plan": "Plan",
|
|
218
218
|
"init.choice.review.task": "Task",
|
|
219
219
|
"init.choice.review.feature": "Feature",
|
|
@@ -527,7 +527,7 @@ var enCli = {
|
|
|
527
527
|
"init.choice.taskAgent.on": "On - delegate each task implementation",
|
|
528
528
|
"init.choice.taskAgent.off": "Off - implement tasks in the main agent",
|
|
529
529
|
"init.prompt.reviews": "Select independent review gates:",
|
|
530
|
-
"init.prompt.maxReviewRounds": "Maximum automatic
|
|
530
|
+
"init.prompt.maxReviewRounds": "Maximum automatic finding remediation rounds before continuing with residual risks:",
|
|
531
531
|
"init.choice.review.plan": "Plan",
|
|
532
532
|
"init.choice.review.task": "Task",
|
|
533
533
|
"init.choice.review.feature": "Feature",
|
|
@@ -1374,7 +1374,7 @@ Before taking the next workflow step:
|
|
|
1374
1374
|
16. When \`workflow-stage --json\` returns \`nextAction.category === "task_review"\` with \`executor === "subagent"\`, delegate a fresh read-only review for the returned \`taskId\`, \`baseSha\`, \`targetSha\`, and \`targetTree\`; the main agent records the returned reviewRound and evidence and moves the task from \`REVIEW\` to \`DONE\` only after an approve decision
|
|
1375
1375
|
17. When \`workflow-stage --json\` returns \`nextAction.category === "pre_pr_review"\` and \`nextAction.executor === "subagent"\`, delegate a fresh read-only Feature review using the returned \`model\`, \`reasoningEffort\`, \`onUnavailable\`, reviewRound, and review target metadata; do not select or require a named review skill
|
|
1376
1376
|
18. Review subagents return findings without modifying code; the main agent remediates findings and records the actual reviewer metadata, reviewed scope, evidence, decision, and exact hash/SHA/tree target metadata
|
|
1377
|
-
19. workflow.agentReview.maxRounds counts automatic finding-remediation passes, not the initial review.
|
|
1377
|
+
19. workflow.agentReview.maxRounds counts automatic finding-remediation passes, not the initial review. After those passes are exhausted, keep the latest changes_requested findings as residual risks and automatically complete that Plan/task/Feature review gate without asking the user for a review-approval token; blocked decisions never auto-complete
|
|
1378
1378
|
20. For a local workflow, do not report completion directly after implementation approval; follow the exact returned \`local verify\` / \`local merge\` / \`local cleanup\` commands until \`workflow-stage\` proves verification, integration, and cleanup and returns \`done\`; review-fix and \`feature_remediation\` stages explicitly permit scoped fixes
|
|
1379
1379
|
21. In a \`local-ff\` or \`local-squash\` workflow, keep implementation approval and local merge approval distinct when \`local_merge\` is required: the first accepts the implementation, and the second authorizes the configured integration strategy, post-merge checks, and local cleanup
|
|
1380
1380
|
|
|
@@ -2131,7 +2131,7 @@ function initCommand(program2) {
|
|
|
2131
2131
|
"Review gates: comma-separated plan,task,feature | none"
|
|
2132
2132
|
).option(
|
|
2133
2133
|
"--max-review-rounds <count>",
|
|
2134
|
-
"Automatic review finding remediation rounds before
|
|
2134
|
+
"Automatic review finding remediation rounds before continuing with residual risks (default: 1)"
|
|
2135
2135
|
).option(
|
|
2136
2136
|
"--completion-strategy <strategy>",
|
|
2137
2137
|
"Local completion: local-ff | local-squash | none"
|
|
@@ -8518,6 +8518,9 @@ function resolveMaxReviewRounds(config) {
|
|
|
8518
8518
|
const configured = config.workflow?.agentReview?.maxRounds;
|
|
8519
8519
|
return typeof configured === "number" && Number.isInteger(configured) && configured > 0 ? configured : 1;
|
|
8520
8520
|
}
|
|
8521
|
+
function reviewRemediationLimitReached(config, reviewRound, decisionOutcome) {
|
|
8522
|
+
return decisionOutcome === "changes_requested" && (reviewRound || 1) > resolveMaxReviewRounds(config);
|
|
8523
|
+
}
|
|
8521
8524
|
function parseWorkflowTaskLine(line, index = -1) {
|
|
8522
8525
|
const canonical = parseTaskLine(line, index);
|
|
8523
8526
|
if (canonical) {
|
|
@@ -9241,16 +9244,32 @@ function reviewEvidenceSatisfied(config, feature, scope, evidence) {
|
|
|
9241
9244
|
});
|
|
9242
9245
|
}
|
|
9243
9246
|
function planReviewSatisfied(config, feature, review, target) {
|
|
9244
|
-
return review.status === "done" && reviewEvidenceSatisfied(config, feature, "plan", review.evidence) && review.decisionOutcome === "approve"
|
|
9247
|
+
return review.status === "done" && reviewEvidenceSatisfied(config, feature, "plan", review.evidence) && (review.decisionOutcome === "approve" || reviewRemediationLimitReached(
|
|
9248
|
+
config,
|
|
9249
|
+
review.reviewRound,
|
|
9250
|
+
review.decisionOutcome
|
|
9251
|
+
)) && review.reviewedSpecHash === target.specHash && review.reviewedPlanHash === target.planHash;
|
|
9245
9252
|
}
|
|
9246
9253
|
function featureReviewSatisfied(config, feature, tasks, target) {
|
|
9247
|
-
return !!target && tasks.prePrReviewStatus === "done" && reviewEvidenceSatisfied(config, feature, "feature", tasks.prePrEvidence) && !!tasks.prePrDecision && tasks.prePrDecisionOutcome === "approve"
|
|
9254
|
+
return !!target && tasks.prePrReviewStatus === "done" && reviewEvidenceSatisfied(config, feature, "feature", tasks.prePrEvidence) && !!tasks.prePrDecision && (tasks.prePrDecisionOutcome === "approve" || reviewRemediationLimitReached(
|
|
9255
|
+
config,
|
|
9256
|
+
tasks.prePrReviewRound,
|
|
9257
|
+
tasks.prePrDecisionOutcome
|
|
9258
|
+
)) && tasks.prePrReviewedHead === target.targetSha && tasks.prePrReviewedTree === target.targetTree;
|
|
9248
9259
|
}
|
|
9249
9260
|
function taskReviewEvidenceSatisfied(config, feature, task, target) {
|
|
9250
|
-
return !!target && reviewEvidenceSatisfied(config, feature, "task", task.reviewEvidence) && task.reviewDecisionOutcome === "approve"
|
|
9261
|
+
return !!target && reviewEvidenceSatisfied(config, feature, "task", task.reviewEvidence) && (task.reviewDecisionOutcome === "approve" || reviewRemediationLimitReached(
|
|
9262
|
+
config,
|
|
9263
|
+
task.reviewRound,
|
|
9264
|
+
task.reviewDecisionOutcome
|
|
9265
|
+
)) && task.reviewedHead === target.targetSha && task.reviewedTree === target.targetTree;
|
|
9251
9266
|
}
|
|
9252
9267
|
function recordedTaskReviewSatisfied(config, feature, projectGitCwd, task, currentTargetSha) {
|
|
9253
|
-
if (!currentTargetSha || !task.reviewedHead || !task.reviewedTree || task.reviewDecisionOutcome !== "approve"
|
|
9268
|
+
if (!currentTargetSha || !task.reviewedHead || !task.reviewedTree || task.reviewDecisionOutcome !== "approve" && !reviewRemediationLimitReached(
|
|
9269
|
+
config,
|
|
9270
|
+
task.reviewRound,
|
|
9271
|
+
task.reviewDecisionOutcome
|
|
9272
|
+
) || !reviewEvidenceSatisfied(config, feature, "task", task.reviewEvidence)) {
|
|
9254
9273
|
return false;
|
|
9255
9274
|
}
|
|
9256
9275
|
const actualTree = runGitCapture(
|
|
@@ -9671,36 +9690,6 @@ function resolvePlanReviewPayload(config, feature, review, target) {
|
|
|
9671
9690
|
docsDirectory: config.docsDir
|
|
9672
9691
|
};
|
|
9673
9692
|
if (review.decisionOutcome === "changes_requested") {
|
|
9674
|
-
if (reviewRound > maxReviewRounds) {
|
|
9675
|
-
return {
|
|
9676
|
-
status: "ok",
|
|
9677
|
-
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|
|
9678
|
-
docsDir: config.docsDir,
|
|
9679
|
-
featureRef: buildFeatureRef(feature),
|
|
9680
|
-
stage: "review_escalation",
|
|
9681
|
-
nextAction: buildAction(
|
|
9682
|
-
"review_escalation",
|
|
9683
|
-
`Plan review requested more changes after ${maxReviewRounds} automatic remediation round(s) were used. Ask the user whether to revise again, request a different reviewer, accept the documented risk, change scope, or hold the Feature.`,
|
|
9684
|
-
true,
|
|
9685
|
-
null,
|
|
9686
|
-
void 0,
|
|
9687
|
-
{ ...actionContext, reviewRound }
|
|
9688
|
-
),
|
|
9689
|
-
approvalRequired: true,
|
|
9690
|
-
implementationAllowed: false,
|
|
9691
|
-
primaryActionLabel: "A",
|
|
9692
|
-
actionOptions: [
|
|
9693
|
-
buildStageOption(
|
|
9694
|
-
"A",
|
|
9695
|
-
"A",
|
|
9696
|
-
"review_retry",
|
|
9697
|
-
"Increase workflow.agentReview.maxRounds, then revise the Plan and run one more fresh review round."
|
|
9698
|
-
),
|
|
9699
|
-
buildStageOption("B", "B", "hold", "Hold the Feature for user resolution.")
|
|
9700
|
-
],
|
|
9701
|
-
blockedReasonCode: "PLAN_REVIEW_NOT_APPROVED"
|
|
9702
|
-
};
|
|
9703
|
-
}
|
|
9704
9693
|
if (targetMatches) {
|
|
9705
9694
|
return {
|
|
9706
9695
|
status: "ok",
|
|
@@ -9801,6 +9790,11 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
9801
9790
|
specContent || "",
|
|
9802
9791
|
planContent || ""
|
|
9803
9792
|
);
|
|
9793
|
+
const planReviewAutoCompleted = planReview.status === "done" && reviewEvidenceSatisfied(config, feature, "plan", planReview.evidence) && reviewRemediationLimitReached(
|
|
9794
|
+
config,
|
|
9795
|
+
planReview.reviewRound,
|
|
9796
|
+
planReview.decisionOutcome
|
|
9797
|
+
) && planReview.reviewedSpecHash === planReviewTarget.specHash && planReview.reviewedPlanHash === planReviewTarget.planHash;
|
|
9804
9798
|
const enforcePlanReview = requirements.planReviewEnabled && (tasks.docStatus !== "approved" || planReview.hasMetadata);
|
|
9805
9799
|
const issueDraft = parseWorkflowDraftMetadataExtended(issueContent || "");
|
|
9806
9800
|
const prDraft = parseWorkflowDraftMetadataExtended(prContent || "");
|
|
@@ -9845,7 +9839,7 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
9845
9839
|
planReviewTarget
|
|
9846
9840
|
);
|
|
9847
9841
|
}
|
|
9848
|
-
const approvalRequired = isReviewStage ? resolveActionApprovalRequired(config, "plan_approve", true) : false;
|
|
9842
|
+
const approvalRequired = isReviewStage && !planReviewAutoCompleted ? resolveActionApprovalRequired(config, "plan_approve", true) : false;
|
|
9849
9843
|
const actionOptions = approvalRequired ? buildApprovalActionOptions({
|
|
9850
9844
|
approveSummary: "Approve plan.md and continue to the tasks stage.",
|
|
9851
9845
|
holdSummary: "Request plan changes before continuing."
|
|
@@ -9858,7 +9852,7 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
9858
9852
|
stage: "plan",
|
|
9859
9853
|
nextAction: buildAction(
|
|
9860
9854
|
isReviewStage ? "plan_approve" : "plan_write",
|
|
9861
|
-
isReviewStage ? approvalRequired ? "Get user approval and update plan.md status to Approved." : "Promote plan.md from Review to Approved and continue automatically." : "Write or refine plan.md until it is ready for approval.",
|
|
9855
|
+
isReviewStage ? planReviewAutoCompleted ? "The Plan review remediation limit was reached. Preserve the remaining findings as residual risks, promote plan.md from Review to Approved, and continue automatically without asking the user for review approval." : approvalRequired ? "Get user approval and update plan.md status to Approved." : "Promote plan.md from Review to Approved and continue automatically." : "Write or refine plan.md until it is ready for approval.",
|
|
9862
9856
|
approvalRequired
|
|
9863
9857
|
),
|
|
9864
9858
|
approvalRequired,
|
|
@@ -10045,32 +10039,7 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
10045
10039
|
};
|
|
10046
10040
|
const evidenceMatchesTarget = reviewTask.reviewedHead === reviewTarget.targetSha && reviewTask.reviewedTree === reviewTarget.targetTree;
|
|
10047
10041
|
if (reviewTask.reviewDecisionOutcome === "changes_requested") {
|
|
10048
|
-
if (reviewContext.reviewRound
|
|
10049
|
-
return {
|
|
10050
|
-
status: "ok",
|
|
10051
|
-
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|
|
10052
|
-
docsDir: config.docsDir,
|
|
10053
|
-
featureRef: buildFeatureRef(feature),
|
|
10054
|
-
stage: "review_escalation",
|
|
10055
|
-
nextAction: buildAction(
|
|
10056
|
-
"review_escalation",
|
|
10057
|
-
`Task review for ${reviewTask.taskId || reviewTask.title} requested more changes after ${reviewContext.maxReviewRounds} automatic remediation round(s) were used. Ask the user whether to authorize another remediation round or hold the Feature.`,
|
|
10058
|
-
true,
|
|
10059
|
-
null,
|
|
10060
|
-
void 0,
|
|
10061
|
-
reviewContext
|
|
10062
|
-
),
|
|
10063
|
-
approvalRequired: true,
|
|
10064
|
-
implementationAllowed: false,
|
|
10065
|
-
primaryActionLabel: "A",
|
|
10066
|
-
actionOptions: [
|
|
10067
|
-
buildStageOption("A", "A", "review_retry", "Increase workflow.agentReview.maxRounds, then run one more task remediation and fresh review round."),
|
|
10068
|
-
buildStageOption("B", "B", "hold", "Hold the Feature for user resolution.")
|
|
10069
|
-
],
|
|
10070
|
-
blockedReasonCode: "TASK_REVIEW_NOT_APPROVED"
|
|
10071
|
-
};
|
|
10072
|
-
}
|
|
10073
|
-
if (evidenceMatchesTarget) {
|
|
10042
|
+
if (evidenceMatchesTarget && reviewContext.reviewRound <= reviewContext.maxReviewRounds) {
|
|
10074
10043
|
return {
|
|
10075
10044
|
status: "ok",
|
|
10076
10045
|
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|
|
@@ -10112,7 +10081,7 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
10112
10081
|
};
|
|
10113
10082
|
}
|
|
10114
10083
|
if (taskReviewEvidenceSatisfied(config, feature, reviewTask, reviewTarget)) {
|
|
10115
|
-
const completionSummary = reviewTask.status === "DONE" ? `The independent review approved ${reviewTask.taskId || reviewTask.title} at the current code tree. Commit the review evidence before continuing.` : `The independent review approved ${reviewTask.taskId || reviewTask.title} at the current code tree. Mark the task DONE and commit the review evidence before starting another task.`;
|
|
10084
|
+
const completionSummary = reviewTask.reviewDecisionOutcome === "approve" ? reviewTask.status === "DONE" ? `The independent review approved ${reviewTask.taskId || reviewTask.title} at the current code tree. Commit the review evidence before continuing.` : `The independent review approved ${reviewTask.taskId || reviewTask.title} at the current code tree. Mark the task DONE and commit the review evidence before starting another task.` : reviewTask.status === "DONE" ? `The review remediation limit was reached for ${reviewTask.taskId || reviewTask.title}. Keep the remaining findings as residual risks and commit the review evidence before continuing automatically.` : `The review remediation limit was reached for ${reviewTask.taskId || reviewTask.title}. Keep the remaining findings as residual risks, mark the task DONE, and commit the review evidence before continuing automatically.`;
|
|
10116
10085
|
return {
|
|
10117
10086
|
status: "ok",
|
|
10118
10087
|
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|
|
@@ -10255,32 +10224,7 @@ async function collectWorkflowStage(cwd, selector, component) {
|
|
|
10255
10224
|
} : null;
|
|
10256
10225
|
const evidenceMatchesTarget = !!reviewTarget && tasks.prePrReviewedHead === reviewTarget.targetSha && tasks.prePrReviewedTree === reviewTarget.targetTree;
|
|
10257
10226
|
if (reviewContext && tasks.prePrDecisionOutcome === "changes_requested") {
|
|
10258
|
-
if (reviewContext.reviewRound
|
|
10259
|
-
return {
|
|
10260
|
-
status: "ok",
|
|
10261
|
-
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|
|
10262
|
-
docsDir: config.docsDir,
|
|
10263
|
-
featureRef: buildFeatureRef(feature),
|
|
10264
|
-
stage: "review_escalation",
|
|
10265
|
-
nextAction: buildAction(
|
|
10266
|
-
"review_escalation",
|
|
10267
|
-
`Feature review requested more changes after ${reviewContext.maxReviewRounds} automatic remediation round(s) were used. Ask the user whether to authorize another remediation round, accept the documented risk, change scope, or hold the Feature.`,
|
|
10268
|
-
true,
|
|
10269
|
-
null,
|
|
10270
|
-
void 0,
|
|
10271
|
-
reviewContext
|
|
10272
|
-
),
|
|
10273
|
-
approvalRequired: true,
|
|
10274
|
-
implementationAllowed: false,
|
|
10275
|
-
primaryActionLabel: "A",
|
|
10276
|
-
actionOptions: [
|
|
10277
|
-
buildStageOption("A", "A", "review_retry", "Increase workflow.agentReview.maxRounds, then run one more Feature remediation and fresh review round."),
|
|
10278
|
-
buildStageOption("B", "B", "hold", "Hold the Feature for user resolution.")
|
|
10279
|
-
],
|
|
10280
|
-
blockedReasonCode: "PRE_PR_REVIEW_NOT_APPROVED"
|
|
10281
|
-
};
|
|
10282
|
-
}
|
|
10283
|
-
if (evidenceMatchesTarget) {
|
|
10227
|
+
if (evidenceMatchesTarget && reviewContext.reviewRound <= reviewContext.maxReviewRounds) {
|
|
10284
10228
|
return {
|
|
10285
10229
|
status: "ok",
|
|
10286
10230
|
reasonCode: "WORKFLOW_STAGE_RESOLVED",
|