gsd-pi 2.44.0-dev.73f2fd5 → 2.44.0-dev.8894d5b
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/resources/extensions/gsd/auto/infra-errors.js +0 -3
- package/dist/resources/extensions/gsd/auto/phases.js +36 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -24
- package/dist/resources/extensions/gsd/auto-timers.js +3 -57
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -4
- package/dist/resources/extensions/gsd/auto-worktree.js +6 -9
- package/dist/resources/extensions/gsd/auto.js +3 -30
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +0 -136
- package/dist/resources/extensions/gsd/commands/catalog.js +1 -6
- package/dist/resources/extensions/gsd/commands/handlers/core.js +0 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +0 -5
- package/dist/resources/extensions/gsd/db-writer.js +16 -34
- package/dist/resources/extensions/gsd/doctor.js +0 -8
- package/dist/resources/extensions/gsd/git-service.js +3 -8
- package/dist/resources/extensions/gsd/gsd-db.js +1 -12
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -7
- package/dist/resources/extensions/gsd/tools/plan-slice.js +0 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +0 -1
- package/dist/resources/extensions/gsd/tools/replan-slice.js +0 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +0 -6
- package/dist/resources/extensions/mcp-client/index.js +0 -14
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
- 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 +2 -2
- 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 +20 -20
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +1 -3
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -15
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -11
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -20
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +0 -6
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +0 -17
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +1 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +0 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +2 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +8 -17
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -7
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -15
- package/packages/pi-coding-agent/src/core/model-registry.ts +1 -21
- package/packages/pi-coding-agent/src/core/settings-manager.ts +0 -9
- package/packages/pi-coding-agent/src/main.ts +0 -19
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +0 -15
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +3 -18
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -16
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +1 -8
- package/src/resources/extensions/gsd/auto/infra-errors.ts +0 -3
- package/src/resources/extensions/gsd/auto/phases.ts +48 -45
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -24
- package/src/resources/extensions/gsd/auto-timers.ts +3 -64
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -5
- package/src/resources/extensions/gsd/auto-worktree.ts +6 -9
- package/src/resources/extensions/gsd/auto.ts +3 -37
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +0 -129
- package/src/resources/extensions/gsd/commands/catalog.ts +1 -6
- package/src/resources/extensions/gsd/commands/handlers/core.ts +0 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +0 -5
- package/src/resources/extensions/gsd/db-writer.ts +17 -39
- package/src/resources/extensions/gsd/doctor.ts +1 -7
- package/src/resources/extensions/gsd/git-service.ts +2 -6
- package/src/resources/extensions/gsd/gsd-db.ts +1 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +14 -3
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -20
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -11
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +0 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +0 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +0 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +0 -7
- package/src/resources/extensions/mcp-client/index.ts +0 -20
- package/dist/resources/extensions/gsd/commands-mcp-status.js +0 -187
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +0 -88
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +0 -15
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.js +0 -41
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +0 -32
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +0 -15
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +0 -40
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +0 -1
- package/packages/pi-coding-agent/src/core/local-model-check.ts +0 -45
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +0 -38
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +0 -48
- package/src/resources/extensions/gsd/commands-mcp-status.ts +0 -247
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +0 -88
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +0 -114
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +0 -120
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +0 -103
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +0 -66
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +0 -67
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +0 -49
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +0 -127
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_ssgManifest.js +0 -0
|
@@ -162,7 +162,6 @@ export function syncGsdStateToWorktree(
|
|
|
162
162
|
"OVERRIDES.md",
|
|
163
163
|
"QUEUE.md",
|
|
164
164
|
"completed-units.json",
|
|
165
|
-
"metrics.json",
|
|
166
165
|
];
|
|
167
166
|
for (const f of rootFiles) {
|
|
168
167
|
const src = join(mainGsd, f);
|
|
@@ -326,9 +325,8 @@ export function syncWorktreeStateBack(
|
|
|
326
325
|
// ── 1. Sync root-level .gsd/ files back ──────────────────────────────
|
|
327
326
|
// The worktree is authoritative — complete-milestone updates REQUIREMENTS,
|
|
328
327
|
// PROJECT, etc. These must overwrite main's copies so they survive teardown.
|
|
329
|
-
// Also includes QUEUE.md
|
|
330
|
-
//
|
|
331
|
-
// (#1787, #2313).
|
|
328
|
+
// Also includes QUEUE.md and completed-units.json which are written during
|
|
329
|
+
// milestone closeout and lost on teardown without explicit sync (#1787).
|
|
332
330
|
const rootFiles = [
|
|
333
331
|
"DECISIONS.md",
|
|
334
332
|
"REQUIREMENTS.md",
|
|
@@ -337,7 +335,6 @@ export function syncWorktreeStateBack(
|
|
|
337
335
|
"OVERRIDES.md",
|
|
338
336
|
"QUEUE.md",
|
|
339
337
|
"completed-units.json",
|
|
340
|
-
"metrics.json",
|
|
341
338
|
];
|
|
342
339
|
for (const f of rootFiles) {
|
|
343
340
|
const src = join(wtGsd, f);
|
|
@@ -1323,9 +1320,9 @@ export function mergeMilestoneToMain(
|
|
|
1323
1320
|
}
|
|
1324
1321
|
}
|
|
1325
1322
|
|
|
1326
|
-
// 9b. Auto-create PR if enabled (
|
|
1323
|
+
// 9b. Auto-create PR if enabled (requires push_branches + push succeeded)
|
|
1327
1324
|
let prCreated = false;
|
|
1328
|
-
if (prefs.auto_pr === true &&
|
|
1325
|
+
if (prefs.auto_pr === true && pushed) {
|
|
1329
1326
|
const remote = prefs.remote ?? "origin";
|
|
1330
1327
|
const prTarget = prefs.pr_target_branch ?? mainBranch;
|
|
1331
1328
|
try {
|
|
@@ -1335,9 +1332,9 @@ export function mergeMilestoneToMain(
|
|
|
1335
1332
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1336
1333
|
encoding: "utf-8",
|
|
1337
1334
|
});
|
|
1338
|
-
// Create PR via gh CLI
|
|
1335
|
+
// Create PR via gh CLI
|
|
1339
1336
|
execFileSync("gh", [
|
|
1340
|
-
"pr", "create",
|
|
1337
|
+
"pr", "create",
|
|
1341
1338
|
"--base", prTarget,
|
|
1342
1339
|
"--head", milestoneBranch,
|
|
1343
1340
|
"--title", `Milestone ${milestoneId} complete`,
|
|
@@ -610,48 +610,14 @@ export async function stopAuto(
|
|
|
610
610
|
}
|
|
611
611
|
|
|
612
612
|
// ── Step 4: Auto-worktree exit ──
|
|
613
|
-
// When the milestone is complete (has a SUMMARY), merge the worktree branch
|
|
614
|
-
// back to main so code isn't stranded on the worktree branch (#2317).
|
|
615
|
-
// For incomplete milestones, preserve the branch for later resumption.
|
|
616
613
|
try {
|
|
617
614
|
if (s.currentMilestoneId) {
|
|
618
615
|
const notifyCtx = ctx
|
|
619
616
|
? { notify: ctx.ui.notify.bind(ctx.ui) }
|
|
620
617
|
: { notify: () => {} };
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
let milestoneComplete = false;
|
|
625
|
-
try {
|
|
626
|
-
const summaryPath = resolveMilestoneFile(
|
|
627
|
-
s.originalBasePath || s.basePath,
|
|
628
|
-
s.currentMilestoneId,
|
|
629
|
-
"SUMMARY",
|
|
630
|
-
);
|
|
631
|
-
if (!summaryPath) {
|
|
632
|
-
// Also check in the worktree path (SUMMARY may not be synced yet)
|
|
633
|
-
const wtSummaryPath = resolveMilestoneFile(
|
|
634
|
-
s.basePath,
|
|
635
|
-
s.currentMilestoneId,
|
|
636
|
-
"SUMMARY",
|
|
637
|
-
);
|
|
638
|
-
milestoneComplete = wtSummaryPath !== null;
|
|
639
|
-
} else {
|
|
640
|
-
milestoneComplete = true;
|
|
641
|
-
}
|
|
642
|
-
} catch {
|
|
643
|
-
// Non-fatal — fall through to preserveBranch path
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
if (milestoneComplete) {
|
|
647
|
-
// Milestone is complete — merge worktree branch back to main
|
|
648
|
-
resolver.mergeAndExit(s.currentMilestoneId, notifyCtx);
|
|
649
|
-
} else {
|
|
650
|
-
// Milestone still in progress — preserve branch for later resumption
|
|
651
|
-
resolver.exitMilestone(s.currentMilestoneId, notifyCtx, {
|
|
652
|
-
preserveBranch: true,
|
|
653
|
-
});
|
|
654
|
-
}
|
|
618
|
+
buildResolver().exitMilestone(s.currentMilestoneId, notifyCtx, {
|
|
619
|
+
preserveBranch: true,
|
|
620
|
+
});
|
|
655
621
|
}
|
|
656
622
|
} catch (e) {
|
|
657
623
|
debugLog("stop-cleanup-worktree", { error: e instanceof Error ? e.message : String(e) });
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
3
|
-
import { Text } from "@gsd/pi-tui";
|
|
4
3
|
|
|
5
4
|
import { findMilestoneIds, nextMilestoneId, claimReservedId, getReservedMilestoneIds } from "../guided-flow.js";
|
|
6
5
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
@@ -88,22 +87,6 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
88
87
|
], { description: "Who made this decision: 'human' (user directed), 'agent' (LLM decided autonomously), or 'collaborative' (discussed and agreed). Default: 'agent'" })),
|
|
89
88
|
}),
|
|
90
89
|
execute: decisionSaveExecute,
|
|
91
|
-
renderCall(args: any, theme: any) {
|
|
92
|
-
let text = theme.fg("toolTitle", theme.bold("decision_save "));
|
|
93
|
-
if (args.scope) text += theme.fg("accent", `[${args.scope}] `);
|
|
94
|
-
if (args.decision) text += theme.fg("muted", args.decision);
|
|
95
|
-
if (args.choice) text += theme.fg("dim", ` — ${args.choice}`);
|
|
96
|
-
return new Text(text, 0, 0);
|
|
97
|
-
},
|
|
98
|
-
renderResult(result: any, _options: any, theme: any) {
|
|
99
|
-
const d = result.details;
|
|
100
|
-
if (result.isError || d?.error) {
|
|
101
|
-
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
102
|
-
}
|
|
103
|
-
let text = theme.fg("success", `Decision ${d?.id ?? ""} saved`);
|
|
104
|
-
if (d?.id) text += theme.fg("dim", ` → DECISIONS.md`);
|
|
105
|
-
return new Text(text, 0, 0);
|
|
106
|
-
},
|
|
107
90
|
};
|
|
108
91
|
|
|
109
92
|
pi.registerTool(decisionSaveTool);
|
|
@@ -174,22 +157,6 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
174
157
|
supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })),
|
|
175
158
|
}),
|
|
176
159
|
execute: requirementUpdateExecute,
|
|
177
|
-
renderCall(args: any, theme: any) {
|
|
178
|
-
let text = theme.fg("toolTitle", theme.bold("requirement_update "));
|
|
179
|
-
if (args.id) text += theme.fg("accent", args.id);
|
|
180
|
-
const fields = ["status", "validation", "notes", "description"].filter((f) => args[f]);
|
|
181
|
-
if (fields.length > 0) text += theme.fg("dim", ` (${fields.join(", ")})`);
|
|
182
|
-
return new Text(text, 0, 0);
|
|
183
|
-
},
|
|
184
|
-
renderResult(result: any, _options: any, theme: any) {
|
|
185
|
-
const d = result.details;
|
|
186
|
-
if (result.isError || d?.error) {
|
|
187
|
-
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
188
|
-
}
|
|
189
|
-
let text = theme.fg("success", `Requirement ${d?.id ?? ""} updated`);
|
|
190
|
-
text += theme.fg("dim", ` → REQUIREMENTS.md`);
|
|
191
|
-
return new Text(text, 0, 0);
|
|
192
|
-
},
|
|
193
160
|
};
|
|
194
161
|
|
|
195
162
|
pi.registerTool(requirementUpdateTool);
|
|
@@ -268,22 +235,6 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
268
235
|
content: Type.String({ description: "The full markdown content of the artifact" }),
|
|
269
236
|
}),
|
|
270
237
|
execute: summarySaveExecute,
|
|
271
|
-
renderCall(args: any, theme: any) {
|
|
272
|
-
let text = theme.fg("toolTitle", theme.bold("summary_save "));
|
|
273
|
-
if (args.artifact_type) text += theme.fg("accent", args.artifact_type);
|
|
274
|
-
const path = [args.milestone_id, args.slice_id, args.task_id].filter(Boolean).join("/");
|
|
275
|
-
if (path) text += theme.fg("dim", ` ${path}`);
|
|
276
|
-
return new Text(text, 0, 0);
|
|
277
|
-
},
|
|
278
|
-
renderResult(result: any, _options: any, theme: any) {
|
|
279
|
-
const d = result.details;
|
|
280
|
-
if (result.isError || d?.error) {
|
|
281
|
-
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
282
|
-
}
|
|
283
|
-
let text = theme.fg("success", `${d?.artifact_type ?? "Artifact"} saved`);
|
|
284
|
-
if (d?.path) text += theme.fg("dim", ` → ${d.path}`);
|
|
285
|
-
return new Text(text, 0, 0);
|
|
286
|
-
},
|
|
287
238
|
};
|
|
288
239
|
|
|
289
240
|
pi.registerTool(summarySaveTool);
|
|
@@ -356,18 +307,6 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
356
307
|
],
|
|
357
308
|
parameters: Type.Object({}),
|
|
358
309
|
execute: milestoneGenerateIdExecute,
|
|
359
|
-
renderCall(_args: any, theme: any) {
|
|
360
|
-
return new Text(theme.fg("toolTitle", theme.bold("milestone_generate_id")), 0, 0);
|
|
361
|
-
},
|
|
362
|
-
renderResult(result: any, _options: any, theme: any) {
|
|
363
|
-
const d = result.details;
|
|
364
|
-
if (result.isError || d?.error) {
|
|
365
|
-
return new Text(theme.fg("error", `Error: ${d?.error ?? "unknown"}`), 0, 0);
|
|
366
|
-
}
|
|
367
|
-
let text = theme.fg("success", `Generated ${d?.id ?? "ID"}`);
|
|
368
|
-
if (d?.source === "reserved") text += theme.fg("dim", " (reserved)");
|
|
369
|
-
return new Text(text, 0, 0);
|
|
370
|
-
},
|
|
371
310
|
};
|
|
372
311
|
|
|
373
312
|
pi.registerTool(milestoneGenerateIdTool);
|
|
@@ -874,74 +813,6 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
874
813
|
pi.registerTool(milestoneCompleteTool);
|
|
875
814
|
registerAlias(pi, milestoneCompleteTool, "gsd_milestone_complete", "gsd_complete_milestone");
|
|
876
815
|
|
|
877
|
-
// ─── gsd_validate_milestone (gsd_milestone_validate alias) ─────────────
|
|
878
|
-
|
|
879
|
-
const milestoneValidateExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
880
|
-
const dbAvailable = await ensureDbOpen();
|
|
881
|
-
if (!dbAvailable) {
|
|
882
|
-
return {
|
|
883
|
-
content: [{ type: "text" as const, text: "Error: GSD database is not available. Cannot validate milestone." }],
|
|
884
|
-
details: { operation: "validate_milestone", error: "db_unavailable" } as any,
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
try {
|
|
888
|
-
const { handleValidateMilestone } = await import("../tools/validate-milestone.js");
|
|
889
|
-
const result = await handleValidateMilestone(params, process.cwd());
|
|
890
|
-
if ("error" in result) {
|
|
891
|
-
return {
|
|
892
|
-
content: [{ type: "text" as const, text: `Error validating milestone: ${result.error}` }],
|
|
893
|
-
details: { operation: "validate_milestone", error: result.error } as any,
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
return {
|
|
897
|
-
content: [{ type: "text" as const, text: `Validated milestone ${result.milestoneId} — verdict: ${result.verdict}. Written to ${result.validationPath}` }],
|
|
898
|
-
details: {
|
|
899
|
-
operation: "validate_milestone",
|
|
900
|
-
milestoneId: result.milestoneId,
|
|
901
|
-
verdict: result.verdict,
|
|
902
|
-
validationPath: result.validationPath,
|
|
903
|
-
} as any,
|
|
904
|
-
};
|
|
905
|
-
} catch (err) {
|
|
906
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
907
|
-
process.stderr.write(`gsd-db: validate_milestone tool failed: ${msg}\n`);
|
|
908
|
-
return {
|
|
909
|
-
content: [{ type: "text" as const, text: `Error validating milestone: ${msg}` }],
|
|
910
|
-
details: { operation: "validate_milestone", error: msg } as any,
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
};
|
|
914
|
-
|
|
915
|
-
const milestoneValidateTool = {
|
|
916
|
-
name: "gsd_validate_milestone",
|
|
917
|
-
label: "Validate Milestone",
|
|
918
|
-
description:
|
|
919
|
-
"Validate a milestone before completion — persist validation results to the DB, render VALIDATION.md to disk. " +
|
|
920
|
-
"Records verdict (pass/needs-attention/needs-remediation) and rationale.",
|
|
921
|
-
promptSnippet: "Validate a GSD milestone (DB write + VALIDATION.md render)",
|
|
922
|
-
promptGuidelines: [
|
|
923
|
-
"Use gsd_validate_milestone when all slices are done and the milestone needs validation before completion.",
|
|
924
|
-
"Parameters: milestoneId, verdict, remediationRound, successCriteriaChecklist, sliceDeliveryAudit, crossSliceIntegration, requirementCoverage, verdictRationale, remediationPlan (optional).",
|
|
925
|
-
"If verdict is 'needs-remediation', also provide remediationPlan and use gsd_reassess_roadmap to add remediation slices to the roadmap.",
|
|
926
|
-
"On success, returns validationPath where VALIDATION.md was written.",
|
|
927
|
-
],
|
|
928
|
-
parameters: Type.Object({
|
|
929
|
-
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
930
|
-
verdict: StringEnum(["pass", "needs-attention", "needs-remediation"], { description: "Validation verdict" }),
|
|
931
|
-
remediationRound: Type.Number({ description: "Remediation round (0 for first validation)" }),
|
|
932
|
-
successCriteriaChecklist: Type.String({ description: "Markdown checklist of success criteria with pass/fail and evidence" }),
|
|
933
|
-
sliceDeliveryAudit: Type.String({ description: "Markdown table auditing each slice's claimed vs delivered output" }),
|
|
934
|
-
crossSliceIntegration: Type.String({ description: "Markdown describing any cross-slice boundary mismatches" }),
|
|
935
|
-
requirementCoverage: Type.String({ description: "Markdown describing any unaddressed requirements" }),
|
|
936
|
-
verdictRationale: Type.String({ description: "Why this verdict was chosen" }),
|
|
937
|
-
remediationPlan: Type.Optional(Type.String({ description: "Remediation plan (required if verdict is needs-remediation)" })),
|
|
938
|
-
}),
|
|
939
|
-
execute: milestoneValidateExecute,
|
|
940
|
-
};
|
|
941
|
-
|
|
942
|
-
pi.registerTool(milestoneValidateTool);
|
|
943
|
-
registerAlias(pi, milestoneValidateTool, "gsd_milestone_validate", "gsd_validate_milestone");
|
|
944
|
-
|
|
945
816
|
// ─── gsd_replan_slice (gsd_slice_replan alias) ─────────────────────────
|
|
946
817
|
|
|
947
818
|
const replanSliceExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
@@ -15,7 +15,7 @@ export interface GsdCommandDefinition {
|
|
|
15
15
|
type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
|
|
16
16
|
|
|
17
17
|
export const GSD_COMMAND_DESCRIPTION =
|
|
18
|
-
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast
|
|
18
|
+
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|undo-task|reset-slice|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update|fast";
|
|
19
19
|
|
|
20
20
|
export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
21
21
|
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
|
@@ -68,7 +68,6 @@ export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
|
|
68
68
|
{ cmd: "templates", desc: "List available workflow templates" },
|
|
69
69
|
{ cmd: "extensions", desc: "Manage extensions (list, enable, disable, info)" },
|
|
70
70
|
{ cmd: "fast", desc: "Toggle OpenAI service tier (on/off/flex/status)" },
|
|
71
|
-
{ cmd: "mcp", desc: "MCP server status and connectivity check (status, check <server>)" },
|
|
72
71
|
{ cmd: "workflow", desc: "Custom workflow lifecycle (new, run, list, validate, pause, resume)" },
|
|
73
72
|
];
|
|
74
73
|
|
|
@@ -188,10 +187,6 @@ const NESTED_COMPLETIONS: CompletionMap = {
|
|
|
188
187
|
{ cmd: "flex", desc: "Flex tier (0.5x cost, slower)" },
|
|
189
188
|
{ cmd: "status", desc: "Show current service tier setting" },
|
|
190
189
|
],
|
|
191
|
-
mcp: [
|
|
192
|
-
{ cmd: "status", desc: "Show all MCP server statuses (default)" },
|
|
193
|
-
{ cmd: "check", desc: "Detailed status for a specific server" },
|
|
194
|
-
],
|
|
195
190
|
doctor: [
|
|
196
191
|
{ cmd: "fix", desc: "Auto-fix detected issues" },
|
|
197
192
|
{ cmd: "heal", desc: "AI-driven deep healing" },
|
|
@@ -53,7 +53,6 @@ export function showHelp(ctx: ExtensionCommandContext): void {
|
|
|
53
53
|
" /gsd hooks Show post-unit hook configuration",
|
|
54
54
|
" /gsd extensions Manage extensions [list|enable|disable|info]",
|
|
55
55
|
" /gsd fast Toggle OpenAI service tier [on|off|flex|status]",
|
|
56
|
-
" /gsd mcp MCP server status and connectivity [status|check <server>]",
|
|
57
56
|
"",
|
|
58
57
|
"MAINTENANCE",
|
|
59
58
|
" /gsd doctor Diagnose and repair .gsd/ state [audit|fix|heal] [scope]",
|
|
@@ -191,11 +191,6 @@ Examples:
|
|
|
191
191
|
await handleFast(trimmed.replace(/^fast\s*/, "").trim(), ctx);
|
|
192
192
|
return true;
|
|
193
193
|
}
|
|
194
|
-
if (trimmed === "mcp" || trimmed.startsWith("mcp ")) {
|
|
195
|
-
const { handleMcpStatus } = await import("../../commands-mcp-status.js");
|
|
196
|
-
await handleMcpStatus(trimmed.replace(/^mcp\s*/, "").trim(), ctx);
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
194
|
if (trimmed === "extensions" || trimmed.startsWith("extensions ")) {
|
|
200
195
|
const { handleExtensions } = await import("../../commands-extensions.js");
|
|
201
196
|
await handleExtensions(trimmed.replace(/^extensions\s*/, "").trim(), ctx);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// parseDecisionsTable() and parseRequirementsSections() with field fidelity.
|
|
10
10
|
|
|
11
11
|
import { join, resolve } from 'node:path';
|
|
12
|
-
import { readFileSync, existsSync
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
13
13
|
import type { Decision, Requirement } from './types.js';
|
|
14
14
|
import { resolveGsdRootFile } from './paths.js';
|
|
15
15
|
import { saveFile } from './files.js';
|
|
@@ -428,52 +428,30 @@ export async function saveArtifactToDb(
|
|
|
428
428
|
try {
|
|
429
429
|
const db = await import('./gsd-db.js');
|
|
430
430
|
|
|
431
|
-
// Guard against path traversal before any reads/writes
|
|
432
|
-
const gsdDir = resolve(basePath, '.gsd');
|
|
433
|
-
const fullPath = resolve(basePath, '.gsd', opts.path);
|
|
434
|
-
if (!fullPath.startsWith(gsdDir)) {
|
|
435
|
-
throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Shrinkage guard: if the file already exists and the new content is
|
|
439
|
-
// significantly smaller (<50%), preserve the richer file on disk and
|
|
440
|
-
// store its content in the DB instead of the abbreviated version.
|
|
441
|
-
let dbContent = opts.content;
|
|
442
|
-
let skipDiskWrite = false;
|
|
443
|
-
if (existsSync(fullPath)) {
|
|
444
|
-
const existingSize = statSync(fullPath).size;
|
|
445
|
-
const newSize = Buffer.byteLength(opts.content, 'utf-8');
|
|
446
|
-
if (existingSize > 0 && newSize < existingSize * 0.5) {
|
|
447
|
-
process.stderr.write(
|
|
448
|
-
`gsd-db: saveArtifactToDb — new content (${newSize}B) is <50% of existing file ` +
|
|
449
|
-
`(${existingSize}B) at ${opts.path}. Preserving disk file to prevent data loss.\n`,
|
|
450
|
-
);
|
|
451
|
-
dbContent = readFileSync(fullPath, 'utf-8');
|
|
452
|
-
skipDiskWrite = true;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
431
|
db.insertArtifact({
|
|
457
432
|
path: opts.path,
|
|
458
433
|
artifact_type: opts.artifact_type,
|
|
459
434
|
milestone_id: opts.milestone_id ?? null,
|
|
460
435
|
slice_id: opts.slice_id ?? null,
|
|
461
436
|
task_id: opts.task_id ?? null,
|
|
462
|
-
full_content:
|
|
437
|
+
full_content: opts.content,
|
|
463
438
|
});
|
|
464
439
|
|
|
465
|
-
// Write the file to disk (
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
440
|
+
// Write the file to disk (guard against path traversal)
|
|
441
|
+
const gsdDir = resolve(basePath, '.gsd');
|
|
442
|
+
const fullPath = resolve(basePath, '.gsd', opts.path);
|
|
443
|
+
if (!fullPath.startsWith(gsdDir)) {
|
|
444
|
+
throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
|
|
445
|
+
}
|
|
446
|
+
try {
|
|
447
|
+
await saveFile(fullPath, opts.content);
|
|
448
|
+
} catch (diskErr) {
|
|
449
|
+
process.stderr.write(
|
|
450
|
+
`gsd-db: saveArtifactToDb — disk write failed, rolling back DB row: ${(diskErr as Error).message}\n`,
|
|
451
|
+
);
|
|
452
|
+
const rollbackAdapter = db._getAdapter();
|
|
453
|
+
rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
|
|
454
|
+
throw diskErr;
|
|
477
455
|
}
|
|
478
456
|
// Invalidate file-read caches so deriveState() sees the updated markdown.
|
|
479
457
|
// Do NOT clear the artifacts table — we just wrote to it intentionally.
|
|
@@ -470,7 +470,7 @@ export async function runGSDDoctor(basePath: string, options?: { fix?: boolean;
|
|
|
470
470
|
if (!roadmapContent) continue;
|
|
471
471
|
|
|
472
472
|
// Normalize slices: prefer DB, fall back to parser
|
|
473
|
-
type NormSlice = RoadmapSliceEntry
|
|
473
|
+
type NormSlice = RoadmapSliceEntry;
|
|
474
474
|
let slices: NormSlice[];
|
|
475
475
|
if (isDbAvailable()) {
|
|
476
476
|
const dbSlices = getMilestoneSlices(milestoneId);
|
|
@@ -478,7 +478,6 @@ export async function runGSDDoctor(basePath: string, options?: { fix?: boolean;
|
|
|
478
478
|
id: s.id,
|
|
479
479
|
title: s.title,
|
|
480
480
|
done: s.status === "complete",
|
|
481
|
-
pending: s.status === "pending",
|
|
482
481
|
risk: (s.risk || "medium") as RoadmapSliceEntry["risk"],
|
|
483
482
|
depends: s.depends,
|
|
484
483
|
demo: s.demo,
|
|
@@ -565,9 +564,6 @@ export async function runGSDDoctor(basePath: string, options?: { fix?: boolean;
|
|
|
565
564
|
|
|
566
565
|
const slicePath = resolveSlicePath(basePath, milestoneId, slice.id);
|
|
567
566
|
if (!slicePath) {
|
|
568
|
-
// Pending slices haven't been planned yet — directories are created
|
|
569
|
-
// lazily by ensurePreconditions() at dispatch time. Skip them.
|
|
570
|
-
if (slice.pending) continue;
|
|
571
567
|
const expectedPath = relSlicePath(basePath, milestoneId, slice.id);
|
|
572
568
|
issues.push({
|
|
573
569
|
severity: slice.done ? "warning" : "error",
|
|
@@ -590,8 +586,6 @@ export async function runGSDDoctor(basePath: string, options?: { fix?: boolean;
|
|
|
590
586
|
|
|
591
587
|
const tasksDir = resolveTasksDir(basePath, milestoneId, slice.id);
|
|
592
588
|
if (!tasksDir) {
|
|
593
|
-
// Pending slices haven't been planned yet — tasks/ is created on demand.
|
|
594
|
-
if (slice.pending) continue;
|
|
595
589
|
issues.push({
|
|
596
590
|
severity: slice.done ? "warning" : "error",
|
|
597
591
|
code: "missing_tasks_dir",
|
|
@@ -684,17 +684,13 @@ export function createDraftPR(
|
|
|
684
684
|
milestoneId: string,
|
|
685
685
|
title: string,
|
|
686
686
|
body: string,
|
|
687
|
-
opts?: { head?: string; base?: string },
|
|
688
687
|
): string | null {
|
|
689
688
|
try {
|
|
690
|
-
const
|
|
689
|
+
const result = execFileSync("gh", [
|
|
691
690
|
"pr", "create", "--draft",
|
|
692
691
|
"--title", title,
|
|
693
692
|
"--body", body,
|
|
694
|
-
];
|
|
695
|
-
if (opts?.head) args.push("--head", opts.head);
|
|
696
|
-
if (opts?.base) args.push("--base", opts.base);
|
|
697
|
-
const result = execFileSync("gh", args, { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV });
|
|
693
|
+
], { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV });
|
|
698
694
|
return result.trim();
|
|
699
695
|
} catch {
|
|
700
696
|
return null;
|
|
@@ -301,7 +301,6 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
|
|
|
301
301
|
inputs TEXT NOT NULL DEFAULT '[]',
|
|
302
302
|
expected_output TEXT NOT NULL DEFAULT '[]',
|
|
303
303
|
observability_impact TEXT NOT NULL DEFAULT '',
|
|
304
|
-
full_plan_md TEXT NOT NULL DEFAULT '',
|
|
305
304
|
sequence INTEGER DEFAULT 0, -- DEAD CODE: no tool exposes sequence — always 0
|
|
306
305
|
PRIMARY KEY (milestone_id, slice_id, id),
|
|
307
306
|
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
@@ -617,15 +616,6 @@ function migrateSchema(db: DbAdapter): void {
|
|
|
617
616
|
});
|
|
618
617
|
}
|
|
619
618
|
|
|
620
|
-
if (currentVersion < 11) {
|
|
621
|
-
ensureColumn(db, "tasks", "full_plan_md", `ALTER TABLE tasks ADD COLUMN full_plan_md TEXT NOT NULL DEFAULT ''`);
|
|
622
|
-
|
|
623
|
-
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
|
|
624
|
-
":version": 11,
|
|
625
|
-
":applied_at": new Date().toISOString(),
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
|
|
629
619
|
db.exec("COMMIT");
|
|
630
620
|
} catch (err) {
|
|
631
621
|
db.exec("ROLLBACK");
|
|
@@ -933,7 +923,6 @@ export interface TaskPlanningRecord {
|
|
|
933
923
|
inputs: string[];
|
|
934
924
|
expectedOutput: string[];
|
|
935
925
|
observabilityImpact: string;
|
|
936
|
-
fullPlanMd?: string;
|
|
937
926
|
}
|
|
938
927
|
|
|
939
928
|
export function insertMilestone(m: {
|
|
@@ -1174,8 +1163,7 @@ export function upsertTaskPlanning(milestoneId: string, sliceId: string, taskId:
|
|
|
1174
1163
|
verify = COALESCE(:verify, verify),
|
|
1175
1164
|
inputs = COALESCE(:inputs, inputs),
|
|
1176
1165
|
expected_output = COALESCE(:expected_output, expected_output),
|
|
1177
|
-
observability_impact = COALESCE(:observability_impact, observability_impact)
|
|
1178
|
-
full_plan_md = COALESCE(:full_plan_md, full_plan_md)
|
|
1166
|
+
observability_impact = COALESCE(:observability_impact, observability_impact)
|
|
1179
1167
|
WHERE milestone_id = :milestone_id AND slice_id = :slice_id AND id = :id`,
|
|
1180
1168
|
).run({
|
|
1181
1169
|
":milestone_id": milestoneId,
|
|
@@ -1189,7 +1177,6 @@ export function upsertTaskPlanning(milestoneId: string, sliceId: string, taskId:
|
|
|
1189
1177
|
":inputs": planning.inputs ? JSON.stringify(planning.inputs) : null,
|
|
1190
1178
|
":expected_output": planning.expectedOutput ? JSON.stringify(planning.expectedOutput) : null,
|
|
1191
1179
|
":observability_impact": planning.observabilityImpact ?? null,
|
|
1192
|
-
":full_plan_md": planning.fullPlanMd ?? null,
|
|
1193
1180
|
});
|
|
1194
1181
|
}
|
|
1195
1182
|
|
|
@@ -1281,7 +1268,6 @@ export interface TaskRow {
|
|
|
1281
1268
|
inputs: string[];
|
|
1282
1269
|
expected_output: string[];
|
|
1283
1270
|
observability_impact: string;
|
|
1284
|
-
full_plan_md: string;
|
|
1285
1271
|
sequence: number;
|
|
1286
1272
|
}
|
|
1287
1273
|
|
|
@@ -1310,7 +1296,6 @@ function rowToTask(row: Record<string, unknown>): TaskRow {
|
|
|
1310
1296
|
inputs: JSON.parse((row["inputs"] as string) || "[]"),
|
|
1311
1297
|
expected_output: JSON.parse((row["expected_output"] as string) || "[]"),
|
|
1312
1298
|
observability_impact: (row["observability_impact"] as string) ?? "",
|
|
1313
|
-
full_plan_md: (row["full_plan_md"] as string) ?? "",
|
|
1314
1299
|
sequence: (row["sequence"] as number) ?? 0,
|
|
1315
1300
|
};
|
|
1316
1301
|
}
|
|
@@ -387,7 +387,7 @@ export async function renderTaskPlanFromDb(
|
|
|
387
387
|
mkdirSync(tasksDir, { recursive: true });
|
|
388
388
|
const absPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
389
389
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
390
|
-
const content =
|
|
390
|
+
const content = renderTaskPlanMarkdown(task);
|
|
391
391
|
|
|
392
392
|
await writeAndStore(absPath, artifactPath, content, {
|
|
393
393
|
artifact_type: "PLAN",
|
|
@@ -21,8 +21,8 @@ Then:
|
|
|
21
21
|
4. Verify each **success criterion** from the milestone definition in `{{roadmapPath}}`. For each criterion, confirm it was met with specific evidence from slice summaries, test results, or observable behavior. List any criterion that was NOT met.
|
|
22
22
|
5. Verify the milestone's **definition of done** — all slices are `[x]`, all slice summaries exist, and any cross-slice integration points work correctly.
|
|
23
23
|
6. Validate **requirement status transitions**. For each requirement that changed status during this milestone, confirm the transition is supported by evidence. Requirements can move between Active, Validated, Deferred, Blocked, or Out of Scope — but only with proof.
|
|
24
|
-
7.
|
|
25
|
-
8. Update `.gsd/REQUIREMENTS.md` if any requirement status transitions were validated in step
|
|
24
|
+
7. Write `{{milestoneSummaryPath}}` using the milestone-summary template. Fill all frontmatter fields and narrative sections. The `requirement_outcomes` field must list every requirement that changed status with `from_status`, `to_status`, and `proof`.
|
|
25
|
+
8. Update `.gsd/REQUIREMENTS.md` if any requirement status transitions were validated in step 5.
|
|
26
26
|
9. Update `.gsd/PROJECT.md` to reflect milestone completion and current project state.
|
|
27
27
|
10. Review all slice summaries for cross-cutting lessons, patterns, or gotchas that emerged during this milestone. Append any non-obvious, reusable insights to `.gsd/KNOWLEDGE.md`.
|
|
28
28
|
11. Do not commit manually — the system auto-commits your changes after this unit completes.
|
|
@@ -31,4 +31,6 @@ Then:
|
|
|
31
31
|
|
|
32
32
|
**File system safety:** When scanning milestone directories for evidence, use `ls` or `find` to list directory contents first — never pass a directory path (e.g. `tasks/`, `slices/`) directly to the `read` tool. The `read` tool only accepts file paths, not directories.
|
|
33
33
|
|
|
34
|
+
**You MUST write `{{milestoneSummaryPath}}` AND update PROJECT.md before finishing.**
|
|
35
|
+
|
|
34
36
|
When done, say: "Milestone {{milestoneId}} complete."
|
|
@@ -63,7 +63,7 @@ Then:
|
|
|
63
63
|
- a matching task plan file with description, steps, must-haves, verification, inputs, and expected output
|
|
64
64
|
- **Inputs and Expected Output must list concrete backtick-wrapped file paths** (e.g. `` `src/types.ts` ``). These are machine-parsed to derive task dependencies — vague prose without paths breaks parallel execution. Every task must have at least one output file path.
|
|
65
65
|
- Observability Impact section **only if the task touches runtime boundaries, async flows, or error paths** — omit it otherwise
|
|
66
|
-
6. **Persist planning state through
|
|
66
|
+
6. **Persist planning state through DB-backed tools.** Call `gsd_plan_slice` with the full slice planning payload (goal, demo, must-haves, verification, tasks, and metadata). Then call `gsd_plan_task` for each task to persist its planning fields. These tools write to the DB and render `{{outputPath}}` and `{{slicePath}}/tasks/T##-PLAN.md` files automatically. Do **not** rely on direct `PLAN.md` writes as the source of truth; the DB-backed tools are the canonical write path for slice and task planning state.
|
|
67
67
|
7. **Self-audit the plan.** Walk through each check — if any fail, fix the plan files before moving on:
|
|
68
68
|
- **Completion semantics:** If every task were completed exactly as written, the slice goal/demo should actually be true.
|
|
69
69
|
- **Requirement coverage:** Every must-have in the slice maps to at least one task. No must-have is orphaned. If `REQUIREMENTS.md` exists, every Active requirement this slice owns maps to at least one task.
|
|
@@ -50,14 +50,14 @@ If all criteria have at least one remaining owning slice, the coverage check pas
|
|
|
50
50
|
|
|
51
51
|
**If the roadmap is still good:**
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Write `{{assessmentPath}}` with a brief confirmation that roadmap coverage still holds after {{completedSliceId}}. If requirements exist, explicitly note whether requirement coverage remains sound. If `gsd_reassess_roadmap` is available, use it with `verdict: "roadmap-confirmed"`, an empty `sliceChanges` object, and the assessment text — the tool writes the assessment to the DB and renders ASSESSMENT.md.
|
|
54
54
|
|
|
55
55
|
**If changes are needed:**
|
|
56
56
|
|
|
57
|
-
**Persist changes through `gsd_reassess_roadmap`.** Pass: `milestoneId`, `completedSliceId`, `verdict` (e.g. "roadmap-adjusted"), `assessment` (text explaining the decision), and `sliceChanges` with `modified` (array of sliceId, title, risk, depends, demo), `added` (same shape), `removed` (array of slice ID strings). The tool structurally enforces preservation of completed slices, writes the assessment to the DB, re-renders
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{{commitInstruction}}
|
|
57
|
+
1. **Persist changes through `gsd_reassess_roadmap`.** Pass: `milestoneId`, `completedSliceId`, `verdict` (e.g. "roadmap-adjusted"), `assessment` (text explaining the decision), and `sliceChanges` with `modified` (array of sliceId, title, risk, depends, demo), `added` (same shape), `removed` (array of slice ID strings). The tool structurally enforces preservation of completed slices, writes the assessment to the DB, re-renders ROADMAP.md, and renders ASSESSMENT.md. Skip step 2 when this tool succeeds.
|
|
58
|
+
2. **Degraded fallback — direct file writes:** If `gsd_reassess_roadmap` is not available, rewrite the remaining (unchecked) slices in `{{roadmapPath}}` directly. Keep completed slices exactly as they are (`[x]`). Update the boundary map for changed slices. Update the proof strategy if risks changed. Update requirement coverage if ownership or scope changed.
|
|
59
|
+
3. Write `{{assessmentPath}}` explaining what changed and why — keep it brief and concrete.
|
|
60
|
+
4. If `.gsd/REQUIREMENTS.md` exists and requirement ownership or status changed, update it.
|
|
61
|
+
5. {{commitInstruction}}
|
|
62
62
|
|
|
63
63
|
When done, say: "Roadmap reassessed."
|
|
@@ -32,8 +32,19 @@ Consider these captures when rewriting the remaining tasks — they represent th
|
|
|
32
32
|
|
|
33
33
|
1. Read the blocker task summary carefully. Understand exactly what was discovered and why it blocks the current plan.
|
|
34
34
|
2. Analyze the remaining `[ ]` tasks in the slice plan. Determine which are still valid, which need modification, and which should be replaced.
|
|
35
|
-
3. **Persist replan state through `gsd_replan_slice`.** Call it with: `milestoneId`, `sliceId`, `blockerTaskId`, `blockerDescription`, `whatChanged`, `updatedTasks` (array of task objects with taskId, title, description, estimate, files, verify, inputs, expectedOutput), `removedTaskIds` (array of task ID strings). The tool structurally enforces preservation of completed tasks, writes replan history to the DB, re-renders
|
|
36
|
-
4.
|
|
37
|
-
|
|
35
|
+
3. **Persist replan state through `gsd_replan_slice`.** Call it with the following parameters: `milestoneId`, `sliceId`, `blockerTaskId`, `blockerDescription`, `whatChanged`, `updatedTasks` (array of task objects with taskId, title, description, estimate, files, verify, inputs, expectedOutput), `removedTaskIds` (array of task ID strings). The tool structurally enforces preservation of completed tasks, writes replan history to the DB, re-renders PLAN.md, and renders REPLAN.md. Skip steps 4–5 when this tool succeeds.
|
|
36
|
+
4. **Degraded fallback — direct file writes:** If `gsd_replan_slice` is not available, fall back to writing files directly. Write `{{replanPath}}` documenting:
|
|
37
|
+
- What blocker was discovered and in which task
|
|
38
|
+
- What changed in the plan and why
|
|
39
|
+
- Which incomplete tasks were modified, added, or removed
|
|
40
|
+
- Any new risks or considerations introduced by the replan
|
|
41
|
+
5. If using the degraded fallback, rewrite `{{planPath}}` with the updated slice plan:
|
|
42
|
+
- Keep all `[x]` tasks exactly as they were (same IDs, same descriptions, same checkmarks)
|
|
43
|
+
- Update the `[ ]` tasks to address the blocker
|
|
44
|
+
- Ensure the slice Goal and Demo sections are still achievable with the new tasks, or update them if the blocker fundamentally changes what the slice can deliver
|
|
45
|
+
- Update the Files Likely Touched section if the replan changes which files are affected
|
|
46
|
+
- If a DB-backed planning tool exists for this phase, use it as the source of truth and make any rewritten `PLAN.md` reflect that persisted state rather than bypassing it
|
|
47
|
+
6. If any incomplete task had a `T0x-PLAN.md`, remove or rewrite it to match the new task description.
|
|
48
|
+
7. Do not commit manually — the system auto-commits your changes after this unit completes.
|
|
38
49
|
|
|
39
50
|
When done, say: "Slice {{sliceId}} replanned."
|