@opengsd/gsd-pi 1.1.1-dev.154fd443 → 1.1.1-dev.1854a79a

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.
Files changed (169) hide show
  1. package/dist/project-sessions.js +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/browser-tools/index.js +39 -22
  4. package/dist/resources/extensions/browser-tools/state.js +12 -0
  5. package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
  6. package/dist/resources/extensions/browser-tools/utils.js +3 -3
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -9
  8. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +659 -57
  10. package/dist/resources/extensions/gsd/auto-prompts.js +14 -1
  11. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  12. package/dist/resources/extensions/gsd/auto-tool-tracking.js +5 -0
  13. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +29 -0
  14. package/dist/resources/extensions/gsd/auto.js +62 -464
  15. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +2 -1
  16. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  17. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  18. package/dist/resources/extensions/gsd/markdown-renderer.js +31 -32
  19. package/dist/resources/extensions/gsd/mcp-filter.js +6 -0
  20. package/dist/resources/extensions/gsd/native-git-bridge.js +9 -0
  21. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  22. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  23. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  24. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
  25. package/dist/web/standalone/.next/BUILD_ID +1 -1
  26. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  27. package/dist/web/standalone/.next/build-manifest.json +2 -2
  28. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  29. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  47. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  48. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  49. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  50. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  51. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  52. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  53. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  54. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  55. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  57. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  58. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  59. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  60. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  61. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  62. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  63. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  64. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  65. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  66. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  67. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  68. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  69. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  70. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  71. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  72. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  73. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  74. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  75. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  76. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  77. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  78. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  79. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  80. package/dist/web/standalone/.next/server/app/index.html +1 -1
  81. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  88. package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
  89. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  90. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  91. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  93. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  94. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  95. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  96. package/package.json +6 -4
  97. package/packages/cloud-mcp-gateway/package.json +2 -2
  98. package/packages/contracts/package.json +1 -1
  99. package/packages/daemon/package.json +4 -4
  100. package/packages/gsd-agent-core/package.json +5 -5
  101. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  102. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
  103. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  104. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  105. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  106. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
  108. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  110. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
  111. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  112. package/packages/gsd-agent-modes/package.json +7 -7
  113. package/packages/mcp-server/package.json +3 -3
  114. package/packages/native/package.json +1 -1
  115. package/packages/pi-agent-core/package.json +1 -1
  116. package/packages/pi-ai/dist/models.generated.d.ts +0 -34
  117. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  118. package/packages/pi-ai/dist/models.generated.js +0 -34
  119. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  120. package/packages/pi-ai/package.json +1 -1
  121. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  122. package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
  123. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
  125. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  126. package/packages/pi-coding-agent/package.json +7 -7
  127. package/packages/pi-tui/package.json +2 -2
  128. package/packages/rpc-client/package.json +2 -2
  129. package/pkg/package.json +1 -1
  130. package/src/resources/extensions/browser-tools/index.ts +39 -22
  131. package/src/resources/extensions/browser-tools/state.ts +13 -0
  132. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
  133. package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
  134. package/src/resources/extensions/browser-tools/utils.ts +3 -3
  135. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -8
  136. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +2 -2
  137. package/src/resources/extensions/gsd/auto/contracts.ts +8 -119
  138. package/src/resources/extensions/gsd/auto/orchestrator.ts +794 -58
  139. package/src/resources/extensions/gsd/auto-prompts.ts +21 -1
  140. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  141. package/src/resources/extensions/gsd/auto-tool-tracking.ts +5 -0
  142. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +33 -0
  143. package/src/resources/extensions/gsd/auto.ts +81 -500
  144. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +2 -0
  145. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  146. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  147. package/src/resources/extensions/gsd/markdown-renderer.ts +38 -19
  148. package/src/resources/extensions/gsd/mcp-filter.ts +7 -0
  149. package/src/resources/extensions/gsd/native-git-bridge.ts +9 -0
  150. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  151. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  152. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  153. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  154. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  155. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +590 -855
  156. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
  157. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  158. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  159. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  160. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  161. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  162. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +4 -2
  163. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +19 -5
  164. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
  165. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  166. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
  167. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  168. /package/dist/web/standalone/.next/static/{vAecbJ3K9eO213bAxU8Mi → h38jfi0dnRY0y3hbyBszg}/_buildManifest.js +0 -0
  169. /package/dist/web/standalone/.next/static/{vAecbJ3K9eO213bAxU8Mi → h38jfi0dnRY0y3hbyBszg}/_ssgManifest.js +0 -0
