lee-spec-kit 0.7.0 → 0.7.1
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 +1 -0
- package/dist/index.js +181 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/en/common/agents/agents.md +2 -1
- package/templates/en/common/agents/skills/execute-task.md +2 -1
- package/templates/ko/common/agents/agents.md +2 -1
- package/templates/ko/common/agents/skills/execute-task.md +2 -1
package/README.en.md
CHANGED
|
@@ -281,6 +281,7 @@ Use advanced selectors (`--component`, `--all`, `--done`) only when you need mul
|
|
|
281
281
|
- `--ticket` is required for `--execute` only when the selected action has `requiresUserCheck=true`.
|
|
282
282
|
- It is short-lived (5 minutes by default) and cannot be reused after one execution.
|
|
283
283
|
- When you `--execute` a handoff-only command (`pre_pr_review_run`, `code_review_run`), the result is `approved_handoff_prepared` with `nextMainState` instead of the normal `approved_executed`.
|
|
284
|
+
- Treat `approved_handoff_prepared` as delegated-work-required: continue the delegated review/fix loop immediately, do not re-approve the same label, and refresh `context` only after the required evidence/state update.
|
|
284
285
|
|
|
285
286
|
`context --json-compact` is the default recommended format, providing a minimal hot-path contract for agents.
|
|
286
287
|
Use `context --json` only when full-detail debugging fields are required.
|
package/dist/index.js
CHANGED
|
@@ -627,7 +627,7 @@ var koMessages = {
|
|
|
627
627
|
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)",
|
|
628
628
|
prePrReviewFieldMissing: "tasks.md\uC5D0 `PR \uC804 \uB9AC\uBDF0` \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. `- **PR \uC804 \uB9AC\uBDF0**: Pending | Running | Done` \uD56D\uBAA9\uC744 \uCD94\uAC00\uD558\uACE0 \uB2E4\uC2DC context\uB97C \uC2E4\uD589\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
629
629
|
prePrReviewRun: "\uCF54\uB4DC \uB9AC\uBDF0 \uC5D0\uC774\uC804\uD2B8\uB97C \uC2E4\uD589\uD574 `spec.md`/`plan.md`/`tasks.md` \uB300\uBE44 \uAD6C\uD604 \uC801\uD569\uC131\uC744 \uAC80\uD1A0\uD558\uACE0, `Summary`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Findings`/`Residual Risks`\uAC00 \uD3EC\uD568\uB41C `review-trace.json`\uC744 \uC0DD\uC131\uD55C \uB4A4 `pre-pr-review`\uB85C \uB9AC\uBDF0 \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. `pre-pr-review-run` \uC790\uCCB4\uB294 evidence\uB97C \uC0DD\uC131\uD558\uAC70\uB098 \uC0C1\uD0DC\uB97C \uBC14\uB85C \uB118\uAE30\uC9C0 \uC54A\uC73C\uBA70, \uD604\uC7AC evidence \uC815\uCC45\uC774 \uACBD\uB85C\uB97C \uC694\uAD6C\uD560 \uB54C\uB9CC `--evidence review-trace.json`\uC744 \uD568\uAED8 \uC0AC\uC6A9\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
630
|
-
prePrReviewRunning: "Pre-PR \uB9AC\uBDF0 handoff\uAC00 \uC774\uBBF8 \
|
|
630
|
+
prePrReviewRunning: "Pre-PR \uB9AC\uBDF0 handoff\uAC00 \uC774\uBBF8 \uC900\uBE44\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uAE30\uC874 delegated review\uB97C \uC7AC\uC0AC\uC6A9\uD558\uAC70\uB098 \uC774\uC5B4\uC11C \uC218\uD589\uD574 `review-trace.json`\uC744 \uB9CC\uB4E0 \uB4A4 `pre-pr-review`\uB85C \uACB0\uACFC\uB97C \uAE30\uB85D\uD558\uC138\uC694. \uAC19\uC740 \uB77C\uBCA8\uC744 \uB2E4\uC2DC \uC2B9\uC778 \uB8E8\uD504\uB85C \uC5F4\uC9C0 \uB9C8\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
631
631
|
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`/`Feature Intent Summary`/`Implementation Fit`/`Missing Cases`/`Spec Alignment Checked`/`Finding Count`/`Blocking Findings`/`Decision`/`Findings`(\uB610\uB294 \uBA85\uC2DC\uC801 `0 findings`)/`Residual Risks`\uB97C \uAE30\uB85D\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
632
632
|
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)",
|
|
633
633
|
prePrReviewFixRequired: "\uD604\uC7AC `PR \uC804 \uB9AC\uBDF0 Decision`\uC774 `{decision}`\uC785\uB2C8\uB2E4. PR \uC0DD\uC131 \uB2E8\uACC4\uB85C \uC774\uB3D9\uD558\uAE30 \uC804\uC5D0 pre-PR \uC9C0\uC801\uC0AC\uD56D\uC744 \uCF54\uB4DC\uC5D0 \uBC18\uC601\uD558\uC138\uC694. (\uD655\uC778 \uD544\uC694)",
|
|
@@ -1183,7 +1183,7 @@ var enMessages = {
|
|
|
1183
1183
|
prLegacyAsk: "tasks.md is missing PR/PR Status fields. Update to the latest template format? (CHECK required)",
|
|
1184
1184
|
prePrReviewFieldMissing: "tasks.md is missing the `Pre-PR Review` field. Add `- **Pre-PR Review**: Pending | Running | Done` and run context again. (CHECK required)",
|
|
1185
1185
|
prePrReviewRun: "Run the code review agent, compare the implementation against `spec.md`/`plan.md`/`tasks.md`, and generate `review-trace.json` with `Summary`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Findings`, and `Residual Risks`. Then record findings with `pre-pr-review`; `pre-pr-review-run` itself does not generate evidence or advance state, and you should use `--evidence review-trace.json` only when the active evidence policy requires a path. (CHECK required)",
|
|
1186
|
-
prePrReviewRunning: "Pre-PR review handoff is already
|
|
1186
|
+
prePrReviewRunning: "Pre-PR review handoff is already prepared. Reuse or resume the delegated review, generate `review-trace.json`, then record the result with `pre-pr-review`. Do not re-approve the same label. (CHECK required)",
|
|
1187
1187
|
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`, `Feature Intent Summary`, `Implementation Fit`, `Missing Cases`, `Spec Alignment Checked`, `Finding Count`, `Blocking Findings`, `Decision`, `Findings` (or explicit `0 findings`), and `Residual Risks`. (CHECK required)",
|
|
1188
1188
|
prePrReviewDecisionMissing: "tasks.md `Pre-PR Decision` is empty/placeholder or missing decision format. Record it as `decision: ...` (or `\uACB0\uC815: ...`). (CHECK required)",
|
|
1189
1189
|
prePrReviewFixRequired: "Current `Pre-PR Decision` is `{decision}`. Apply the requested fixes from pre-PR findings before moving to PR creation. (CHECK required)",
|
|
@@ -1990,6 +1990,7 @@ In approval-waiting state:
|
|
|
1990
1990
|
3. Do not paraphrase or omit these lines.
|
|
1991
1991
|
4. Prefer \`approvalRequest.userFacingLines\` as the source for user-facing approval text.
|
|
1992
1992
|
5. Prefer \`matchedFeature.currentSubstateOwner\` plus \`agentOrchestration.subAgentHandoff\` as the delegation SSOT. Treat \`currentActionShouldDelegate\` as a compatibility mirror for older consumers.
|
|
1993
|
+
6. When \`matchedFeature.currentSubstateOwner="subagent"\` and \`agentOrchestration.subAgentHandoff.required=true\` with \`mode="command"\`, call \`spawn_agent\` first and do not execute the delegated command directly from the main agent. If the delegated command is handoff-only, continue the delegated work immediately and do not re-open the same approval label.
|
|
1993
1994
|
|
|
1994
1995
|
In non-approval state (progress updates, analysis, tool execution logs, unrelated Q&A):
|
|
1995
1996
|
|
|
@@ -2004,23 +2005,35 @@ If approval is still pending after answering an unrelated question:
|
|
|
2004
2005
|
- \`actionOptions[*].approvalPrompt\` (label meaning included), and
|
|
2005
2006
|
- \`approvalRequest.finalPrompt\` (format line).
|
|
2006
2007
|
- Never output \`finalPrompt\` alone without the matching \`A: ...\` prompt.`;
|
|
2007
|
-
function
|
|
2008
|
+
function renderManagedSegment(lang, docsRepo) {
|
|
2008
2009
|
return `${LEE_SPEC_KIT_AGENTS_BEGIN}
|
|
2009
2010
|
${CANONICAL_LEE_SPEC_KIT_AGENTS_TEXT}
|
|
2010
|
-
${LEE_SPEC_KIT_AGENTS_END}
|
|
2011
|
+
${LEE_SPEC_KIT_AGENTS_END}`;
|
|
2012
|
+
}
|
|
2013
|
+
function renderManagedBlock(lang, docsRepo) {
|
|
2014
|
+
return `${renderManagedSegment()}
|
|
2011
2015
|
|
|
2012
2016
|
`;
|
|
2013
2017
|
}
|
|
2014
2018
|
async function upsertLeeSpecKitAgentsMd(filePath, options) {
|
|
2015
2019
|
const block = renderManagedBlock(options.lang, options.docsRepo);
|
|
2020
|
+
const segment = renderManagedSegment(options.lang, options.docsRepo);
|
|
2016
2021
|
const exists = await fs.pathExists(filePath);
|
|
2017
2022
|
if (!exists) {
|
|
2018
2023
|
await fs.writeFile(filePath, block, "utf-8");
|
|
2019
2024
|
return { changed: true, action: "created" };
|
|
2020
2025
|
}
|
|
2021
2026
|
const current = await fs.readFile(filePath, "utf-8");
|
|
2022
|
-
|
|
2023
|
-
|
|
2027
|
+
const beginIndex = current.indexOf(LEE_SPEC_KIT_AGENTS_BEGIN);
|
|
2028
|
+
const endIndex = current.indexOf(LEE_SPEC_KIT_AGENTS_END);
|
|
2029
|
+
if (beginIndex !== -1 && endIndex !== -1 && beginIndex <= endIndex) {
|
|
2030
|
+
const replaceEnd = endIndex + LEE_SPEC_KIT_AGENTS_END.length;
|
|
2031
|
+
const next2 = `${current.slice(0, beginIndex)}${segment}${current.slice(replaceEnd)}`;
|
|
2032
|
+
if (next2 === current) {
|
|
2033
|
+
return { changed: false, action: "noop" };
|
|
2034
|
+
}
|
|
2035
|
+
await fs.writeFile(filePath, next2, "utf-8");
|
|
2036
|
+
return { changed: true, action: "updated" };
|
|
2024
2037
|
}
|
|
2025
2038
|
let next = current;
|
|
2026
2039
|
if (next.length > 0 && !next.endsWith("\n")) next += "\n";
|
|
@@ -7491,7 +7504,7 @@ async function getFeatureNameFromSpec(fsAdapter, featureDir, fallbackSlug, fallb
|
|
|
7491
7504
|
return fallbackSlug || fallbackFolderName;
|
|
7492
7505
|
}
|
|
7493
7506
|
function updateCommand(program2) {
|
|
7494
|
-
program2.command("update").description("Update docs templates to the latest version").option("--agents", "Update agents/ folder only").option("--skills", "Cleanup legacy agents/skills copies (CLI-managed)").option("--templates", "Cleanup legacy feature-base copies (CLI-managed)").option(
|
|
7507
|
+
program2.command("update").description("Update docs templates to the latest version").option("--agents", "Update agents/ folder only").option("--agents-md", "Sync project-scoped AGENTS.md entrypoint").option("--skills", "Cleanup legacy agents/skills copies (CLI-managed)").option("--templates", "Cleanup legacy feature-base copies (CLI-managed)").option(
|
|
7495
7508
|
"-f, --force",
|
|
7496
7509
|
"Force overwrite even if docs has uncommitted changes"
|
|
7497
7510
|
).action(async (options) => {
|
|
@@ -7534,8 +7547,9 @@ async function runUpdate(options) {
|
|
|
7534
7547
|
const docsLockPath = getDocsLockPath(docsDir);
|
|
7535
7548
|
const forceOverwrite = !!options.force || await isDocsWorktreeCleanOrThrow(docsDir, lang, [docsLockPath]);
|
|
7536
7549
|
const configBackfill = await backfillMissingConfigDefaults(docsDir);
|
|
7537
|
-
const hasExplicitSelection = !!(options.agents || options.skills || options.templates);
|
|
7550
|
+
const hasExplicitSelection = !!(options.agents || options.agentsMd || options.skills || options.templates);
|
|
7538
7551
|
const updateAgents = options.agents || options.skills || !hasExplicitSelection;
|
|
7552
|
+
const updateAgentsMd = options.agentsMd || !hasExplicitSelection;
|
|
7539
7553
|
const updateTemplates = options.templates || !hasExplicitSelection;
|
|
7540
7554
|
const agentsMode = options.skills && !options.agents ? "skills" : "all";
|
|
7541
7555
|
console.log(chalk8.blue(tr(lang, "cli", "update.start")));
|
|
@@ -7591,6 +7605,18 @@ async function runUpdate(options) {
|
|
|
7591
7605
|
);
|
|
7592
7606
|
}
|
|
7593
7607
|
}
|
|
7608
|
+
if (updateAgentsMd) {
|
|
7609
|
+
const agentsMdTargets = await collectAgentsMdTargets(cwd, config);
|
|
7610
|
+
for (const target of agentsMdTargets) {
|
|
7611
|
+
const result = await upsertLeeSpecKitAgentsMd(target, {
|
|
7612
|
+
lang,
|
|
7613
|
+
docsRepo: config.docsRepo ?? "embedded"
|
|
7614
|
+
});
|
|
7615
|
+
if (result.changed) {
|
|
7616
|
+
updatedCount += 1;
|
|
7617
|
+
}
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7594
7620
|
if (updateTemplates) {
|
|
7595
7621
|
console.log(chalk8.blue(tr(lang, "cli", "update.updatingFeatureBase")));
|
|
7596
7622
|
console.log(chalk8.gray(tr(lang, "cli", "update.engineManagedFeatureBaseBuiltin")));
|
|
@@ -7625,6 +7651,42 @@ async function runUpdate(options) {
|
|
|
7625
7651
|
{ owner: "update" }
|
|
7626
7652
|
);
|
|
7627
7653
|
}
|
|
7654
|
+
function getGitTopLevelOrNull2(cwd) {
|
|
7655
|
+
try {
|
|
7656
|
+
const out = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
7657
|
+
cwd,
|
|
7658
|
+
encoding: "utf-8",
|
|
7659
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
7660
|
+
});
|
|
7661
|
+
const value = String(out || "").trim();
|
|
7662
|
+
return value ? value : null;
|
|
7663
|
+
} catch {
|
|
7664
|
+
return null;
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
async function collectAgentsMdTargets(cwd, config) {
|
|
7668
|
+
if (!config) return [];
|
|
7669
|
+
const targets = /* @__PURE__ */ new Set();
|
|
7670
|
+
const docsRepo = config.docsRepo ?? "embedded";
|
|
7671
|
+
if (docsRepo === "embedded") {
|
|
7672
|
+
const repoRoot = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || path12.resolve(config.docsDir, "..");
|
|
7673
|
+
targets.add(path12.join(repoRoot, "AGENTS.md"));
|
|
7674
|
+
return [...targets];
|
|
7675
|
+
}
|
|
7676
|
+
targets.add(path12.join(config.docsDir, "AGENTS.md"));
|
|
7677
|
+
const baseDir = getGitTopLevelOrNull2(cwd) || getGitTopLevelOrNull2(config.docsDir) || process.cwd();
|
|
7678
|
+
const rawRoots = typeof config.projectRoot === "string" ? [config.projectRoot] : config.projectRoot && typeof config.projectRoot === "object" ? Object.values(config.projectRoot) : [];
|
|
7679
|
+
for (const rawRoot of rawRoots) {
|
|
7680
|
+
const value = String(rawRoot || "").trim();
|
|
7681
|
+
if (!value) continue;
|
|
7682
|
+
const resolved = path12.resolve(baseDir, value);
|
|
7683
|
+
if (!await fs.pathExists(resolved)) continue;
|
|
7684
|
+
const stat = await fs.stat(resolved);
|
|
7685
|
+
if (!stat.isDirectory()) continue;
|
|
7686
|
+
targets.add(path12.join(resolved, "AGENTS.md"));
|
|
7687
|
+
}
|
|
7688
|
+
return [...targets];
|
|
7689
|
+
}
|
|
7628
7690
|
function isPlainObject(value) {
|
|
7629
7691
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
7630
7692
|
}
|
|
@@ -8749,6 +8811,73 @@ function buildApprovalCommand(state, featureName, selectedComponent, execute) {
|
|
|
8749
8811
|
}
|
|
8750
8812
|
return `npx lee-spec-kit context ${featureRef}${componentArg} --approve <LABEL>`;
|
|
8751
8813
|
}
|
|
8814
|
+
function buildFeatureComponentArgs(feature) {
|
|
8815
|
+
return feature.type && feature.type !== "single" ? ["--component", feature.type] : [];
|
|
8816
|
+
}
|
|
8817
|
+
function buildPrePrRecordCommand(feature, decision) {
|
|
8818
|
+
const args = [
|
|
8819
|
+
"pre-pr-review",
|
|
8820
|
+
feature.folderName,
|
|
8821
|
+
...buildFeatureComponentArgs(feature),
|
|
8822
|
+
"--evidence",
|
|
8823
|
+
"review-trace.json",
|
|
8824
|
+
"--decision",
|
|
8825
|
+
decision
|
|
8826
|
+
];
|
|
8827
|
+
return `npx lee-spec-kit ${args.join(" ")}`;
|
|
8828
|
+
}
|
|
8829
|
+
function buildDelegatedActionContract(state) {
|
|
8830
|
+
const feature = state.matchedFeature;
|
|
8831
|
+
const substateId = feature?.currentSubstateId;
|
|
8832
|
+
if (!feature || !substateId) return null;
|
|
8833
|
+
if (substateId === "pre_pr_review_run" || substateId === "pre_pr_review_running") {
|
|
8834
|
+
return {
|
|
8835
|
+
required: true,
|
|
8836
|
+
mode: "command",
|
|
8837
|
+
category: "pre_pr_review_run",
|
|
8838
|
+
currentSubstateId: substateId,
|
|
8839
|
+
delegatedWorkRequired: true,
|
|
8840
|
+
handoffOnly: true,
|
|
8841
|
+
advancesWorkflow: false,
|
|
8842
|
+
doNotReapproveSameLabel: substateId === "pre_pr_review_running",
|
|
8843
|
+
nextMainState: "pre_pr_review_running",
|
|
8844
|
+
reuseKey: `pre-pr:${feature.folderName}`,
|
|
8845
|
+
evidenceFile: "review-trace.json",
|
|
8846
|
+
nextStepRequirement: "generate_review_trace_then_record",
|
|
8847
|
+
recordCommands: {
|
|
8848
|
+
changesRequested: buildPrePrRecordCommand(
|
|
8849
|
+
feature,
|
|
8850
|
+
"changes_requested"
|
|
8851
|
+
),
|
|
8852
|
+
approve: buildPrePrRecordCommand(feature, "approve")
|
|
8853
|
+
},
|
|
8854
|
+
guidance: substateId === "pre_pr_review_running" ? "A pre-PR review handoff is already prepared. Reuse or resume the delegated review, generate review-trace.json, then record the result with pre-pr-review. Do not re-approve the same label." : "After approval, spawn_agent first and hand off the delegated pre-PR review. Handoff-only execution only prepares the review session; continue the delegated review immediately after approval."
|
|
8855
|
+
};
|
|
8856
|
+
}
|
|
8857
|
+
if (substateId === "code_review_run" || substateId === "code_review_running") {
|
|
8858
|
+
return {
|
|
8859
|
+
required: true,
|
|
8860
|
+
mode: "command",
|
|
8861
|
+
category: "code_review_run",
|
|
8862
|
+
currentSubstateId: substateId,
|
|
8863
|
+
delegatedWorkRequired: true,
|
|
8864
|
+
handoffOnly: true,
|
|
8865
|
+
advancesWorkflow: false,
|
|
8866
|
+
doNotReapproveSameLabel: substateId === "code_review_running",
|
|
8867
|
+
nextMainState: "code_review_running",
|
|
8868
|
+
reuseKey: `code-review:${feature.folderName}`,
|
|
8869
|
+
guidance: substateId === "code_review_running" ? "A PR review handoff is already prepared. Reuse or resume the delegated review-fix work, then refresh PR Review Evidence and PR Review Decision before continuing. Do not re-approve the same label." : "After approval, spawn_agent first and hand off the delegated PR review-fix work. Handoff-only execution only prepares the delegated session; continue the delegated work immediately after approval."
|
|
8870
|
+
};
|
|
8871
|
+
}
|
|
8872
|
+
return null;
|
|
8873
|
+
}
|
|
8874
|
+
function buildDelegatedApprovalGuidance(handoffRequired, handoffMode) {
|
|
8875
|
+
const base = "Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user. Keep `requiredDocs`, `checkPolicy`, and raw execution commands as internal guidance. For commit actions, include scope (`docs`/`project`) and commit message in the visible prompt. User replies should include the label token (e.g. `A`, `A OK`, `A proceed`, `A \uC9C4\uD589\uD574`).";
|
|
8876
|
+
const delegatedCommand = handoffRequired && handoffMode === "command" ? ' When `matchedFeature.currentSubstateOwner="subagent"` and `agentOrchestration.subAgentHandoff.required=true` with `mode="command"`, call spawn_agent first and do not execute the delegated command directly from the main agent. If the delegated command is handoff-only, `--execute` only prepares the handoff; continue the delegated work immediately and do not re-approve the same label.' : "";
|
|
8877
|
+
const nonDelegated = " For non-delegated command actions, prefer one-shot `npx lee-spec-kit flow <featureRef> --approve <LABEL> --execute` to avoid session mismatch after context compression/reset. Use ticket-based `context --execute --ticket` only when explicitly needed.";
|
|
8878
|
+
const orchestration = ' Use main-agent orchestration: keep short steps in main agent. Prefer `matchedFeature.currentSubstateOwner` + `agentOrchestration.subAgentHandoff` as the delegation SSOT; `currentActionShouldDelegate` is a compatibility mirror. Delegate auto-run only when `agentOrchestration.subAgentHandoff.required=true` with `mode="auto_run"`.';
|
|
8879
|
+
return `${base}${delegatedCommand}${nonDelegated}${orchestration}`;
|
|
8880
|
+
}
|
|
8752
8881
|
function buildFinalApprovalPrompt(lang, actionOptions) {
|
|
8753
8882
|
if (actionOptions.length === 0) return "";
|
|
8754
8883
|
const labels = listLabels(actionOptions);
|
|
@@ -9358,6 +9487,28 @@ function getCommandExecutionLockPath(action, config) {
|
|
|
9358
9487
|
}
|
|
9359
9488
|
return getProjectExecutionLockPath(action.cwd);
|
|
9360
9489
|
}
|
|
9490
|
+
function buildApprovedHandoffMetadata(action, featureRef) {
|
|
9491
|
+
if (action.category === "pre_pr_review_run") {
|
|
9492
|
+
return {
|
|
9493
|
+
delegatedWorkRequired: true,
|
|
9494
|
+
doNotReapproveSameLabel: true,
|
|
9495
|
+
reuseKey: `pre-pr:${featureRef}`,
|
|
9496
|
+
nextStepRequirement: "generate_review_trace_then_record",
|
|
9497
|
+
evidenceFile: "review-trace.json"
|
|
9498
|
+
};
|
|
9499
|
+
}
|
|
9500
|
+
if (action.category === "code_review_run") {
|
|
9501
|
+
return {
|
|
9502
|
+
delegatedWorkRequired: true,
|
|
9503
|
+
doNotReapproveSameLabel: true,
|
|
9504
|
+
reuseKey: `code-review:${featureRef}`
|
|
9505
|
+
};
|
|
9506
|
+
}
|
|
9507
|
+
return {
|
|
9508
|
+
delegatedWorkRequired: true,
|
|
9509
|
+
doNotReapproveSameLabel: true
|
|
9510
|
+
};
|
|
9511
|
+
}
|
|
9361
9512
|
async function runApprovedOption(state, config, lang, featureName, selectionOptions, options) {
|
|
9362
9513
|
const approval = options.approve || "";
|
|
9363
9514
|
const ticketToken = (options.ticket || "").trim();
|
|
@@ -9588,6 +9739,10 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
|
|
|
9588
9739
|
);
|
|
9589
9740
|
if (jsonMode) {
|
|
9590
9741
|
if (executionMetadata?.handoffOnly && !executionMetadata.advancesWorkflow) {
|
|
9742
|
+
const handoffMetadata = buildApprovedHandoffMetadata(
|
|
9743
|
+
selectedAction,
|
|
9744
|
+
freshState.matchedFeature?.folderName ?? featureRef
|
|
9745
|
+
);
|
|
9591
9746
|
console.log(
|
|
9592
9747
|
JSON.stringify(
|
|
9593
9748
|
{
|
|
@@ -9602,6 +9757,7 @@ async function runApprovedOption(state, config, lang, featureName, selectionOpti
|
|
|
9602
9757
|
handoffOnly: true,
|
|
9603
9758
|
advancesWorkflow: false,
|
|
9604
9759
|
nextMainState: executionMetadata.nextMainState,
|
|
9760
|
+
...handoffMetadata,
|
|
9605
9761
|
stdout: execResult.stdout?.trim() || void 0,
|
|
9606
9762
|
stderr: execResult.stderr?.trim() || void 0
|
|
9607
9763
|
},
|
|
@@ -9782,6 +9938,11 @@ async function runContext(featureName, options) {
|
|
|
9782
9938
|
state.matchedFeature?.folderName || null,
|
|
9783
9939
|
state.matchedFeature?.currentSubstateOwner
|
|
9784
9940
|
);
|
|
9941
|
+
const delegatedAction = buildDelegatedActionContract(state);
|
|
9942
|
+
const approvalGuidance = buildDelegatedApprovalGuidance(
|
|
9943
|
+
agentOrchestration.subAgentHandoff.required,
|
|
9944
|
+
agentOrchestration.subAgentHandoff.mode
|
|
9945
|
+
);
|
|
9785
9946
|
if (options.approve || options.execute) {
|
|
9786
9947
|
await runApprovedOption(
|
|
9787
9948
|
state,
|
|
@@ -9840,6 +10001,7 @@ async function runContext(featureName, options) {
|
|
|
9840
10001
|
agentOrchestration: {
|
|
9841
10002
|
subAgentHandoff: agentOrchestration.subAgentHandoff
|
|
9842
10003
|
},
|
|
10004
|
+
delegatedAction,
|
|
9843
10005
|
autoRun: {
|
|
9844
10006
|
available: autoRunPlan.available,
|
|
9845
10007
|
policyEligible: autoRunPlan.policyEligible,
|
|
@@ -9975,13 +10137,14 @@ async function runContext(featureName, options) {
|
|
|
9975
10137
|
"actionOptions[].detail",
|
|
9976
10138
|
"actionOptions[].approvalPrompt"
|
|
9977
10139
|
] : [],
|
|
9978
|
-
recommendation:
|
|
10140
|
+
recommendation: approvalGuidance,
|
|
9979
10141
|
oneApprovalPerAction: approvalRequired,
|
|
9980
10142
|
requireFreshContext: true,
|
|
9981
10143
|
contextVersion: state.contextVersion,
|
|
9982
10144
|
config: config.approval ?? { mode: "builtin" }
|
|
9983
10145
|
},
|
|
9984
10146
|
agentOrchestration,
|
|
10147
|
+
delegatedAction,
|
|
9985
10148
|
autoRun: {
|
|
9986
10149
|
available: autoRunPlan.available,
|
|
9987
10150
|
policyEligible: autoRunPlan.policyEligible,
|
|
@@ -9995,7 +10158,10 @@ async function runContext(featureName, options) {
|
|
|
9995
10158
|
guidance: 'Use auto-run only when `autoRun.available=true`. If `autoRun.policyEligible=true` but `autoRun.executableNow=false`, resolve `autoRun.manualBoundary` first. Do not treat `autoRun.available` alone as a delegation trigger; use `agentOrchestration.subAgentHandoff.required` + `mode="auto_run"` for actual delegation. Stop and request approval when `approvalRequest.required=true` or when auto mode reaches configured gate categories.'
|
|
9996
10159
|
},
|
|
9997
10160
|
approvalRequest: {
|
|
9998
|
-
guidance:
|
|
10161
|
+
guidance: approvalGuidance.replace(
|
|
10162
|
+
"Before asking for approval, show only `actionOptions[].approvalPrompt` lines and `approvalRequest.finalPrompt` to the user.",
|
|
10163
|
+
"User-facing output must include only approval prompts (`A: ...`) and `finalPrompt`."
|
|
10164
|
+
),
|
|
9999
10165
|
required: approvalRequired,
|
|
10000
10166
|
finalPrompt: finalApprovalPrompt,
|
|
10001
10167
|
userFacingLines: approvalUserFacingLines,
|
|
@@ -11403,6 +11569,7 @@ function toCompactFlowContextSnapshot(state) {
|
|
|
11403
11569
|
actionOptions: state.actionOptions.map(
|
|
11404
11570
|
(option) => toCompactFlowActionOption(option)
|
|
11405
11571
|
),
|
|
11572
|
+
delegatedAction: buildDelegatedActionContract(state),
|
|
11406
11573
|
primaryActionLabel: primaryAction?.label ?? null,
|
|
11407
11574
|
primaryActionType: primaryAction?.action.type ?? null,
|
|
11408
11575
|
primaryActionCategory: primaryAction?.action.category ?? null,
|
|
@@ -16183,6 +16350,7 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
16183
16350
|
suggestedParallelism: 1,
|
|
16184
16351
|
fallbackToMainAgentWhenQuotaExceeded: true,
|
|
16185
16352
|
nextStepRequirement: "generate_review_trace_then_record",
|
|
16353
|
+
delegatedWorkRequired: true,
|
|
16186
16354
|
nextMainState: "pre_pr_review_running",
|
|
16187
16355
|
evidenceFile: "review-trace.json",
|
|
16188
16356
|
tasksUpdated,
|
|
@@ -16220,6 +16388,9 @@ async function runPrePrReviewRun(featureName, options) {
|
|
|
16220
16388
|
console.log(`Suggested parallelism: 1`);
|
|
16221
16389
|
console.log(`Next main state: pre_pr_review_running`);
|
|
16222
16390
|
console.log(`Evidence file: review-trace.json`);
|
|
16391
|
+
console.log(
|
|
16392
|
+
config.lang === "ko" ? "Next required: delegated review\uB97C \uC774\uC5B4\uC11C \uC218\uD589\uD558\uACE0 review-trace.json\uC744 \uB9CC\uB4E0 \uB4A4 pre-pr-review\uB85C \uAE30\uB85D" : "Next required: continue the delegated review, generate review-trace.json, then record the result with pre-pr-review"
|
|
16393
|
+
);
|
|
16223
16394
|
if (tasksUpdated) {
|
|
16224
16395
|
console.log(`tasks.md updated: ${tasksPath}`);
|
|
16225
16396
|
console.log(
|