@opengsd/gsd-pi 1.2.0-dev.d6c5343c → 1.2.0-dev.ddc97c10
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/mcp-server.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +28 -10
- package/dist/resources/extensions/gsd/auto/phases.js +47 -4
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -2
- package/dist/resources/extensions/gsd/auto-model-selection.js +11 -7
- package/dist/resources/extensions/gsd/auto-post-unit.js +18 -6
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto.js +37 -1
- package/dist/resources/extensions/gsd/blocked-models.js +28 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
- package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
- package/dist/resources/extensions/gsd/consent-question.js +16 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -3
- package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
- package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
- package/dist/resources/extensions/gsd/gsd-db.js +2 -1
- package/dist/resources/extensions/gsd/guided-flow.js +6 -3
- package/dist/resources/extensions/gsd/milestone-closeout.js +73 -2
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +21 -2
- package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
- package/dist/resources/shared/package-manager-detection.js +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-check.d.ts +2 -0
- package/dist/update-check.js +24 -1
- package/dist/update-cmd.js +20 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/cli.js +10 -5
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
- package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +4 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +99 -38
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +2 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +12 -7
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +12 -3
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
- package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +11 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +28 -10
- package/src/resources/extensions/gsd/auto/phases.ts +63 -24
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +10 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +11 -10
- package/src/resources/extensions/gsd/auto-model-selection.ts +16 -7
- package/src/resources/extensions/gsd/auto-post-unit.ts +21 -6
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto.ts +44 -1
- package/src/resources/extensions/gsd/blocked-models.ts +49 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
- package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
- package/src/resources/extensions/gsd/consent-question.ts +15 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
- package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
- package/src/resources/extensions/gsd/gsd-db.ts +4 -3
- package/src/resources/extensions/gsd/guided-flow.ts +21 -26
- package/src/resources/extensions/gsd/milestone-closeout.ts +97 -2
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/consent-question.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/shared/gsd-browser-cli.ts +23 -2
- package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
- package/src/resources/shared/package-manager-detection.ts +1 -1
- /package/dist/web/standalone/.next/static/{jmTLg6xZmAuq_LIqKOxrH → McokybTayhff1xEVc-d3T}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{jmTLg6xZmAuq_LIqKOxrH → McokybTayhff1xEVc-d3T}/_ssgManifest.js +0 -0
|
@@ -9,7 +9,7 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent
|
|
|
9
9
|
import { existsSync, readFileSync, mkdirSync } from "node:fs";
|
|
10
10
|
import { execFileSync } from "node:child_process";
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
|
-
import { join, resolve as resolvePath, sep } from "node:path";
|
|
12
|
+
import { join, resolve as resolvePath, sep, win32 as pathWin32 } from "node:path";
|
|
13
13
|
import { homedir } from "node:os";
|
|
14
14
|
import { deriveState } from "./state.js";
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
@@ -29,6 +29,7 @@ import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
|
29
29
|
import { currentDirectoryRoot, projectRoot } from "./commands/context.js";
|
|
30
30
|
import { loadPrompt } from "./prompt-loader.js";
|
|
31
31
|
import { buildClaudeRuntimeFloorAdvisory } from "../../shared/claude-runtime-floor.js";
|
|
32
|
+
import { reconcileGsdBrowserPathAfterInstall } from "../../shared/gsd-browser-path-sync.js";
|
|
32
33
|
import { isPnpmInstall } from "../../shared/package-manager-detection.js";
|
|
33
34
|
import {
|
|
34
35
|
buildDoctorHealIssuePayload,
|
|
@@ -65,9 +66,33 @@ function isBunInstall(argv1: string | undefined = process.argv[1]): boolean {
|
|
|
65
66
|
function resolveInstallCommand(pkg: string): string {
|
|
66
67
|
if (isBunInstall()) return `bun add -g ${pkg}`;
|
|
67
68
|
if (isPnpmInstall()) return `pnpm add -g ${pkg}`;
|
|
69
|
+
const npmPrefix = resolveWindowsNpmGlobalPrefix();
|
|
70
|
+
if (npmPrefix) return `npm --prefix ${quoteWindowsArg(npmPrefix)} install -g ${pkg}`;
|
|
68
71
|
return `npm install -g ${pkg}`;
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
function resolveWindowsNpmGlobalPrefix(
|
|
75
|
+
argv1: string | undefined = process.argv[1],
|
|
76
|
+
platform: NodeJS.Platform = process.platform,
|
|
77
|
+
): string | null {
|
|
78
|
+
if (platform !== "win32" || !argv1) return null;
|
|
79
|
+
const normalized = pathWin32.normalize(argv1);
|
|
80
|
+
const marker = `${pathWin32.sep}node_modules${pathWin32.sep}`;
|
|
81
|
+
const index = normalized.toLowerCase().lastIndexOf(marker);
|
|
82
|
+
if (index <= 0) return null;
|
|
83
|
+
const prefix = normalized.slice(0, index);
|
|
84
|
+
// Verify this is a real npm global prefix: such a directory always contains
|
|
85
|
+
// npm's own bin shim (`npm.cmd`) as a sibling of `node_modules/`. Local
|
|
86
|
+
// project `node_modules/`, npx caches, and other non-global layouts do not,
|
|
87
|
+
// so without this check `--prefix` would target the wrong directory.
|
|
88
|
+
if (!existsSync(pathWin32.join(prefix, "npm.cmd"))) return null;
|
|
89
|
+
return prefix;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function quoteWindowsArg(value: string): string {
|
|
93
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
94
|
+
}
|
|
95
|
+
|
|
71
96
|
function notifyClaudeRuntimeFloorAdvisory(ctx: ExtensionCommandContext): void {
|
|
72
97
|
let advisory: string | null = null;
|
|
73
98
|
try {
|
|
@@ -576,12 +601,30 @@ export async function handleUpdate(ctx: ExtensionCommandContext, args = ""): Pro
|
|
|
576
601
|
execSync(installCmd, {
|
|
577
602
|
stdio: ["ignore", "pipe", "ignore"],
|
|
578
603
|
});
|
|
604
|
+
let reconcile: ReturnType<typeof reconcileGsdBrowserPathAfterInstall> | null = null;
|
|
605
|
+
if (browserUpdate) {
|
|
606
|
+
try {
|
|
607
|
+
reconcile = reconcileGsdBrowserPathAfterInstall({
|
|
608
|
+
latestVersion: latest,
|
|
609
|
+
compareSemver: compareSemverLocal,
|
|
610
|
+
resolvePathVersion: resolveGsdBrowserPathVersionForCommand,
|
|
611
|
+
});
|
|
612
|
+
} catch {
|
|
613
|
+
// Reconciliation is best-effort: the install above already succeeded,
|
|
614
|
+
// so a reconcile failure must not flip the result to "Update failed".
|
|
615
|
+
reconcile = null;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
579
618
|
const newPathVersion = browserUpdate ? resolveGsdBrowserPathVersionForCommand() : null;
|
|
580
|
-
const
|
|
619
|
+
const pathNote = browserUpdate && !(newPathVersion && compareSemverLocal(newPathVersion, latest) >= 0)
|
|
620
|
+
? (reconcile?.message
|
|
621
|
+
?? "Ensure the npm global bin directory is on your PATH so MCP automation uses the updated binary.")
|
|
622
|
+
: "";
|
|
581
623
|
ctx.ui.notify(
|
|
582
624
|
browserUpdate
|
|
583
625
|
? `Updated gsd-browser to v${latest}. Restart your GSD session to use the new browser automation version.` +
|
|
584
|
-
(
|
|
626
|
+
(reconcile?.action === "synced" && reconcile.message ? `\n${reconcile.message}` : "") +
|
|
627
|
+
(pathNote ? `\nNote: ${pathNote}` : "")
|
|
585
628
|
: `Updated to v${latest}. Restart your GSD session to use the new version.`,
|
|
586
629
|
"info",
|
|
587
630
|
);
|
|
@@ -107,6 +107,20 @@ export function hasResearchDecisionQuestion(text: string): boolean {
|
|
|
107
107
|
return hasQuestionMatching(text, [RESEARCH_DECISION_QUESTION_RE]);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Detect a plain-text "Next steps:" menu — numbered options with an "Other"
|
|
112
|
+
* choice — emitted as prose instead of a structured ask_user_questions call.
|
|
113
|
+
* Without this, auto-mode treats the menu as informational and loops on its
|
|
114
|
+
* own turn until tokens are exhausted (#454).
|
|
115
|
+
*/
|
|
116
|
+
export function hasPlainTextNextStepsMenu(lines: string[]): boolean {
|
|
117
|
+
const nextStepsIndex = lines.findIndex((line) => /^next steps\s*:?$/i.test(line));
|
|
118
|
+
if (nextStepsIndex < 0) return false;
|
|
119
|
+
const menuLines = lines.slice(nextStepsIndex + 1);
|
|
120
|
+
const numberedOptions = menuLines.filter((line) => /^\d+[.)]\s+\S/.test(line));
|
|
121
|
+
return numberedOptions.length >= 2 && numberedOptions.some((line) => /\bother\b/i.test(line));
|
|
122
|
+
}
|
|
123
|
+
|
|
110
124
|
// ── Message text extraction (moved from user-input-boundary) ────────────────
|
|
111
125
|
|
|
112
126
|
function extractMessageText(msg: unknown, includeThinking: boolean): string {
|
|
@@ -347,6 +361,7 @@ export function isAwaitingUserInput(messages: unknown[] | undefined): boolean {
|
|
|
347
361
|
if (!text) return false;
|
|
348
362
|
const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
349
363
|
if (lines.some((line) => line.endsWith("?"))) return true;
|
|
364
|
+
if (hasPlainTextNextStepsMenu(lines)) return true;
|
|
350
365
|
return hasApprovalQuestion(text);
|
|
351
366
|
}
|
|
352
367
|
|
|
@@ -223,6 +223,7 @@ export function writeLock(
|
|
|
223
223
|
* stale session-file pointer.
|
|
224
224
|
*/
|
|
225
225
|
export function clearLock(basePath: string): void {
|
|
226
|
+
const legacyLock = readLegacyLock(basePath);
|
|
226
227
|
clearLegacyLockFile(basePath);
|
|
227
228
|
|
|
228
229
|
if (!isDbAvailable()) return;
|
|
@@ -235,8 +236,15 @@ export function clearLock(basePath: string): void {
|
|
|
235
236
|
deleteRuntimeKv("worker", staleWorker.worker_id, SESSION_FILE_KV_KEY);
|
|
236
237
|
return;
|
|
237
238
|
}
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
if (legacyLock?.pid) {
|
|
240
|
+
markWorkerStoppingByPid(projectRoot, legacyLock.pid);
|
|
241
|
+
const workerByLegacyPid = getAllAutoWorkers().find(
|
|
242
|
+
(w) =>
|
|
243
|
+
w.pid === legacyLock.pid
|
|
244
|
+
&& normalizeRealPath(w.project_root_realpath) === projectRoot,
|
|
245
|
+
);
|
|
246
|
+
if (workerByLegacyPid) forceReleaseLeasesForWorker(workerByLegacyPid.worker_id);
|
|
247
|
+
}
|
|
240
248
|
const worker = findActiveWorkerForCurrentProcess(projectRoot);
|
|
241
249
|
if (worker) deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
242
250
|
|
|
@@ -7,7 +7,7 @@ import { isAfter, latestExplicitReopenAt } from "./milestone-reopen-events.js";
|
|
|
7
7
|
import { resolveGsdPathContract, resolveMilestoneFile } from "./paths.js";
|
|
8
8
|
import { deriveState } from "./state.js";
|
|
9
9
|
import { readEvents } from "./workflow-events.js";
|
|
10
|
-
import {
|
|
10
|
+
import { flushWorkflowProjections } from "./projection-flush.js";
|
|
11
11
|
|
|
12
12
|
export async function checkEngineHealth(
|
|
13
13
|
basePath: string,
|
|
@@ -270,7 +270,7 @@ export async function checkEngineHealth(
|
|
|
270
270
|
const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
|
|
271
271
|
if (!roadmapPath || !existsSync(roadmapPath)) {
|
|
272
272
|
try {
|
|
273
|
-
await
|
|
273
|
+
await flushWorkflowProjections(basePath, { milestoneId: milestone.id });
|
|
274
274
|
fixesApplied.push(`re-rendered missing projections for ${milestone.id}`);
|
|
275
275
|
} catch {
|
|
276
276
|
// Non-fatal — projection re-render failed
|
|
@@ -280,7 +280,7 @@ export async function checkEngineHealth(
|
|
|
280
280
|
const projectionMtime = statSync(roadmapPath).mtimeMs;
|
|
281
281
|
if (lastEventTs > projectionMtime) {
|
|
282
282
|
try {
|
|
283
|
-
await
|
|
283
|
+
await flushWorkflowProjections(basePath, { milestoneId: milestone.id });
|
|
284
284
|
fixesApplied.push(`re-rendered stale projections for ${milestone.id}`);
|
|
285
285
|
} catch {
|
|
286
286
|
// Non-fatal — projection re-render failed
|
|
@@ -5,10 +5,9 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
|
|
6
6
|
import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
|
|
7
7
|
import { loadFile } from "./files.js";
|
|
8
|
-
import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
9
|
-
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
10
8
|
import { resolveMilestoneFile } from "./paths.js";
|
|
11
|
-
import {
|
|
9
|
+
import { isCompletedMilestoneTerminal } from "./milestone-closeout.js";
|
|
10
|
+
import { deriveState } from "./state.js";
|
|
12
11
|
import { allWorktreesDirs, createWorktree, listWorktrees, resolveGitDir } from "./worktree-manager.js";
|
|
13
12
|
import { abortAndReset } from "./git-self-heal.js";
|
|
14
13
|
import { RUNTIME_EXCLUSION_PATHS, resolveMilestoneIntegrationBranch, writeIntegrationBranch } from "./git-service.js";
|
|
@@ -146,22 +145,6 @@ function getSnapshotDiffCheckFailure(basePath: string): string | null {
|
|
|
146
145
|
return failures.length > 0 ? failures.join("\n") : null;
|
|
147
146
|
}
|
|
148
147
|
|
|
149
|
-
async function isCompletedMilestoneTerminal(basePath: string, milestoneId: string): Promise<boolean> {
|
|
150
|
-
const summaryPath = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
151
|
-
if (!summaryPath) return false;
|
|
152
|
-
|
|
153
|
-
if (isDbAvailable()) {
|
|
154
|
-
const milestone = getMilestone(milestoneId);
|
|
155
|
-
return !!milestone && milestone.status === "complete";
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
159
|
-
const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
|
|
160
|
-
if (!roadmapContent) return false;
|
|
161
|
-
const roadmap = parseLegacyRoadmap(roadmapContent);
|
|
162
|
-
return isMilestoneComplete(roadmap);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
148
|
export async function checkGitHealth(
|
|
166
149
|
basePath: string,
|
|
167
150
|
issues: DoctorIssue[],
|
|
@@ -66,7 +66,7 @@ function disabled(description: string, reason: string): string {
|
|
|
66
66
|
|
|
67
67
|
export function buildGsdHomeModel(
|
|
68
68
|
state: GSDState,
|
|
69
|
-
closeout?: Pick<CloseoutContext, "strandedQuick" | "unmergedMilestones">,
|
|
69
|
+
closeout?: Pick<CloseoutContext, "strandedQuick" | "unmergedMilestones" | "idleResidueHint">,
|
|
70
70
|
): GsdHomeModel {
|
|
71
71
|
const blocked = isBlocked(state);
|
|
72
72
|
const complete = state.phase === "complete";
|
|
@@ -74,10 +74,14 @@ export function buildGsdHomeModel(
|
|
|
74
74
|
const workLabel = activeWorkLabel(state);
|
|
75
75
|
const strandedQuick = closeout?.strandedQuick ?? null;
|
|
76
76
|
const unmergedMilestone = closeout?.unmergedMilestones?.[0];
|
|
77
|
+
const idleResidueHint = closeout?.idleResidueHint ?? null;
|
|
78
|
+
const hasIdleResidue = Boolean(idleResidueHint);
|
|
77
79
|
const nextReason = complete
|
|
78
80
|
? "all milestones are complete"
|
|
79
81
|
: blocked
|
|
80
82
|
? "the active milestone is blocked"
|
|
83
|
+
: hasIdleResidue
|
|
84
|
+
? "milestone git residue needs recovery"
|
|
81
85
|
: !hasActiveWork
|
|
82
86
|
? "there is no active milestone"
|
|
83
87
|
: "";
|
|
@@ -91,6 +95,8 @@ export function buildGsdHomeModel(
|
|
|
91
95
|
? "finish_milestone"
|
|
92
96
|
: blocked
|
|
93
97
|
? "fix_recover"
|
|
98
|
+
: hasIdleResidue
|
|
99
|
+
? "fix_recover"
|
|
94
100
|
: canAdvance
|
|
95
101
|
? "continue_step"
|
|
96
102
|
: complete && unmappedActive > 0
|
|
@@ -107,6 +113,8 @@ export function buildGsdHomeModel(
|
|
|
107
113
|
? [`Quick task Q${strandedQuick.taskNum} finished on ${strandedQuick.quickBranch} but is not merged to ${strandedQuick.originalBranch}.`]
|
|
108
114
|
: unmergedMilestone
|
|
109
115
|
? [`${unmergedMilestone.milestoneId} is complete but not merged into ${unmergedMilestone.integrationBranch}.`]
|
|
116
|
+
: idleResidueHint
|
|
117
|
+
? [idleResidueHint.message]
|
|
110
118
|
: completionSummary;
|
|
111
119
|
|
|
112
120
|
return {
|
|
@@ -181,10 +189,12 @@ export function buildGsdHomeModel(
|
|
|
181
189
|
label: "Fix or recover",
|
|
182
190
|
description: blocked
|
|
183
191
|
? "Review the blocker and recovery commands for the active milestone."
|
|
192
|
+
: hasIdleResidue
|
|
193
|
+
? "Review stranded milestone worktrees/branches and run the suggested recovery command."
|
|
184
194
|
: disabled("This becomes active when closeout, validation, or state recovery is needed.", "no blocker is active"),
|
|
185
|
-
enabled: blocked,
|
|
195
|
+
enabled: blocked || hasIdleResidue,
|
|
186
196
|
recommended: recommended === "fix_recover",
|
|
187
|
-
disabledReason: blocked ? undefined : "no blocker is active",
|
|
197
|
+
disabledReason: blocked || hasIdleResidue ? undefined : "no blocker is active",
|
|
188
198
|
},
|
|
189
199
|
{
|
|
190
200
|
id: "start_configure",
|
|
@@ -246,9 +246,9 @@ export function insertMilestone(m: {
|
|
|
246
246
|
status?: string;
|
|
247
247
|
depends_on?: string[];
|
|
248
248
|
planning?: Partial<MilestonePlanningRecord>;
|
|
249
|
-
}):
|
|
249
|
+
}): boolean {
|
|
250
250
|
if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
251
|
-
getDbOrNull()!.prepare(
|
|
251
|
+
const result = getDbOrNull()!.prepare(
|
|
252
252
|
`INSERT OR IGNORE INTO milestones (
|
|
253
253
|
id, title, status, depends_on, created_at,
|
|
254
254
|
vision, success_criteria, key_risks, proof_strategy,
|
|
@@ -279,7 +279,8 @@ export function insertMilestone(m: {
|
|
|
279
279
|
":definition_of_done": JSON.stringify(m.planning?.definitionOfDone ?? []),
|
|
280
280
|
":requirement_coverage": m.planning?.requirementCoverage ?? "",
|
|
281
281
|
":boundary_map_markdown": m.planning?.boundaryMapMarkdown ?? "",
|
|
282
|
-
});
|
|
282
|
+
}) as { changes?: number };
|
|
283
|
+
return (result.changes ?? 0) > 0;
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
export function upsertMilestonePlanning(milestoneId: string, planning: Partial<MilestonePlanningRecord> & { title?: string; status?: string; depends_on?: string[] }): void {
|
|
@@ -78,11 +78,8 @@ import {
|
|
|
78
78
|
} from "./requirements-backlog.js";
|
|
79
79
|
import { selectAndApplyModel } from "./auto-model-selection.js";
|
|
80
80
|
import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
|
|
81
|
-
import {
|
|
82
|
-
|
|
83
|
-
getRequiredWorkflowToolsForGuidedUnit,
|
|
84
|
-
supportsStructuredQuestions,
|
|
85
|
-
} from "./workflow-mcp.js";
|
|
81
|
+
import { supportsStructuredQuestions } from "./workflow-mcp.js";
|
|
82
|
+
import { getUnitWorkflowDispatchReadinessError } from "./tool-contract.js";
|
|
86
83
|
import {
|
|
87
84
|
runPreparation,
|
|
88
85
|
formatCodebaseBrief,
|
|
@@ -555,7 +552,7 @@ interface DispatchWorkflowOptions {
|
|
|
555
552
|
deps?: {
|
|
556
553
|
loadPreferences?: typeof loadEffectiveGSDPreferences;
|
|
557
554
|
selectModel?: typeof selectAndApplyModel;
|
|
558
|
-
|
|
555
|
+
getDispatchReadinessError?: typeof getUnitWorkflowDispatchReadinessError;
|
|
559
556
|
};
|
|
560
557
|
}
|
|
561
558
|
|
|
@@ -584,7 +581,8 @@ async function dispatchWorkflow(
|
|
|
584
581
|
const projectRoot = resolveGuidedDispatchProjectRoot(resolvedOptions.basePath);
|
|
585
582
|
const loadPreferences = resolvedOptions.deps?.loadPreferences ?? loadEffectiveGSDPreferences;
|
|
586
583
|
const selectModel = resolvedOptions.deps?.selectModel ?? selectAndApplyModel;
|
|
587
|
-
const
|
|
584
|
+
const getDispatchReadinessError = resolvedOptions.deps?.getDispatchReadinessError
|
|
585
|
+
?? getUnitWorkflowDispatchReadinessError;
|
|
588
586
|
|
|
589
587
|
// Route through the dynamic routing pipeline (complexity classification,
|
|
590
588
|
// tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
|
|
@@ -603,25 +601,22 @@ async function dispatchWorkflow(
|
|
|
603
601
|
});
|
|
604
602
|
}
|
|
605
603
|
|
|
606
|
-
const compatibilityError =
|
|
607
|
-
result.appliedModel?.provider ?? ctx.model?.provider,
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
? ctx.modelRegistry.getProviderAuthMode(
|
|
615
|
-
:
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
// here — not whether MCP tools are pre-registered in the parent session.
|
|
623
|
-
},
|
|
624
|
-
);
|
|
604
|
+
const compatibilityError = getDispatchReadinessError({
|
|
605
|
+
provider: result.appliedModel?.provider ?? ctx.model?.provider,
|
|
606
|
+
projectRoot,
|
|
607
|
+
surface: "guided flow",
|
|
608
|
+
unitType,
|
|
609
|
+
authMode: result.appliedModel?.provider
|
|
610
|
+
? ctx.modelRegistry.getProviderAuthMode(result.appliedModel.provider)
|
|
611
|
+
: ctx.model?.provider
|
|
612
|
+
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
613
|
+
: undefined,
|
|
614
|
+
baseUrl: result.appliedModel?.baseUrl ?? ctx.model?.baseUrl,
|
|
615
|
+
// Guided flow starts the MCP workflow server as part of dispatch, so the
|
|
616
|
+
// parent session's activeTools doesn't include MCP tools yet. The MCP
|
|
617
|
+
// launch config check (detectWorkflowMcpLaunchConfig) is the right gate
|
|
618
|
+
// here — not whether MCP tools are pre-registered in the parent session.
|
|
619
|
+
});
|
|
625
620
|
if (compatibilityError) {
|
|
626
621
|
ctx.ui.notify(compatibilityError, "error");
|
|
627
622
|
return;
|
|
@@ -5,10 +5,20 @@
|
|
|
5
5
|
// - postUnit: git commit, artifact verify, DB settle, then GitHub finalize
|
|
6
6
|
// - recovery: DB repair from artifacts, then GitHub finalize
|
|
7
7
|
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
|
|
8
10
|
import { loadFile } from "./files.js";
|
|
9
11
|
import { resolveMilestoneFile } from "./paths.js";
|
|
10
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getMilestone,
|
|
14
|
+
getClosedSliceIds,
|
|
15
|
+
getLatestAssessmentByScope,
|
|
16
|
+
getMilestoneSlices,
|
|
17
|
+
isDbAvailable,
|
|
18
|
+
} from "./gsd-db.js";
|
|
11
19
|
import { isClosedStatus } from "./status-guards.js";
|
|
20
|
+
import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
|
|
21
|
+
import { handleCompleteMilestone } from "./tools/complete-milestone.js";
|
|
12
22
|
import { runSafely } from "./auto-utils.js";
|
|
13
23
|
import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
|
|
14
24
|
import { uatSignoffBlockerGuidance } from "./guidance.js";
|
|
@@ -28,6 +38,76 @@ import {
|
|
|
28
38
|
const COMPLETE_MILESTONE_DB_SETTLE_MS = 1500;
|
|
29
39
|
const COMPLETE_MILESTONE_DB_SETTLE_POLL_MS = 100;
|
|
30
40
|
|
|
41
|
+
/**
|
|
42
|
+
* True when a milestone is terminal for git cleanup (orphaned worktrees, stale branches).
|
|
43
|
+
* DB-authoritative (ADR-017): closed status, or validation-pass with all slices closed.
|
|
44
|
+
* When the DB is unavailable we cannot make this decision and conservatively
|
|
45
|
+
* return false so callers leave the worktree/branch alone instead of cleaning
|
|
46
|
+
* up based on parsed projections.
|
|
47
|
+
*/
|
|
48
|
+
export async function isCompletedMilestoneTerminal(
|
|
49
|
+
_basePath: string,
|
|
50
|
+
milestoneId: string,
|
|
51
|
+
): Promise<boolean> {
|
|
52
|
+
if (!isDbAvailable()) return false;
|
|
53
|
+
|
|
54
|
+
const milestone = getMilestone(milestoneId);
|
|
55
|
+
if (!milestone) return false;
|
|
56
|
+
|
|
57
|
+
if (isClosedStatus(milestone.status)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const validation = getLatestAssessmentByScope(milestoneId, "milestone-validation");
|
|
62
|
+
if (validation?.status !== "pass") {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
67
|
+
if (slices.length === 0) return false;
|
|
68
|
+
return slices.every((slice) => isClosedStatus(slice.status));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Write a missing milestone SUMMARY projection when canonical DB closeout already settled. */
|
|
72
|
+
export async function repairMissingMilestoneSummaryProjection(
|
|
73
|
+
basePath: string,
|
|
74
|
+
milestoneId: string,
|
|
75
|
+
): Promise<{ ok: true } | { ok: false; error: string }> {
|
|
76
|
+
const milestone = getMilestone(milestoneId);
|
|
77
|
+
if (!milestone) {
|
|
78
|
+
return { ok: false, error: `milestone not found: ${milestoneId}` };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, milestoneId);
|
|
82
|
+
const summaryPath = resolveExpectedArtifactPath("complete-milestone", milestoneId, artifactBasePath);
|
|
83
|
+
if (summaryPath && existsSync(summaryPath)) {
|
|
84
|
+
return { ok: true };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await handleCompleteMilestone(
|
|
88
|
+
{
|
|
89
|
+
milestoneId,
|
|
90
|
+
title: milestone.title,
|
|
91
|
+
oneLiner: "Canonical closeout completed; summary projection repaired automatically.",
|
|
92
|
+
narrative:
|
|
93
|
+
"The workflow database recorded this milestone as complete, but the milestone SUMMARY artifact was missing on disk. " +
|
|
94
|
+
"Dispatch policy repaired the projection so closeout proof and cleanup can proceed.",
|
|
95
|
+
verificationPassed: true,
|
|
96
|
+
triggerReason: "closeout-projection-repair",
|
|
97
|
+
},
|
|
98
|
+
basePath,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
if ("error" in result) {
|
|
102
|
+
return { ok: false, error: result.error };
|
|
103
|
+
}
|
|
104
|
+
const writtenSummaryPath = result.summaryPath;
|
|
105
|
+
if (result.stale || !writtenSummaryPath || !existsSync(writtenSummaryPath)) {
|
|
106
|
+
return { ok: false, error: "milestone SUMMARY projection write failed" };
|
|
107
|
+
}
|
|
108
|
+
return { ok: true };
|
|
109
|
+
}
|
|
110
|
+
|
|
31
111
|
/**
|
|
32
112
|
* True when the milestone is closed in the DB and the completion summary artifact exists.
|
|
33
113
|
* Polls briefly so post-unit verification can observe the tool's DB write.
|
|
@@ -78,7 +158,22 @@ export async function evaluateCompleteMilestoneDispatch(
|
|
|
78
158
|
if (isDbAvailable()) {
|
|
79
159
|
const milestone = getMilestone(mid);
|
|
80
160
|
if (milestone && isClosedStatus(milestone.status)) {
|
|
81
|
-
|
|
161
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, mid);
|
|
162
|
+
const summaryPath = resolveExpectedArtifactPath("complete-milestone", mid, artifactBasePath);
|
|
163
|
+
const summaryMissing = !summaryPath || !existsSync(summaryPath);
|
|
164
|
+
if (summaryMissing) {
|
|
165
|
+
const repair = await repairMissingMilestoneSummaryProjection(basePath, mid);
|
|
166
|
+
if (!repair.ok) {
|
|
167
|
+
logWarning(
|
|
168
|
+
"dispatch",
|
|
169
|
+
`Milestone ${mid} is closed in DB but SUMMARY repair failed: ${repair.error}. Dispatching complete-milestone to retry.`,
|
|
170
|
+
);
|
|
171
|
+
} else {
|
|
172
|
+
return { action: "skip" };
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
return { action: "skip" };
|
|
176
|
+
}
|
|
82
177
|
}
|
|
83
178
|
}
|
|
84
179
|
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./gsd-db.js";
|
|
16
16
|
import { invalidateStateCache } from "./state.js";
|
|
17
17
|
import { renderRoadmapFromDb } from "./markdown-renderer.js";
|
|
18
|
-
import {
|
|
18
|
+
import { flushWorkflowProjections } from "./projection-flush.js";
|
|
19
19
|
import { writeManifest } from "./workflow-manifest.js";
|
|
20
20
|
import { appendEvent } from "./workflow-events.js";
|
|
21
21
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -171,7 +171,7 @@ async function renderPlanArtifacts(
|
|
|
171
171
|
|
|
172
172
|
async function runPostPlanHooks(basePath: string, params: PersistMilestonePlanParams): Promise<void> {
|
|
173
173
|
try {
|
|
174
|
-
await
|
|
174
|
+
await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
|
|
175
175
|
writeManifest(basePath);
|
|
176
176
|
appendEvent(basePath, {
|
|
177
177
|
cmd: "plan-milestone",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Single workflow projection flush seam for mutation exits.
|
|
3
|
+
|
|
4
|
+
import { renderAllProjections } from "./workflow-projections.js";
|
|
5
|
+
|
|
6
|
+
export interface ProjectionFlushScope {
|
|
7
|
+
milestoneId: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ProjectionFlushResult {
|
|
11
|
+
milestoneId: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function flushWorkflowProjections(
|
|
15
|
+
basePath: string,
|
|
16
|
+
scope: ProjectionFlushScope,
|
|
17
|
+
): Promise<ProjectionFlushResult> {
|
|
18
|
+
await renderAllProjections(basePath, scope.milestoneId);
|
|
19
|
+
return { milestoneId: scope.milestoneId };
|
|
20
|
+
}
|
|
@@ -49,4 +49,4 @@ Use `subagent` only when useful: reviewer, security, or tester. Apply findings b
|
|
|
49
49
|
|
|
50
50
|
**You MUST call `gsd_slice_complete` with summary and UAT content only after verification passes.**
|
|
51
51
|
|
|
52
|
-
When done, say: "Slice {{sliceId}} complete."
|
|
52
|
+
When done, say: "Slice {{sliceId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -76,4 +76,4 @@ Keep about **{{verificationBudget}}** for verification and summary. If context i
|
|
|
76
76
|
|
|
77
77
|
**You MUST call `gsd_task_complete` before finishing, including when the stale-path safety rule stops execution.**
|
|
78
78
|
|
|
79
|
-
When done, say: "Task {{taskId}} complete."
|
|
79
|
+
When done, say: "Task {{taskId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -118,4 +118,4 @@ If external API keys or secrets are required, use the inlined **Secrets Manifest
|
|
|
118
118
|
|
|
119
119
|
If no external API keys or secrets are required, skip this step; do not create an empty manifest.
|
|
120
120
|
|
|
121
|
-
When done, say: "Milestone {{milestoneId}} planned."
|
|
121
|
+
When done, say: "Milestone {{milestoneId}} planned." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -57,4 +57,4 @@ The slice directory already exists. Do not mkdir.
|
|
|
57
57
|
|
|
58
58
|
**You MUST call `gsd_plan_slice` to persist planning state before finishing, unless the stale-path safety rule above stops the unit before safe planning can occur.**
|
|
59
59
|
|
|
60
|
-
When done, say: "Slice {{sliceId}} planned."
|
|
60
|
+
When done, say: "Slice {{sliceId}} planned." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -37,4 +37,4 @@ You are executing a GSD quick task — a lightweight, focused unit of work outsi
|
|
|
37
37
|
- <what was tested/verified>
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
When done, say: "Quick task {{taskNum}} complete."
|
|
40
|
+
When done, say: "Quick task {{taskNum}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -67,4 +67,4 @@ If `.gsd/REQUIREMENTS.md` exists and requirement ownership or status changed, up
|
|
|
67
67
|
|
|
68
68
|
**DB access safety:** Do NOT query `.gsd/gsd.db` directly via `sqlite3` or `node -e require('better-sqlite3')`. Use `gsd_milestone_status` to read current milestone and slice state. All roadmap mutations go through `gsd_reassess_roadmap` — the tool writes to the DB and re-renders ROADMAP.md atomically.
|
|
69
69
|
|
|
70
|
-
When done, say: "Roadmap reassessed."
|
|
70
|
+
When done, say: "Roadmap reassessed." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -77,4 +77,4 @@ The slice directory and tasks/ subdirectory already exist. Do NOT mkdir.
|
|
|
77
77
|
|
|
78
78
|
**You MUST call `gsd_plan_slice` to persist planning state before finishing.** After success, the pipeline clears the sketch flag on next state derivation; the on-disk PLAN file is the signal.
|
|
79
79
|
|
|
80
|
-
When done, say: "Slice {{sliceId}} refined."
|
|
80
|
+
When done, say: "Slice {{sliceId}} refined." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -38,4 +38,4 @@ Consider these captures when rewriting the remaining tasks — they represent th
|
|
|
38
38
|
4. If any incomplete task had a `T0x-PLAN.md`, remove or rewrite it to match the new task description.
|
|
39
39
|
5. Do not commit manually — the system auto-commits your changes after this unit completes.
|
|
40
40
|
|
|
41
|
-
When done, say: "Slice {{sliceId}} replanned."
|
|
41
|
+
When done, say: "Slice {{sliceId}} replanned." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -46,4 +46,4 @@ Then research the codebase and relevant technologies. Narrate key findings and s
|
|
|
46
46
|
|
|
47
47
|
**You MUST call `gsd_summary_save` with the research content before finishing.**
|
|
48
48
|
|
|
49
|
-
When done, say: "Milestone {{milestoneId}} researched."
|
|
49
|
+
When done, say: "Milestone {{milestoneId}} researched." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -55,4 +55,4 @@ The slice directory already exists at `{{slicePath}}/`. Do NOT mkdir.
|
|
|
55
55
|
|
|
56
56
|
**You MUST call `gsd_summary_save` with the research content before finishing.**
|
|
57
57
|
|
|
58
|
-
When done, say: "Slice {{sliceId}} researched."
|
|
58
|
+
When done, say: "Slice {{sliceId}} researched." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -30,4 +30,4 @@ An override was issued by the user that changes a fundamental decision or approa
|
|
|
30
30
|
|
|
31
31
|
**You MUST update the relevant documents AND mark overrides as resolved in `{{overridesPath}}` before finishing.**
|
|
32
32
|
|
|
33
|
-
When done, say: "Override applied across all documents."
|
|
33
|
+
When done, say: "Override applied across all documents." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -100,4 +100,4 @@ checks: [{
|
|
|
100
100
|
|
|
101
101
|
**You MUST call `gsd_uat_result_save` before finishing. Do not write the assessment file directly, and do not call `gsd_summary_save` as a substitute.**
|
|
102
102
|
|
|
103
|
-
When done, say: "UAT {{sliceId}} complete."
|
|
103
|
+
When done, say: "UAT {{sliceId}} complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -65,4 +65,4 @@ Classify each capture as one of:
|
|
|
65
65
|
|
|
66
66
|
**Important:** Do NOT execute any resolutions. Only classify and update CAPTURES.md. Resolution execution happens separately (in auto-mode dispatch or manually by the user).
|
|
67
67
|
|
|
68
|
-
When done, say: "Triage complete."
|
|
68
|
+
When done, say: "Triage complete." Say this exactly once — if you already said it in a prior message, do not repeat it.
|
|
@@ -87,4 +87,4 @@ If verdict is `needs-remediation`:
|
|
|
87
87
|
|
|
88
88
|
**File system safety:** When scanning milestone directories, use `ls` or `find` first. Never pass a directory path such as `tasks/` or `slices/` directly to `read`; it only accepts files.
|
|
89
89
|
|
|
90
|
-
When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>."
|
|
90
|
+
When done, say: "Milestone {{milestoneId}} validation complete — verdict: <verdict>." Say this exactly once — if you already said it in a prior message, do not repeat it.
|