@@ -6,10 +6,11 @@ import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-
6
6
  import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
7
7
  import {
8
8
  getActiveRequirements,
9
- insertMilestone,
9
+ getAllMilestones,
10
10
  getMilestone,
11
11
  getSliceStatusSummary,
12
12
  getSliceTaskCounts,
13
+ insertMilestone,
13
14
  insertAssessment,
14
15
  insertGateRun,
15
16
  readTransaction,
@@ -126,6 +127,111 @@ function registerProjectMilestoneSequence(content: string): string[] {
126
127
  return registered;
127
128
  }
128
129
 
130
+ /** Minimal shape of a DB milestone row needed to re-render the sequence section. */
131
+ interface MilestoneSeqRow {
132
+ id: string;
133
+ title: string;
134
+ status: string;
135
+ vision: string;
136
+ }
137
+
138
+ /**
139
+ * Best-effort recovery of the human one-liner for each milestone id from a
140
+ * (possibly malformed) Milestone Sequence body. Deliberately lenient: tolerates
141
+ * any separator the canonical MILESTONE_LINE_RE rejects (en-dash, " : ", a
142
+ * missing checkbox, etc.) so a model formatting slip does not discard the prose.
143
+ */
144
+ function recoverMilestoneTails(sequenceBody: string): Map<string, string> {
145
+ const out = new Map<string, string>();
146
+ const lenient = /^\s*(?:-\s*)?(?:\[[ xX]\]\s*)?(M\d{3})\b\s*[:.\-–—]*\s*(.*)$/;
147
+ for (const rawLine of sequenceBody.split("\n")) {
148
+ const m = rawLine.match(lenient);
149
+ if (m) out.set(m[1], m[2].trim());
150
+ }
151
+ return out;
152
+ }
153
+
154
+ function firstSentence(text: string): string {
155
+ const trimmed = text.trim();
156
+ if (!trimmed) return "";
157
+ const idx = trimmed.search(/[.!?](\s|$)/);
158
+ return (idx >= 0 ? trimmed.slice(0, idx + 1) : trimmed).trim();
159
+ }
160
+
161
+ /** Render one canonical, parseable milestone line for the given DB row. */
162
+ function renderMilestoneLine(m: MilestoneSeqRow, recoveredTail: string): string {
163
+ const done = m.status === "complete";
164
+ let oneLiner = recoveredTail;
165
+ // The recovered tail often still carries the title (e.g. "Foo — bar" or
166
+ // "Foo : bar"). Strip a leading repetition of the title, then any separator.
167
+ if (oneLiner.toLowerCase().startsWith(m.title.toLowerCase())) {
168
+ oneLiner = oneLiner.slice(m.title.length).replace(/^\s*[:.\-–—]+\s*/, "").trim();
169
+ } else {
170
+ const sep = oneLiner.match(/\s+(?:—|–|--|-|:)\s+/);
171
+ if (sep && sep.index !== undefined) oneLiner = oneLiner.slice(sep.index + sep[0].length).trim();
172
+ }
173
+ // MILESTONE_LINE_RE requires non-empty prose after the separator.
174
+ if (!oneLiner) oneLiner = firstSentence(m.vision) || (done ? "Completed." : "Planned.");
175
+ return `- [${done ? "x" : " "}] ${m.id}: ${m.title} — ${oneLiner}`;
176
+ }
177
+
178
+ /**
179
+ * Rebuild the "## Milestone Sequence" section from authoritative DB rows when a
180
+ * model-authored PROJECT.md projection parsed to zero milestone lines but the DB
181
+ * already holds milestones. The DB is the source of truth (markdown is a
182
+ * projection), so this repairs the projection rather than failing the save.
183
+ * Preserves a leading HTML comment in the section and recovers one-liners
184
+ * best-effort. The returned content parses cleanly under MILESTONE_LINE_RE.
185
+ */
186
+ function rebuildMilestoneSequenceSection(content: string, milestones: MilestoneSeqRow[]): string {
187
+ const lines = content.split("\n");
188
+ const headerIdx = lines.findIndex(l => /^##\s+Milestone Sequence\s*$/.test(l));
189
+
190
+ const canonicalLines = (() => {
191
+ // Recover tails from the existing (malformed) body when the section exists.
192
+ let body = "";
193
+ if (headerIdx !== -1) {
194
+ let end = headerIdx + 1;
195
+ while (end < lines.length && !/^##\s+/.test(lines[end])) end++;
196
+ body = lines.slice(headerIdx + 1, end).join("\n");
197
+ }
198
+ const tails = recoverMilestoneTails(body);
199
+ return milestones.map(m => renderMilestoneLine(m, tails.get(m.id) ?? ""));
200
+ })();
201
+
202
+ if (headerIdx === -1) {
203
+ // No section at all — append a fresh, canonical one.
204
+ const sep = content.endsWith("\n") ? "" : "\n";
205
+ return `${content}${sep}\n## Milestone Sequence\n\n${canonicalLines.join("\n")}\n`;
206
+ }
207
+
208
+ let bodyEnd = headerIdx + 1;
209
+ while (bodyEnd < lines.length && !/^##\s+/.test(lines[bodyEnd])) bodyEnd++;
210
+ const existingBody = lines.slice(headerIdx + 1, bodyEnd);
211
+
212
+ // Preserve a contiguous leading HTML comment block (the "Check off…" hint).
213
+ let i = 0;
214
+ while (i < existingBody.length && existingBody[i].trim() === "") i++;
215
+ const preserved: string[] = [];
216
+ if (i < existingBody.length && existingBody[i].trim().startsWith("<!--")) {
217
+ while (i < existingBody.length) {
218
+ preserved.push(existingBody[i]);
219
+ const closed = existingBody[i].includes("-->");
220
+ i++;
221
+ if (closed) break;
222
+ }
223
+ }
224
+
225
+ return [
226
+ ...lines.slice(0, headerIdx + 1),
227
+ "",
228
+ ...(preserved.length ? [...preserved, ""] : []),
229
+ ...canonicalLines,
230
+ "",
231
+ ...lines.slice(bodyEnd),
232
+ ].join("\n");
233
+ }
234
+
129
235
  async function mirrorArtifactToActiveWorktreeProjection(
130
236
  basePath: string,
131
237
  relativePath: string,
@@ -260,6 +366,7 @@ export async function executeSummarySave(
260
366
  await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, contentToSave);
261
367
 
262
368
  let registeredMilestones: string[] = [];
369
+ let milestoneSequenceSelfHealed = false;
263
370
  if (params.artifact_type === "PROJECT") {
264
371
  try {
265
372
  registeredMilestones = registerProjectMilestoneSequence(contentToSave);
@@ -294,29 +401,83 @@ export async function executeSummarySave(
294
401
  };
295
402
  }
296
403
  if (registeredMilestones.length === 0) {
297
- logError("tool", `gsd_summary_save: PROJECT.md saved to ${relativePath} but parsed zero milestones — registration produced no DB rows`, {
404
+ const existingMilestones = getAllMilestones();
405
+ if (existingMilestones.length === 0) {
406
+ // Genuine first-save failure: no milestones parsed AND none in the DB.
407
+ // /gsd really would report "No Active Milestone" — hard-fail so the
408
+ // caller rewrites the sequence before proceeding.
409
+ logError("tool", `gsd_summary_save: PROJECT.md saved to ${relativePath} but parsed zero milestones — registration produced no DB rows`, {
410
+ tool: "gsd_summary_save",
411
+ });
412
+ // PROJECT.md was persisted; invalidate so subsequent reads see the new
413
+ // artifacts row even though no milestones registered.
414
+ invalidateStateCache();
415
+ return {
416
+ content: [{
417
+ type: "text",
418
+ text:
419
+ `Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
420
+ `so no milestones were registered in the DB. /gsd will report "No Active Milestone". ` +
421
+ `Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
422
+ `\`- [ ] M001: <Title> — <One-liner>\` (em-dash, double-dash \`--\`, or single-dash \`-\` separator), then re-call gsd_summary_save(PROJECT).`,
423
+ }],
424
+ details: {
425
+ operation: "save_summary",
426
+ path: relativePath,
427
+ artifact_type: params.artifact_type,
428
+ error: "milestone_registration_empty_parse",
429
+ },
430
+ isError: true,
431
+ };
432
+ }
433
+
434
+ // Existing DB rows mean this is projection drift, not data loss. Rebuild
435
+ // the section from DB state and re-persist a parseable projection.
436
+ logWarning("tool", `gsd_summary_save: PROJECT.md parsed zero milestone lines but DB has ${existingMilestones.length} — rebuilding Milestone Sequence from DB (projection self-heal)`, {
298
437
  tool: "gsd_summary_save",
438
+ path: relativePath,
299
439
  });
300
- // PROJECT.md was persisted; invalidate so subsequent reads see the new
301
- // artifacts row even though no milestones registered.
302
- invalidateStateCache();
303
- return {
304
- content: [{
305
- type: "text",
306
- text:
307
- `Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
308
- `so no milestones were registered in the DB. /gsd will report "No Active Milestone". ` +
309
- `Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
310
- `\`- [ ] M001: <Title> — <One-liner>\` (em-dash, double-dash \`--\`, or single-dash \`-\` separator), then re-call gsd_summary_save(PROJECT).`,
311
- }],
312
- details: {
313
- operation: "save_summary",
440
+ try {
441
+ const healed = rebuildMilestoneSequenceSection(contentToSave, existingMilestones);
442
+ await saveArtifactToDb(
443
+ { path: relativePath, artifact_type: params.artifact_type, content: healed },
444
+ basePath,
445
+ );
446
+ await mirrorArtifactToActiveWorktreeProjection(basePath, relativePath, healed);
447
+ const healedRegisteredMilestones = registerProjectMilestoneSequence(healed);
448
+ if (healedRegisteredMilestones.length === 0) {
449
+ throw new Error("self-healed PROJECT.md still parsed zero milestone lines");
450
+ }
451
+ registeredMilestones = healedRegisteredMilestones;
452
+ milestoneSequenceSelfHealed = true;
453
+ } catch (healErr) {
454
+ const msg = healErr instanceof Error ? healErr.message : String(healErr);
455
+ logError("tool", `gsd_summary_save: Milestone Sequence self-heal failed: ${msg}`, {
456
+ tool: "gsd_summary_save",
314
457
  path: relativePath,
315
- artifact_type: params.artifact_type,
316
- error: "milestone_registration_empty_parse",
317
- },
318
- isError: true,
319
- };
458
+ error: msg,
459
+ });
460
+ invalidateStateCache();
461
+ return {
462
+ content: [{
463
+ type: "text",
464
+ text:
465
+ `Error: PROJECT.md was saved to ${relativePath} but contains zero parseable milestone lines, ` +
466
+ `and automatic DB-backed Milestone Sequence repair failed: ${msg}. ` +
467
+ `Rewrite PROJECT.md so the "Milestone Sequence" section uses canonical lines: ` +
468
+ `\`- [ ] M001: <Title> — <One-liner>\`, then re-call gsd_summary_save(PROJECT).`,
469
+ }],
470
+ details: {
471
+ operation: "save_summary",
472
+ path: relativePath,
473
+ artifact_type: params.artifact_type,
474
+ error: "milestone_sequence_self_heal_failed",
475
+ self_heal_error: msg,
476
+ },
477
+ isError: true,
478
+ };
479
+ }
480
+ invalidateStateCache();
320
481
  }
321
482
  }
322
483
 
@@ -339,6 +500,7 @@ export async function executeSummarySave(
339
500
  artifact_type: params.artifact_type,
340
501
  content_source: contentSource,
341
502
  ...(registeredMilestones.length > 0 ? { registeredMilestones } : {}),
503
+ ...(milestoneSequenceSelfHealed ? { milestoneSequenceSelfHealed: true } : {}),
342
504
  },
343
505
  };
344
506
  } catch (err) {
@@ -1,2 +0,0 @@
1
- "use strict";exports.id=678,exports.ids=[678],exports.modules={10678:(a,b,c)=>{let d;c.d(b,{isOnboardingComplete:()=>r,readOnboardingRecord:()=>q});var e=c(89477),f=c(86697);c(76212),c(78335);var g=c(65521),h=c(62228);c(95398),process.env.GSD_ENABLE_NATIVE_GSD_PARSER,Symbol("native-unavailable"),new g.AsyncLocalStorage,c(97526),Object.values({Q3:{id:"Q3",scope:"slice",ownerTurn:"gate-evaluate",question:"How can this be exploited?",guidance:"Identify abuse scenarios: parameter tampering, replay attacks, privilege escalation.\nMap data exposure risks: PII, tokens, secrets accessible through this slice.\nDefine input trust boundaries: untrusted user input reaching DB, API, or filesystem.\nIf none apply, return verdict 'omitted' with rationale explaining why.",promptSection:"Abuse Surface"},Q4:{id:"Q4",scope:"slice",ownerTurn:"gate-evaluate",question:"Which existing requirements (R-IDs) does this slice touch, and which must be re-tested?",guidance:"List the R-IDs (e.g. R001, R003) touched by this slice; see the milestone requirements artifact at .gsd/milestones/<id>/REQUIREMENTS.md.\nIdentify what must be re-tested after shipping.\nFlag decisions that should be revisited given the new scope.\nIf no existing requirements are affected, return verdict 'omitted'.",promptSection:"Broken Promises"},Q5:{id:"Q5",scope:"task",ownerTurn:"execute-task",question:"What breaks when dependencies fail?",guidance:"Enumerate the task's external dependencies (APIs, filesystem, network, subprocesses).\nDescribe the failure path for each: timeout, malformed response, connection loss.\nVerify the implementation handles each failure or explicitly bubbles the error.\nReturn verdict 'omitted' only if the task has no external dependencies.",promptSection:"Failure Modes"},Q6:{id:"Q6",scope:"task",ownerTurn:"execute-task",question:"What is the 10x load breakpoint?",guidance:"Identify the resource that saturates first at 10x the expected load.\nDescribe the protection applied (pool sizing, rate limiting, pagination, caching).\nReturn verdict 'omitted' if the task has no runtime load dimension.",promptSection:"Load Profile"},Q7:{id:"Q7",scope:"task",ownerTurn:"execute-task",question:"What negative tests protect this task?",guidance:"List malformed inputs, error paths, and boundary conditions the tests cover.\nPoint to the specific test files or cases that assert each negative scenario.\nReturn verdict 'omitted' only if the task has no meaningful negative surface.",promptSection:"Negative Tests"},Q8:{id:"Q8",scope:"slice",ownerTurn:"complete-slice",question:"How will ops know this slice is healthy or broken?",guidance:"Describe the health signal (metric, log line, dashboard) that proves the slice works.\nDescribe the failure signal that triggers an alert or paging.\nDocument the recovery procedure and any monitoring gaps.\nReturn verdict 'omitted' only for slices with no runtime behavior at all.",promptSection:"Operational Readiness"},MV01:{id:"MV01",scope:"milestone",ownerTurn:"validate-milestone",question:"Is every success criterion in the milestone roadmap satisfied?",guidance:"Walk the success-criteria checklist from the milestone roadmap.\nFor each criterion, point to the slice / assessment / verification evidence that proves it.\nReturn verdict 'flag' if any criterion is unmet or unverifiable.",promptSection:"Success Criteria Checklist"},MV02:{id:"MV02",scope:"milestone",ownerTurn:"validate-milestone",question:"Does every slice have a SUMMARY.md and a passing assessment?",guidance:"Confirm every slice listed in the roadmap has a SUMMARY.md.\nConfirm each slice has an ASSESSMENT verdict of 'pass' (or justified 'omitted').\nFlag missing artifacts and slices with outstanding follow-ups or known limitations.",promptSection:"Slice Delivery Audit"},MV03:{id:"MV03",scope:"milestone",ownerTurn:"validate-milestone",question:"Do the slices integrate end-to-end?",guidance:"Trace at least one cross-slice flow proving the pieces compose.\nFlag gaps where two slices were built in isolation with no integration evidence.",promptSection:"Cross-Slice Integration"},MV04:{id:"MV04",scope:"milestone",ownerTurn:"validate-milestone",question:"Are all touched requirements covered and still coherent?",guidance:"For each requirement advanced, validated, surfaced, or invalidated across the milestone's slices, confirm the milestone-level evidence matches.\nFlag requirements that slices claim to advance but no artifact proves.",promptSection:"Requirement Coverage"}});class i{get(a){return this.entries.get(a)}set(a,b){this.entries.set(a,b)}has(a){return this.entries.has(a)}delete(a){return this.entries.delete(a)}asReadonlyMap(){return this.entries}closeNonActive(a,b){for(let[c,d]of this.entries)d.db!==a&&(this.entries.delete(c),b(d))}constructor(){this.entries=new Map}}class j{markAttempted(){this.attempted=!0}clearError(){this.lastError=null,this.lastPhase=null}recordError(a,b){this.lastPhase=a,this.lastError=b instanceof Error?b:Error(String(b))}reset(){this.attempted=!1,this.clearError()}snapshot(){return{attempted:this.attempted,lastError:this.lastError,lastPhase:this.lastPhase}}constructor(){this.attempted=!1,this.lastError=null,this.lastPhase=null}}class k{isInTransaction(){return this.depth>0}transaction(a,b){if(this.depth>0)return this.runNested(b);a.begin(),this.depth++;try{let c=b();return a.commit(),c}catch(b){throw a.rollback(),b}finally{this.depth--}}readTransaction(a,b,c){if(this.depth>0)return this.runNested(b);a.beginRead(),this.depth++;try{let c=b();return a.commit(),c}catch(b){try{a.rollback()}catch(a){c(a instanceof Error?a:Error(String(a)))}throw b}finally{this.depth--}}runNested(a){this.depth++;try{return a()}finally{this.depth--}}constructor(){this.depth=0}}class l{constructor(a){this.providerName=null,this.providerModule=null,this.loadAttempted=!1,this.deps=a}load(){if(this.loadAttempted)return;this.loadAttempted=!0;try{this.deps.suppressSqliteWarning();let a=this.deps.tryRequireNodeSqlite();if(a.DatabaseSync){this.providerModule=a,this.providerName="node:sqlite";return}}catch{}let a=this.loadBetterSqliteModule();if(a){this.providerModule=a,this.providerName="better-sqlite3";return}let b=22>parseInt(this.deps.nodeVersion.split(".")[0],10)?` GSD requires Node >= 22.0.0 (current: v${this.deps.nodeVersion}). Upgrade Node to fix this.`:"";this.deps.writeStderr(`gsd-db: No SQLite provider available (tried node:sqlite, better-sqlite3).${b}
2
- `)}getProviderName(){return this.providerName}openRaw(a){if(this.load(),!this.providerModule||!this.providerName)return null;if("node:sqlite"===this.providerName){let{DatabaseSync:b}=this.providerModule;return new b(a)}return new this.providerModule(a)}tryOpenBetterSqliteFallback(a){if("node:sqlite"!==this.providerName)return null;let b=this.loadBetterSqliteModule();return b?{providerName:"better-sqlite3",providerModule:b,rawDb:new b(a)}:null}commitFallback(a){this.providerName=a.providerName,this.providerModule=a.providerModule}reset(){this.loadAttempted=!1,this.providerModule=null,this.providerName=null}loadBetterSqliteModule(){try{let a=this.deps.tryRequireBetterSqlite3();if("function"==typeof a)return a;if(a&&"function"==typeof a.default)return a.default}catch{}return null}}function m(){if(void 0!==d)return d;try{d=createRequire(import.meta.url)}catch{d=null}return d}new l({tryRequireNodeSqlite:()=>{let a=m();if(!a)throw Error("unavailable");return a("node:sqlite")},tryRequireBetterSqlite3:()=>{let a=m();if(!a)throw Error("unavailable");return a("better-sqlite3")},suppressSqliteWarning:function(){let a=process.emit;process.emit=function(b,...c){return!("warning"===b&&c[0]&&"object"==typeof c[0]&&"name"in c[0]&&"ExperimentalWarning"===c[0].name&&"message"in c[0]&&"string"==typeof c[0].message&&c[0].message.includes("SQLite"))&&a.apply(process,[b,...c])}},nodeVersion:process.versions.node,writeStderr:a=>process.stderr.write(a)}),new j,new i,new k;let n=process.env.GSD_CODING_AGENT_DIR||(0,f.join)(process.env.GSD_HOME?(0,f.resolve)(process.env.GSD_HOME):(0,f.join)((0,h.homedir)(),".gsd"),"agent"),o=(0,f.join)(n,"onboarding.json"),p={version:1,flowVersion:1,completedAt:null,completedSteps:[],skippedSteps:[],lastResumePoint:null};function q(){if(!(0,e.existsSync)(o))return{...p};try{let a=JSON.parse((0,e.readFileSync)(o,"utf-8"));return{version:"number"==typeof a.version?a.version:1,flowVersion:"number"==typeof a.flowVersion?a.flowVersion:0,completedAt:"string"==typeof a.completedAt?a.completedAt:null,completedSteps:Array.isArray(a.completedSteps)?a.completedSteps.filter(a=>"string"==typeof a):[],skippedSteps:Array.isArray(a.skippedSteps)?a.skippedSteps.filter(a=>"string"==typeof a):[],lastResumePoint:"string"==typeof a.lastResumePoint?a.lastResumePoint:null}}catch{return{...p}}}function r(){let a=q();return null!==a.completedAt&&1===a.flowVersion}},97526:(a,b,c)=>{c.d(b,{DZ:()=>e,rs:()=>d});let d="GSD_GIT_ERROR";class e extends Error{constructor(a,b,c){super(b,c),this.name="GSDError",this.code=a}}}};