gsd-pi 2.33.1-dev.ee47f1b → 2.34.0-dev.bbb5216

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 (135) hide show
  1. package/dist/bundled-resource-path.d.ts +8 -0
  2. package/dist/bundled-resource-path.js +14 -0
  3. package/dist/headless-query.js +6 -6
  4. package/dist/resources/extensions/gsd/auto/session.js +27 -32
  5. package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
  6. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
  7. package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
  8. package/dist/resources/extensions/gsd/auto-loop.js +956 -0
  9. package/dist/resources/extensions/gsd/auto-observability.js +4 -2
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
  11. package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
  12. package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
  13. package/dist/resources/extensions/gsd/auto-start.js +330 -309
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
  16. package/dist/resources/extensions/gsd/auto-timers.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-verification.js +35 -73
  18. package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
  19. package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
  20. package/dist/resources/extensions/gsd/auto.js +283 -1013
  21. package/dist/resources/extensions/gsd/captures.js +10 -4
  22. package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  24. package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
  25. package/dist/resources/extensions/gsd/git-service.js +1 -1
  26. package/dist/resources/extensions/gsd/gsd-db.js +296 -151
  27. package/dist/resources/extensions/gsd/index.js +92 -228
  28. package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
  29. package/dist/resources/extensions/gsd/progress-score.js +61 -156
  30. package/dist/resources/extensions/gsd/quick.js +98 -122
  31. package/dist/resources/extensions/gsd/session-lock.js +13 -0
  32. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  33. package/dist/resources/extensions/gsd/undo.js +43 -48
  34. package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
  35. package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
  36. package/dist/resources/extensions/gsd/verification-gate.js +6 -35
  37. package/dist/resources/extensions/gsd/worktree-command.js +30 -24
  38. package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
  39. package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
  40. package/dist/resources/extensions/gsd/worktree.js +7 -44
  41. package/dist/tool-bootstrap.js +59 -11
  42. package/dist/worktree-cli.js +7 -7
  43. package/package.json +1 -1
  44. package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
  45. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  46. package/packages/pi-ai/dist/models.generated.js +735 -2588
  47. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  48. package/packages/pi-ai/src/models.generated.ts +1039 -2892
  49. package/packages/pi-coding-agent/package.json +1 -1
  50. package/pkg/package.json +1 -1
  51. package/src/resources/extensions/gsd/auto/session.ts +47 -30
  52. package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
  53. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
  54. package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
  55. package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
  56. package/src/resources/extensions/gsd/auto-observability.ts +4 -2
  57. package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
  58. package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
  59. package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
  60. package/src/resources/extensions/gsd/auto-start.ts +440 -354
  61. package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
  62. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
  63. package/src/resources/extensions/gsd/auto-timers.ts +3 -4
  64. package/src/resources/extensions/gsd/auto-verification.ts +76 -90
  65. package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
  66. package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
  67. package/src/resources/extensions/gsd/auto.ts +515 -1199
  68. package/src/resources/extensions/gsd/captures.ts +10 -4
  69. package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
  70. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  71. package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
  72. package/src/resources/extensions/gsd/git-service.ts +8 -1
  73. package/src/resources/extensions/gsd/gitignore.ts +4 -2
  74. package/src/resources/extensions/gsd/gsd-db.ts +375 -180
  75. package/src/resources/extensions/gsd/index.ts +104 -263
  76. package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
  77. package/src/resources/extensions/gsd/progress-score.ts +65 -200
  78. package/src/resources/extensions/gsd/quick.ts +121 -125
  79. package/src/resources/extensions/gsd/session-lock.ts +11 -0
  80. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  81. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
  82. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
  83. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  84. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
  85. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
  86. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
  87. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
  88. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
  89. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
  90. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  91. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
  92. package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
  93. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
  94. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
  95. package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
  96. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
  97. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
  98. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
  99. package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
  100. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
  101. package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
  102. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
  103. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
  104. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  105. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  106. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
  107. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
  108. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
  109. package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
  110. package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
  111. package/src/resources/extensions/gsd/types.ts +90 -81
  112. package/src/resources/extensions/gsd/undo.ts +42 -46
  113. package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
  114. package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
  115. package/src/resources/extensions/gsd/verification-gate.ts +6 -39
  116. package/src/resources/extensions/gsd/worktree-command.ts +36 -24
  117. package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
  118. package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
  119. package/src/resources/extensions/gsd/worktree.ts +7 -44
  120. package/dist/resources/extensions/gsd/auto-constants.js +0 -5
  121. package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
  122. package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
  123. package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
  124. package/src/resources/extensions/gsd/auto-constants.ts +0 -6
  125. package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
  126. package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
  127. package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
  128. package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
  129. package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
  130. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
  131. package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
  132. package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
  133. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
  134. package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
  135. package/src/resources/extensions/gsd/tests/session-lock.test.ts +0 -434
