gsd-pi 2.68.1-dev.c1497ab → 2.68.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +5 -1
  2. package/dist/resources/extensions/gsd/guided-flow.js +70 -25
  3. package/dist/resources/extensions/gsd/model-router.js +2 -32
  4. package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
  5. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  6. package/dist/resources/extensions/gsd/prompts/discuss.md +0 -2
  7. package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  8. package/dist/resources/extensions/gsd/templates/context.md +2 -34
  9. package/dist/web/standalone/.next/BUILD_ID +1 -1
  10. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  11. package/dist/web/standalone/.next/build-manifest.json +3 -3
  12. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  13. package/dist/web/standalone/.next/required-server-files.json +3 -3
  14. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  15. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  25. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  29. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  31. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  35. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  36. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  37. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  41. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  53. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  73. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  83. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  89. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  109. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/index.html +1 -1
  119. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  120. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  121. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  122. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  124. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/page.js +2 -2
  126. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  128. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  129. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  130. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/middleware.js +2 -2
  132. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  134. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  135. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  136. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  137. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
  138. package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
  139. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +1 -0
  140. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
  141. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
  142. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  143. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  144. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  145. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  146. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  147. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  148. package/dist/web/standalone/server.js +1 -1
  149. package/package.json +1 -1
  150. package/src/resources/extensions/gsd/auto-model-selection.ts +3 -1
  151. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +5 -1
  152. package/src/resources/extensions/gsd/guided-flow.ts +84 -22
  153. package/src/resources/extensions/gsd/model-router.ts +10 -44
  154. package/src/resources/extensions/gsd/preferences-types.ts +1 -3
  155. package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
  156. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  157. package/src/resources/extensions/gsd/prompts/discuss.md +0 -2
  158. package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  159. package/src/resources/extensions/gsd/templates/context.md +2 -34
  160. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
  161. package/src/resources/extensions/gsd/tests/capability-router.test.ts +7 -31
  162. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  163. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
  164. package/src/resources/extensions/gsd/tests/model-router.test.ts +2 -2
  165. package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
  166. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
  167. package/src/resources/extensions/gsd/tests/write-gate.test.ts +16 -13
  168. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +0 -1
  169. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
  170. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
  171. /package/dist/web/standalone/.next/static/{5D80IWYltFwlAJiCZ84MC → u9mQsApZYm8sVYSAaft8g}/_buildManifest.js +0 -0
  172. /package/dist/web/standalone/.next/static/{5D80IWYltFwlAJiCZ84MC → u9mQsApZYm8sVYSAaft8g}/_ssgManifest.js +0 -0
@@ -40,9 +40,13 @@ let activeQueuePhase = false;
40
40
  let pendingGateId = null;
41
41
  /**
42
42
  * Recognized gate question ID patterns.
43
- * These appear in discuss.md (depth/requirements/roadmap).
43
+ * These appear in both discuss-prepared.md (4-layer) and discuss.md (depth/requirements/roadmap).
44
44
  */
45
45
  const GATE_QUESTION_PATTERNS = [
46
+ "layer1_scope_gate",
47
+ "layer2_architecture_gate",
48
+ "layer3_error_gate",
49
+ "layer4_quality_gate",
46
50
  "depth_verification",
47
51
  ];
48
52
  /**
@@ -36,7 +36,19 @@ import { parkMilestone, discardMilestone } from "./milestone-actions.js";
36
36
  import { selectAndApplyModel } from "./auto-model-selection.js";
37
37
  import { DISCUSS_TOOLS_ALLOWLIST } from "./constants.js";
38
38
  import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForGuidedUnit, } from "./workflow-mcp.js";
39
- import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from "./preparation.js";
39
+ import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, formatEcosystemBrief, } from "./preparation.js";
40
+ // ─── Preparation result storage ─────────────────────────────────────────────
41
+ // Stores the most recent preparation result for injection into discuss prompts.
42
+ // S02 will consume this when building the prepared discussion prompt.
43
+ let lastPreparationResult = null;
44
+ /** Get the most recent preparation result (for S02 prompt building). */
45
+ export function getLastPreparationResult() {
46
+ return lastPreparationResult;
47
+ }
48
+ /** Clear the preparation result (called after discussion completes). */
49
+ export function clearPreparationResult() {
50
+ lastPreparationResult = null;
51
+ }
40
52
  // ─── Re-exports (preserve public API for existing importers) ────────────────