@@ -55,6 +55,55 @@ function formatExecutorConstraints(): string {
55
55
  ].join("\n");
56
56
  }
57
57
 
58
+ function buildSourceFilePaths(
59
+ base: string,
60
+ mid: string,
61
+ sid?: string,
62
+ ): string {
63
+ const paths: string[] = [];
64
+
65
+ const projectPath = resolveGsdRootFile(base, "PROJECT");
66
+ if (existsSync(projectPath)) {
67
+ paths.push(`- **Project**: \`${relGsdRootFile("PROJECT")}\``);
68
+ }
69
+
70
+ const requirementsPath = resolveGsdRootFile(base, "REQUIREMENTS");
71
+ if (existsSync(requirementsPath)) {
72
+ paths.push(`- **Requirements**: \`${relGsdRootFile("REQUIREMENTS")}\``);
73
+ }
74
+
75
+ const decisionsPath = resolveGsdRootFile(base, "DECISIONS");
76
+ if (existsSync(decisionsPath)) {
77
+ paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
78
+ }
79
+
80
+ const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
81
+ if (contextPath) {
82
+ paths.push(`- **Milestone Context**: \`${relMilestoneFile(base, mid, "CONTEXT")}\``);
83
+ }
84
+
85
+ const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
86
+ if (roadmapPath) {
87
+ paths.push(`- **Roadmap**: \`${relMilestoneFile(base, mid, "ROADMAP")}\``);
88
+ }
89
+
90
+ if (sid) {
91
+ const researchPath = resolveSliceFile(base, mid, sid, "RESEARCH");
92
+ if (researchPath) {
93
+ paths.push(`- **Slice Research**: \`${relSliceFile(base, mid, sid, "RESEARCH")}\``);
94
+ }
95
+ } else {
96
+ const researchPath = resolveMilestoneFile(base, mid, "RESEARCH");
97
+ if (researchPath) {
98
+ paths.push(`- **Milestone Research**: \`${relMilestoneFile(base, mid, "RESEARCH")}\``);
99
+ }
100
+ }
101
+
102
+ return paths.length > 0
103
+ ? paths.join("\n")
104
+ : "- Use `rg --files` and targeted reads to identify the relevant source files before planning.";
105
+ }
106
+
58
107
  // ─── Inline Helpers ───────────────────────────────────────────────────────
59
108
 
60
109
  /**
@@ -189,52 +238,30 @@ export async function inlineGsdRootFile(
189
238
  // ─── DB-Aware Inline Helpers ──────────────────────────────────────────────
190
239
 
191
240
  /**
192
- * Shared DB-fallback pattern: attempt a DB query via the context-store, format
193
- * the result, and fall back to the filesystem file when the DB is unavailable
194
- * or the query yields no results.
195
- *
196
- * @param base Project root for filesystem fallback
197
- * @param label Section heading (e.g. "Decisions")
198
- * @param filename Filesystem fallback file (e.g. "decisions.md")
199
- * @param queryDb Async callback receiving the dynamically-imported
200
- * context-store module. Returns formatted markdown or null.
241
+ * Inline decisions with optional milestone scoping from the DB.
242
+ * Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
201
243
  */
202
- async function inlineFromDbOrFile(
203
- base: string,
204
- label: string,
205
- filename: string,
206
- queryDb: (cs: typeof import("./context-store.js")) => string | null,
244
+ export async function inlineDecisionsFromDb(
245
+ base: string, milestoneId?: string, scope?: string, level?: InlineLevel,
207
246
  ): Promise<string | null> {
247
+ const inlineLevel = level ?? resolveInlineLevel();
208
248
  try {
209
249
  const { isDbAvailable } = await import("./gsd-db.js");
210
250
  if (isDbAvailable()) {
211
- const contextStore = await import("./context-store.js");
212
- const content = queryDb(contextStore);
213
- if (content) {
214
- return `### ${label}\nSource: \`.gsd/${filename.toUpperCase().replace(/\.MD$/i, "")}.md\`\n\n${content}`;
251
+ const { queryDecisions, formatDecisionsForPrompt } = await import("./context-store.js");
252
+ const decisions = queryDecisions({ milestoneId, scope });
253
+ if (decisions.length > 0) {
254
+ // Use compact format for non-full levels to save ~35% tokens
255
+ const formatted = inlineLevel !== "full"
256
+ ? formatDecisionsCompact(decisions)
257
+ : formatDecisionsForPrompt(decisions);
258
+ return `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
215
259
  }
216
260
  }
217
261
  } catch {
218
262
  // DB not available — fall through to filesystem
219
263
  }
220
- return inlineGsdRootFile(base, filename, label);
221
- }
222
-
223
- /**
224
- * Inline decisions with optional milestone scoping from the DB.
225
- * Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
226
- */
227
- export async function inlineDecisionsFromDb(
228
- base: string, milestoneId?: string, scope?: string, level?: InlineLevel,
229
- ): Promise<string | null> {
230
- const inlineLevel = level ?? resolveInlineLevel();
231
- return inlineFromDbOrFile(base, "Decisions", "decisions.md", (cs) => {
232
- const decisions = cs.queryDecisions({ milestoneId, scope });
233
- if (decisions.length === 0) return null;
234
- return inlineLevel !== "full"
235
- ? formatDecisionsCompact(decisions)
236
- : cs.formatDecisionsForPrompt(decisions);
237
- });
264
+ return inlineGsdRootFile(base, "decisions.md", "Decisions");
238
265
  }
239
266
 
240
267
  /**
@@ -245,13 +272,23 @@ export async function inlineRequirementsFromDb(
245
272
  base: string, sliceId?: string, level?: InlineLevel,
246
273
  ): Promise<string | null> {
247
274
  const inlineLevel = level ?? resolveInlineLevel();
248
- return inlineFromDbOrFile(base, "Requirements", "requirements.md", (cs) => {
249
- const requirements = cs.queryRequirements({ sliceId });
250
- if (requirements.length === 0) return null;
251
- return inlineLevel !== "full"
252
- ? formatRequirementsCompact(requirements)
253
- : cs.formatRequirementsForPrompt(requirements);
254
- });
275
+ try {
276
+ const { isDbAvailable } = await import("./gsd-db.js");
277
+ if (isDbAvailable()) {
278
+ const { queryRequirements, formatRequirementsForPrompt } = await import("./context-store.js");
279
+ const requirements = queryRequirements({ sliceId });
280
+ if (requirements.length > 0) {
281
+ // Use compact format for non-full levels to save ~40% tokens
282
+ const formatted = inlineLevel !== "full"
283
+ ? formatRequirementsCompact(requirements)
284
+ : formatRequirementsForPrompt(requirements);
285
+ return `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${formatted}`;
286
+ }
287
+ }
288
+ } catch {
289
+ // DB not available — fall through to filesystem
290
+ }
291
+ return inlineGsdRootFile(base, "requirements.md", "Requirements");
255
292
  }
256
293
 
257
294
  /**
@@ -261,9 +298,19 @@ export async function inlineRequirementsFromDb(
261
298
  export async function inlineProjectFromDb(
262
299
  base: string,
263
300
  ): Promise<string | null> {
264
- return inlineFromDbOrFile(base, "Project", "project.md", (cs) => {
265
- return cs.queryProject();
266
- });
301
+ try {
302
+ const { isDbAvailable } = await import("./gsd-db.js");
303
+ if (isDbAvailable()) {
304
+ const { queryProject } = await import("./context-store.js");
305
+ const content = queryProject();
306
+ if (content) {
307
+ return `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${content}`;
308
+ }
309
+ }
310
+ } catch {
311
+ // DB not available — fall through to filesystem
312
+ }
313
+ return inlineGsdRootFile(base, "project.md", "Project");
267
314
  }
268
315
 
269
316
  // ─── Skill Discovery ──────────────────────────────────────────────────────
@@ -326,27 +373,6 @@ function oneLine(text: string): string {
326
373
  return text.replace(/\s+/g, " ").trim();
327
374
  }
328
375
 
329
- /** Build the standard inlined-context section used by all prompt builders. */
330
- function buildInlinedContextSection(inlined: string[]): string {
331
- return `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
332
- }
333
-
334
- /** Build the formatted list of available GSD source files for planners to read on demand. */
335
- function buildSourceFileList(base: string, opts?: { includeProject?: boolean }): string {
336
- const paths: string[] = [];
337
- if (opts?.includeProject && existsSync(resolveGsdRootFile(base, "PROJECT")))
338
- paths.push(`- **Project**: \`${relGsdRootFile("PROJECT")}\``);
339
- if (existsSync(resolveGsdRootFile(base, "REQUIREMENTS")))
340
- paths.push(`- **Requirements**: \`${relGsdRootFile("REQUIREMENTS")}\``);
341
- if (existsSync(resolveGsdRootFile(base, "DECISIONS")))
342
- paths.push(`- **Decisions**: \`${relGsdRootFile("DECISIONS")}\``);
343
- if (paths.length === 0) {
344
- const types = opts?.includeProject ? "project/requirements/decisions" : "requirements/decisions";
345
- return `_No ${types} files found._`;
346
- }
347
- return paths.join("\n");
348
- }
349
-
350
376
  // ─── Section Builders ──────────────────────────────────────────────────────
351
377
 
352
378
  export function buildResumeSection(
@@ -492,17 +518,6 @@ export async function checkNeedsReassessment(
492
518
 
493
519
  if (hasAssessment) return null;
494
520
 
495
- // Fallback: check the expected path directly via existsSync.
496
- // resolveSliceFile relies on directory listing (readdirSync) which may not
497
- // reflect a freshly written file in git worktree directories on some
498
- // filesystems (observed on macOS APFS). A direct existsSync on the
499
- // constructed path bypasses directory listing entirely. (#1112)
500
- const sliceDir = resolveSlicePath(base, mid, lastCompleted.id);
501
- if (sliceDir) {
502
- const directPath = join(sliceDir, `${lastCompleted.id}-ASSESSMENT.md`);
503
- if (existsSync(directPath)) return null;
504
- }
505
-
506
521
  // Also need a summary to reassess against
507
522
  const summaryFile = resolveSliceFile(base, mid, lastCompleted.id, "SUMMARY");
508
523
  const hasSummary = !!(summaryFile && await loadFile(summaryFile));
@@ -553,21 +568,15 @@ export async function checkNeedsRunUat(
553
568
  const uatContent = await loadFile(uatFile);
554
569
  if (!uatContent) return null;
555
570
 
556
- // If a UAT result already exists, the UAT unit has already run and must not
557
- // be re-dispatched. PASS means progression can continue; any non-PASS verdict
558
- // must be handled by the dispatch table's verdict gate, which stops progression
559
- // with a human-action message instead of replaying the same run-uat unit.
571
+ // If UAT result already exists, skip (idempotent)
560
572
  const uatResultFile = resolveSliceFile(base, mid, sid, "UAT-RESULT");
561
573
  if (uatResultFile) {
562
- const resultContent = await loadFile(uatResultFile);
563
- if (resultContent) return null;
574
+ const hasResult = !!(await loadFile(uatResultFile));
575
+ if (hasResult) return null;
564
576
  }
565
577
 
566
- // Classify UAT type; skip non-artifact-driven types auto-mode can only
567
- // execute mechanical checks. Non-artifact UATs are tracked in the dashboard
568
- // but don't block auto-mode progression.
578
+ // Classify UAT type; unknown type treat as human-experience (human review)
569
579
  const uatType = extractUatType(uatContent) ?? "human-experience";
570
- if (uatType !== "artifact-driven") return null;
571
580
 
572
581
  return { sliceId: sid, uatType };
573
582
  }
@@ -590,7 +599,7 @@ export async function buildResearchMilestonePrompt(mid: string, midTitle: string
590
599
  if (knowledgeInlineRM) inlined.push(knowledgeInlineRM);
591
600
  inlined.push(inlineTemplate("research", "Research"));
592
601
 
593
- const inlinedContext = buildInlinedContextSection(inlined);
602
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
594
603
 
595
604
  const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
596
605
  return loadPrompt("research-milestone", {
@@ -618,8 +627,14 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
618
627
  const { inlinePriorMilestoneSummary } = await import("./files.js");
619
628
  const priorSummaryInline = await inlinePriorMilestoneSummary(mid, base);
620
629
  if (priorSummaryInline) inlined.push(priorSummaryInline);
621
- const sourceFilePaths = buildSourceFileList(base, { includeProject: true });
622
-
630
+ if (inlineLevel !== "minimal") {
631
+ const projectInline = await inlineProjectFromDb(base);
632
+ if (projectInline) inlined.push(projectInline);
633
+ const requirementsInline = await inlineRequirementsFromDb(base, undefined, inlineLevel);
634
+ if (requirementsInline) inlined.push(requirementsInline);
635
+ const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
636
+ if (decisionsInline) inlined.push(decisionsInline);
637
+ }
623
638
  const knowledgeInlinePM = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
624
639
  if (knowledgeInlinePM) inlined.push(knowledgeInlinePM);
625
640
  inlined.push(inlineTemplate("roadmap", "Roadmap"));
@@ -634,22 +649,22 @@ export async function buildPlanMilestonePrompt(mid: string, midTitle: string, ba
634
649
  inlined.push(inlineTemplate("task-plan", "Task Plan"));
635
650
  }
636
651
 
637
- const inlinedContext = buildInlinedContextSection(inlined);
652
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
638
653
 
639
654
  const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
655
+ const researchOutputPath = join(base, relMilestoneFile(base, mid, "RESEARCH"));
640
656
  const secretsOutputPath = join(base, relMilestoneFile(base, mid, "SECRETS"));
641
- const researchOutputRelPath = relMilestoneFile(base, mid, "RESEARCH");
642
657
  return loadPrompt("plan-milestone", {
643
658
  workingDirectory: base,
644
659
  milestoneId: mid, milestoneTitle: midTitle,
645
660
  milestonePath: relMilestonePath(base, mid),
646
661
  contextPath: contextRel,
647
662
  researchPath: researchRel,
663
+ researchOutputPath,
648
664
  outputPath: join(base, outputRelPath),
649
665
  secretsOutputPath,
650
666
  inlinedContext,
651
- sourceFilePaths,
652
- researchOutputPath: join(base, researchOutputRelPath),
667
+ sourceFilePaths: buildSourceFilePaths(base, mid),
653
668
  ...buildSkillDiscoveryVars(),
654
669
  });
655
670
  }
@@ -683,7 +698,7 @@ export async function buildResearchSlicePrompt(
683
698
  const overridesInline = formatOverridesSection(activeOverrides);
684
699
  if (overridesInline) inlined.unshift(overridesInline);
685
700
 
686
- const inlinedContext = buildInlinedContextSection(inlined);
701
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
687
702
 
688
703
  const outputRelPath = relSliceFile(base, mid, sid, "RESEARCH");
689
704
  return loadPrompt("research-slice", {
@@ -713,8 +728,12 @@ export async function buildPlanSlicePrompt(
713
728
  inlined.push(await inlineFile(roadmapPath, roadmapRel, "Milestone Roadmap"));
714
729
  const researchInline = await inlineFileOptional(researchPath, researchRel, "Slice Research");
715
730
  if (researchInline) inlined.push(researchInline);
716
- const sliceSourceFilePaths = buildSourceFileList(base);
717
-
731
+ if (inlineLevel !== "minimal") {
732
+ const decisionsInline = await inlineDecisionsFromDb(base, mid, undefined, inlineLevel);
733
+ if (decisionsInline) inlined.push(decisionsInline);
734
+ const requirementsInline = await inlineRequirementsFromDb(base, sid, inlineLevel);
735
+ if (requirementsInline) inlined.push(requirementsInline);
736
+ }
718
737
  const knowledgeInlinePS = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
719
738
  if (knowledgeInlinePS) inlined.push(knowledgeInlinePS);
720
739
  inlined.push(inlineTemplate("plan", "Slice Plan"));
@@ -727,13 +746,17 @@ export async function buildPlanSlicePrompt(
727
746
  const planOverridesInline = formatOverridesSection(planActiveOverrides);
728
747
  if (planOverridesInline) inlined.unshift(planOverridesInline);
729
748
 
730
- const inlinedContext = buildInlinedContextSection(inlined);
749
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
731
750
 
732
751
  // Build executor context constraints from the budget engine
733
752
  const executorContextConstraints = formatExecutorConstraints();
734
753
 
735
754
  const outputRelPath = relSliceFile(base, mid, sid, "PLAN");
736
- const commitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.";
755
+ const prefs = loadEffectiveGSDPreferences();
756
+ const commitDocsEnabled = prefs?.preferences?.git?.commit_docs !== false;
757
+ const commitInstruction = commitDocsEnabled
758
+ ? `Commit the plan files only: \`git add ${relSlicePath(base, mid, sid)}/ .gsd/DECISIONS.md .gitignore && git commit -m "docs(${sid}): add slice plan"\`. Do not stage .gsd/STATE.md or other runtime files — the system manages those.`
759
+ : "Do not commit — planning docs are not tracked in git for this project.";
737
760
  return loadPrompt("plan-slice", {
738
761
  workingDirectory: base,
739
762
  milestoneId: mid, sliceId: sid, sliceTitle: sTitle,
@@ -743,9 +766,9 @@ export async function buildPlanSlicePrompt(
743
766
  outputPath: join(base, outputRelPath),
744
767
  inlinedContext,
745
768
  dependencySummaries: depContent,
769
+ sourceFilePaths: buildSourceFilePaths(base, mid, sid),
746
770
  executorContextConstraints,
747
771
  commitInstruction,
748
- sourceFilePaths: sliceSourceFilePaths,
749
772
  });
750
773
  }
751
774
 
@@ -902,7 +925,7 @@ export async function buildCompleteSlicePrompt(
902
925
  const completeOverridesInline = formatOverridesSection(completeActiveOverrides);
903
926
  if (completeOverridesInline) inlined.unshift(completeOverridesInline);
904
927
 
905
- const inlinedContext = buildInlinedContextSection(inlined);
928
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
906
929
 
907
930
  const sliceRel = relSlicePath(base, mid, sid);
908
931
  const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
@@ -961,7 +984,7 @@ export async function buildCompleteMilestonePrompt(
961
984
  if (contextInline) inlined.push(contextInline);
962
985
  inlined.push(inlineTemplate("milestone-summary", "Milestone Summary"));
963
986
 
964
- const inlinedContext = buildInlinedContextSection(inlined);
987
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
965
988
 
966
989
  const milestoneSummaryPath = join(base, `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`);
967
990
 
@@ -1032,7 +1055,7 @@ export async function buildValidateMilestonePrompt(
1032
1055
  const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
1033
1056
  if (contextInline) inlined.push(contextInline);
1034
1057
 
1035
- const inlinedContext = buildInlinedContextSection(inlined);
1058
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
1036
1059
 
1037
1060
  const validationOutputPath = join(base, `${relMilestonePath(base, mid)}/${mid}-VALIDATION.md`);
1038
1061
  const roadmapOutputPath = `${relMilestonePath(base, mid)}/${mid}-ROADMAP.md`;
@@ -1086,7 +1109,7 @@ export async function buildReplanSlicePrompt(
1086
1109
  const replanOverridesInline = formatOverridesSection(replanActiveOverrides);
1087
1110
  if (replanOverridesInline) inlined.unshift(replanOverridesInline);
1088
1111
 
1089
- const inlinedContext = buildInlinedContextSection(inlined);
1112
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
1090
1113
 
1091
1114
  const replanPath = join(base, `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`);
1092
1115
 
@@ -1119,7 +1142,7 @@ export async function buildReplanSlicePrompt(
1119
1142
  }
1120
1143
 
1121
1144
  export async function buildRunUatPrompt(
1122
- mid: string, sliceId: string, uatPath: string, base: string,
1145
+ mid: string, sliceId: string, uatPath: string, uatContent: string, base: string,
1123
1146
  ): Promise<string> {
1124
1147
  const inlined: string[] = [];
1125
1148
  inlined.push(await inlineFile(resolveSliceFile(base, mid, sliceId, "UAT"), uatPath, `${sliceId} UAT`));
@@ -1134,9 +1157,10 @@ export async function buildRunUatPrompt(
1134
1157
  const projectInline = await inlineProjectFromDb(base);
1135
1158
  if (projectInline) inlined.push(projectInline);
1136
1159
 
1137
- const inlinedContext = buildInlinedContextSection(inlined);
1160
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
1138
1161
 
1139
1162
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
1163
+ const uatType = extractUatType(uatContent) ?? "human-experience";
1140
1164
 
1141
1165
  return loadPrompt("run-uat", {
1142
1166
  workingDirectory: base,
@@ -1144,6 +1168,7 @@ export async function buildRunUatPrompt(
1144
1168
  sliceId,
1145
1169
  uatPath,
1146
1170
  uatResultPath,
1171
+ uatType,
1147
1172
  inlinedContext,
1148
1173
  });
1149
1174
  }
@@ -1171,7 +1196,7 @@ export async function buildReassessRoadmapPrompt(
1171
1196
  const knowledgeInlineRA = await inlineGsdRootFile(base, "knowledge.md", "Project Knowledge");
1172
1197
  if (knowledgeInlineRA) inlined.push(knowledgeInlineRA);
1173
1198
 
1174
- const inlinedContext = buildInlinedContextSection(inlined);
1199
+ const inlinedContext = `## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`;
1175
1200
 
1176
1201
  const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
1177
1202
 
@@ -1189,7 +1214,11 @@ export async function buildReassessRoadmapPrompt(
1189
1214
  // Non-fatal — captures module may not be available
1190
1215
  }
1191
1216
 
1192
- const reassessCommitInstruction = "Do not commit planning artifacts — .gsd/ is managed externally.";
1217
+ const reassessPrefs = loadEffectiveGSDPreferences();
1218
+ const reassessCommitDocsEnabled = reassessPrefs?.preferences?.git?.commit_docs !== false;
1219
+ const reassessCommitInstruction = reassessCommitDocsEnabled
1220
+ ? `Commit: \`docs(${mid}): reassess roadmap after ${completedSliceId}\`. Stage only the .gsd/milestones/ files you changed — do not stage .gsd/STATE.md or other runtime files.`
1221
+ : "Do not commit — planning docs are not tracked in git for this project.";
1193
1222
 
1194
1223
  return loadPrompt("reassess-roadmap", {
1195
1224
  workingDirectory: base,