41
53
  export { MILESTONE_ID_RE, generateMilestoneSuffix, nextMilestoneId, extractMilestoneSeq, parseMilestoneId, milestoneIdSort, maxMilestoneNum, findMilestoneIds, reserveMilestoneId, claimReservedId, getReservedMilestoneIds, clearReservedMilestoneIds, } from "./milestone-ids.js";
42
54
  export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesContext, } from "./guided-flow-queue.js";
@@ -323,7 +335,7 @@ function resolveAvailableModel(modelId, availableModels, currentProvider) {
323
335
  * Build the discuss-and-plan prompt for a new milestone.
324
336
  * Used by all three "new milestone" paths (first ever, no active, all complete).
325
337
  */
326
- function buildDiscussPrompt(nextId, preamble, _basePath, preparationContext) {
338
+ function buildDiscussPrompt(nextId, preamble, _basePath) {
327
339
  const milestoneRel = `.gsd/milestones/${nextId}`;
328
340
  const inlinedTemplates = [
329
341
  inlineTemplate("project", "Project"),
@@ -335,7 +347,6 @@ function buildDiscussPrompt(nextId, preamble, _basePath, preparationContext) {
335
347
  return loadPrompt("discuss", {
336
348
  milestoneId: nextId,
337
349
  preamble,
338
- preparationContext: preparationContext ?? "",
339
350
  contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
340
351
  roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
341
352
  inlinedTemplates,
@@ -366,12 +377,50 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
366
377
  multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
367
378
  });
368
379
  }
380
+ /**
381
+ * Build the prepared discuss prompt with brief injection.
382
+ * Uses the discuss-prepared template which encodes the 4-layer discussion protocol.
383
+ *
384
+ * @param nextId - The milestone ID being discussed
385
+ * @param preamble - Preamble text for the discuss prompt
386
+ * @param _basePath - Root directory of the project (unused, kept for signature consistency)
387
+ * @param prepResult - Preparation result containing briefs to inject
388
+ * @returns The prepared discuss prompt string
389
+ */
390
+ function buildPreparedPrompt(nextId, preamble, _basePath, prepResult) {
391
+ const milestoneRel = `.gsd/milestones/${nextId}`;
392
+ // Use context-enhanced instead of context for prepared discussions
393
+ const inlinedTemplates = [
394
+ inlineTemplate("project", "Project"),
395
+ inlineTemplate("requirements", "Requirements"),
396
+ inlineTemplate("context-enhanced", "Context Enhanced"),
397
+ inlineTemplate("roadmap", "Roadmap"),
398
+ inlineTemplate("decisions", "Decisions"),
399
+ ].join("\n\n---\n\n");
400
+ // Format the briefs from the preparation result
401
+ const codebaseBrief = prepResult.codebaseBrief || formatCodebaseBrief(prepResult.codebase);
402
+ const priorContextBrief = prepResult.priorContextBrief || formatPriorContextBrief(prepResult.priorContext);
403
+ const ecosystemBrief = prepResult.ecosystemBrief || formatEcosystemBrief(prepResult.ecosystem);
404
+ return loadPrompt("discuss-prepared", {
405
+ milestoneId: nextId,
406
+ preamble,
407
+ codebaseBrief,
408
+ priorContextBrief,
409
+ ecosystemBrief,
410
+ contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
411
+ roadmapPath: `${milestoneRel}/${nextId}-ROADMAP.md`,
412
+ inlinedTemplates,
413
+ commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
414
+ multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
415
+ });
416
+ }
369
417
  /**
370
418
  * Run preparation phase if enabled, then build the discuss prompt.
371
- * Preparation analyzes the codebase and prior context, injecting the results
372
- * as supplementary context into the standard discuss template. The discuss
373
- * template drives the conversation (asks "What's the vision?" first), while
374
- * the preparation briefs give the agent grounding in the existing codebase.
419
+ * This is the main entry point for new milestone discussions with preparation.
420
+ * Stores the preparation result for S02 to inject into the discuss prompt.
421
+ *
422
+ * When preparation succeeds, uses the discuss-prepared template with brief injection.
423
+ * Falls back to the standard discuss template when preparation is disabled or fails.
375
424
  *
376
425
  * @param ctx - Extension command context with UI for progress notifications
377
426
  * @param nextId - The milestone ID being discussed
@@ -380,12 +429,12 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
380
429
  * @returns The discuss prompt string
381
430
  */
382
431
  async function prepareAndBuildDiscussPrompt(ctx, nextId, preamble, basePath) {
432
+ // Clear stale preparation result immediately to prevent cross-session/project
433
+ // state leaks. This ensures data from a prior milestone/project never leaks
434
+ // into subsequent discussions (adversarial review fix #3602).
435
+ lastPreparationResult = null;
383
436
  const prefs = loadEffectiveGSDPreferences()?.preferences ?? {};
384
- // Run preparation if enabled (default: true) — results are injected as
385
- // supplementary context into the standard discuss prompt, NOT as a
386
- // replacement template. The discuss prompt always leads with "What's the
387
- // vision?" so the user defines the scope, not the codebase analysis.
388
- let preparationContext = "";
437
+ // Run preparation if enabled (default: true)
389
438
  if (prefs.discuss_preparation !== false) {
390
439
  try {
391
440
  const prepResult = await runPreparation(basePath, ctx.ui, {
@@ -393,24 +442,20 @@ async function prepareAndBuildDiscussPrompt(ctx, nextId, preamble, basePath) {
393
442
  discuss_web_research: prefs.discuss_web_research,
394
443
  discuss_depth: prefs.discuss_depth,
395
444
  });
445
+ lastPreparationResult = prepResult;
446
+ // Use prepared prompt if preparation was enabled and produced results
396
447
  if (prepResult.enabled) {
397
- const codebaseBrief = prepResult.codebaseBrief || formatCodebaseBrief(prepResult.codebase);
398
- const priorContextBrief = prepResult.priorContextBrief || formatPriorContextBrief(prepResult.priorContext);
399
- const parts = [];
400
- if (codebaseBrief)
401
- parts.push(`### Codebase Brief\n\n${codebaseBrief}`);
402
- if (priorContextBrief)
403
- parts.push(`### Prior Context Brief\n\n${priorContextBrief}`);
404
- if (parts.length > 0) {
405
- preparationContext = `\n\n## Preparation Context\n\nThe system analyzed the codebase before this discussion. Use these findings as background context — they describe what already exists, NOT what the user wants to build. Always ask the user what they want to build first.\n\n${parts.join("\n\n")}`;
406
- }
448
+ return buildPreparedPrompt(nextId, preamble, basePath, prepResult);
407
449
  }
408
450
  }
409
- catch (err) {
410
- logWarning("guided", `preparation failed, proceeding without context: ${err.message}`);
451
+ catch {
452
+ // If preparation throws, ensure stale data doesn't persist
453
+ lastPreparationResult = null;
411
454
  }
412
455
  }
413
- return buildDiscussPrompt(nextId, preamble, basePath, preparationContext);
456
+ // Fall back to standard discuss prompt for backward compatibility
457
+ // lastPreparationResult is already null (cleared at entry or on error)
458
+ return buildDiscussPrompt(nextId, preamble, basePath);
414
459
  }
415
460
  /**
416
461
  * Bootstrap a .gsd/ project from scratch for headless use.
@@ -5,7 +5,7 @@ import { tierOrdinal } from "./complexity-classifier.js";
5
5
  // ─── Known Model Tiers ───────────────────────────────────────────────────────
6
6
  // Maps known model IDs to their capability tier. Used when tier_models is not
7
7
  // explicitly configured to pick the best available model for each tier.
8
- export const MODEL_CAPABILITY_TIER = {
8
+ const MODEL_CAPABILITY_TIER = {
9
9
  // Light-tier models (cheapest)
10
10
  "claude-haiku-4-5": "light",
11
11
  "claude-3-5-haiku-latest": "light",
@@ -80,45 +80,15 @@ const MODEL_COST_PER_1K_INPUT = {
80
80
  // Per-model capability profiles (0–100 scale). Used for capability-aware
81
81
  // model selection within an eligible tier set.
82
82
  export const MODEL_CAPABILITY_PROFILES = {
83
- // ── Anthropic ──────────────────────────────────────────────────────────────
84
83
  "claude-opus-4-6": { coding: 95, debugging: 90, research: 85, reasoning: 95, speed: 30, longContext: 80, instruction: 90 },
85
84
  "claude-sonnet-4-6": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
86
- "claude-sonnet-4-5-20250514": { coding: 85, debugging: 80, research: 75, reasoning: 80, speed: 60, longContext: 75, instruction: 85 },
87
- "claude-3-5-sonnet-latest": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 70, instruction: 82 },
88
85
  "claude-haiku-4-5": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
89
- "claude-3-5-haiku-latest": { coding: 60, debugging: 50, research: 45, reasoning: 50, speed: 95, longContext: 50, instruction: 75 },
90
- "claude-3-haiku-20240307": { coding: 50, debugging: 40, research: 35, reasoning: 40, speed: 95, longContext: 40, instruction: 65 },
91
- "claude-3-opus-latest": { coding: 90, debugging: 85, research: 82, reasoning: 90, speed: 35, longContext: 75, instruction: 88 },
92
- // ── OpenAI GPT ─────────────────────────────────────────────────────────────
93
86
  "gpt-4o": { coding: 80, debugging: 75, research: 70, reasoning: 75, speed: 65, longContext: 70, instruction: 80 },
94
87
  "gpt-4o-mini": { coding: 55, debugging: 45, research: 40, reasoning: 45, speed: 90, longContext: 45, instruction: 70 },
95
- "gpt-4-turbo": { coding: 78, debugging: 72, research: 68, reasoning: 72, speed: 50, longContext: 65, instruction: 78 },
96
- "gpt-4.1": { coding: 82, debugging: 78, research: 72, reasoning: 78, speed: 62, longContext: 72, instruction: 82 },
97
- "gpt-4.1-mini": { coding: 58, debugging: 48, research: 42, reasoning: 48, speed: 88, longContext: 48, instruction: 72 },
98
- "gpt-4.1-nano": { coding: 40, debugging: 30, research: 25, reasoning: 30, speed: 95, longContext: 30, instruction: 60 },
99
- "gpt-5": { coding: 92, debugging: 88, research: 85, reasoning: 92, speed: 40, longContext: 85, instruction: 90 },
100
- "gpt-5-mini": { coding: 62, debugging: 52, research: 48, reasoning: 52, speed: 88, longContext: 52, instruction: 74 },
101
- "gpt-5-nano": { coding: 42, debugging: 32, research: 28, reasoning: 32, speed: 95, longContext: 32, instruction: 62 },
102
- "gpt-5-pro": { coding: 94, debugging: 90, research: 88, reasoning: 94, speed: 35, longContext: 88, instruction: 92 },
103
- "gpt-5.1": { coding: 93, debugging: 89, research: 86, reasoning: 93, speed: 42, longContext: 86, instruction: 91 },
104
- "gpt-5.1-codex-max": { coding: 90, debugging: 85, research: 70, reasoning: 85, speed: 55, longContext: 75, instruction: 85 },
105
- "gpt-5.1-codex-mini": { coding: 65, debugging: 55, research: 40, reasoning: 50, speed: 88, longContext: 48, instruction: 72 },
106
- "gpt-5.2": { coding: 93, debugging: 90, research: 87, reasoning: 93, speed: 42, longContext: 87, instruction: 91 },
107
- "gpt-5.2-codex": { coding: 93, debugging: 90, research: 72, reasoning: 88, speed: 50, longContext: 78, instruction: 88 },
108
- "gpt-5.3-codex": { coding: 94, debugging: 91, research: 74, reasoning: 89, speed: 50, longContext: 80, instruction: 89 },
109
- "gpt-5.3-codex-spark": { coding: 68, debugging: 58, research: 42, reasoning: 52, speed: 90, longContext: 50, instruction: 74 },
110
- "gpt-5.4": { coding: 95, debugging: 92, research: 88, reasoning: 94, speed: 42, longContext: 88, instruction: 92 },
111
- // ── OpenAI o-series (reasoning-first) ──────────────────────────────────────
112
- "o1": { coding: 78, debugging: 82, research: 78, reasoning: 90, speed: 20, longContext: 65, instruction: 82 },
113
- "o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
114
- "o4-mini": { coding: 75, debugging: 80, research: 72, reasoning: 88, speed: 60, longContext: 65, instruction: 80 },
115
- "o4-mini-deep-research": { coding: 75, debugging: 80, research: 85, reasoning: 88, speed: 30, longContext: 80, instruction: 80 },
116
- // ── Google ─────────────────────────────────────────────────────────────────
117
88
  "gemini-2.5-pro": { coding: 75, debugging: 70, research: 85, reasoning: 75, speed: 55, longContext: 90, instruction: 75 },
118
89
  "gemini-2.0-flash": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
119
- "gemini-flash-2.0": { coding: 50, debugging: 40, research: 50, reasoning: 40, speed: 95, longContext: 60, instruction: 65 },
120
- // ── DeepSeek ───────────────────────────────────────────────────────────────
121
90
  "deepseek-chat": { coding: 75, debugging: 65, research: 55, reasoning: 70, speed: 70, longContext: 55, instruction: 65 },
91
+ "o3": { coding: 80, debugging: 85, research: 80, reasoning: 92, speed: 25, longContext: 70, instruction: 85 },
122
92
  };
123
93
  // ─── Base Task Requirements Data Table ───────────────────────────────────────
124
94
  // Per-unit-type base requirement vectors. Weights indicate how important each
@@ -0,0 +1,67 @@
1
+ /**
2
+ * GSD Prompt Validation — Validates enhanced context output before writing.
3
+ *
4
+ * Implements R109 validation requirement: CONTEXT.md must have required sections
5
+ * before being written to disk.
6
+ */
7
+ /**
8
+ * Validate that enhanced context content has all required sections.
9
+ *
10
+ * Required sections per R109:
11
+ * - Scope section (## Scope, ## Milestone Scope, or ## Why This Milestone)
12
+ * - Architectural Decisions section (## Architectural Decisions)
13
+ * - Acceptance Criteria section (## Acceptance Criteria or ## Final Integrated Acceptance)
14
+ *
15
+ * Additionally validates that the Architectural Decisions section contains
16
+ * at least one decision entry (### heading or **Decision marker).
17
+ *
18
+ * @param content - The enhanced context markdown content
19
+ * @returns ValidationResult with valid flag and list of missing sections
20
+ */
21
+ export function validateEnhancedContext(content) {
22
+ const missing = [];
23
+ // Required section 1: Scope (multiple acceptable header variants)
24
+ const hasScopeSection = /^## Scope\b/m.test(content) ||
25
+ /^## Milestone Scope\b/m.test(content) ||
26
+ /^## Why This Milestone\b/m.test(content);
27
+ if (!hasScopeSection) {
28
+ missing.push("Milestone Scope or Why This Milestone");
29
+ }
30
+ // Required section 2: Architectural Decisions
31
+ const hasArchitecturalDecisions = /^## Architectural Decisions\b/m.test(content);
32
+ if (!hasArchitecturalDecisions) {
33
+ missing.push("Architectural Decisions");
34
+ }
35
+ // Required section 3: Acceptance Criteria (multiple acceptable header variants)
36
+ const hasAcceptanceCriteria = /^## Acceptance Criteria\b/m.test(content) ||
37
+ /^## Final Integrated Acceptance\b/m.test(content);
38
+ if (!hasAcceptanceCriteria) {
39
+ missing.push("Acceptance Criteria");
40
+ }
41
+ // Additional validation: Architectural Decisions must have at least one entry
42
+ if (hasArchitecturalDecisions) {
43
+ // Extract the section content between ## Architectural Decisions and the next ## heading.
44
+ // Uses indexOf-based extraction instead of regex with \z (which is invalid in JavaScript
45
+ // regex — it's PCRE/Ruby syntax and JS treats it as literal 'z').
46
+ const sectionStart = content.indexOf("## Architectural Decisions");
47
+ if (sectionStart === -1) {
48
+ missing.push("Architectural Decisions");
49
+ }
50
+ else {
51
+ const afterHeading = content.slice(sectionStart + "## Architectural Decisions".length);
52
+ const nextSection = afterHeading.search(/^## /m);
53
+ const sectionContent = nextSection === -1 ? afterHeading : afterHeading.slice(0, nextSection);
54
+ // Check for actual decision entries:
55
+ // - ### heading (subsection per decision)
56
+ // - **Decision marker (inline decision format)
57
+ const hasDecisionEntry = /^### /m.test(sectionContent) || /^\*\*Decision/m.test(sectionContent);
58
+ if (!hasDecisionEntry) {
59
+ missing.push("At least one architectural decision entry");
60
+ }
61
+ }
62
+ }
63
+ return {
64
+ valid: missing.length === 0,
65
+ missing,
66
+ };
67
+ }