gsd-pi 2.79.0 → 2.80.0

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 (151) hide show
  1. package/README.md +94 -47
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/contracts.js +1 -0
  4. package/dist/resources/extensions/gsd/auto/orchestrator.js +146 -0
  5. package/dist/resources/extensions/gsd/auto/phases.js +61 -7
  6. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  7. package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
  8. package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
  9. package/dist/resources/extensions/gsd/auto-prompts.js +52 -29
  10. package/dist/resources/extensions/gsd/auto-recovery.js +63 -55
  11. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -0
  12. package/dist/resources/extensions/gsd/auto-start.js +3 -2
  13. package/dist/resources/extensions/gsd/auto.js +159 -2
  14. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
  15. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  16. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +41 -45
  17. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +8 -8
  18. package/dist/resources/extensions/gsd/commands/context.js +1 -1
  19. package/dist/resources/extensions/gsd/gsd-db.js +34 -1
  20. package/dist/resources/extensions/gsd/guided-flow.js +40 -0
  21. package/dist/resources/extensions/gsd/paths.js +5 -1
  22. package/dist/resources/extensions/gsd/post-execution-checks.js +25 -6
  23. package/dist/resources/extensions/gsd/preferences-types.js +20 -2
  24. package/dist/resources/extensions/gsd/preferences-validation.js +3 -3
  25. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +82 -2
  26. package/dist/resources/extensions/gsd/unit-context-composer.js +32 -0
  27. package/dist/resources/extensions/gsd/unit-context-manifest.js +21 -0
  28. package/dist/resources/extensions/gsd/uok/audit.js +23 -9
  29. package/dist/resources/extensions/gsd/uok/contracts.js +69 -1
  30. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +3 -0
  31. package/dist/resources/extensions/gsd/uok/loop-adapter.js +48 -33
  32. package/dist/resources/extensions/gsd/uok/timeline.js +125 -0
  33. package/dist/resources/extensions/shared/gsd-phase-state.js +45 -3
  34. package/dist/resources/extensions/shared/interview-ui.js +15 -4
  35. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  36. package/dist/web/standalone/.next/BUILD_ID +1 -1
  37. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  38. package/dist/web/standalone/.next/build-manifest.json +2 -2
  39. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/index.html +1 -1
  56. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  63. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  65. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  66. package/package.json +1 -1
  67. package/packages/daemon/package.json +2 -2
  68. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  69. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  70. package/packages/mcp-server/dist/workflow-tools.js +53 -0
  71. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  72. package/packages/mcp-server/package.json +2 -2
  73. package/packages/mcp-server/src/workflow-tools.test.ts +129 -2
  74. package/packages/mcp-server/src/workflow-tools.ts +81 -0
  75. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  76. package/packages/native/package.json +1 -1
  77. package/packages/pi-agent-core/package.json +1 -1
  78. package/packages/pi-ai/package.json +1 -1
  79. package/packages/pi-coding-agent/package.json +1 -1
  80. package/packages/pi-tui/package.json +1 -1
  81. package/packages/rpc-client/package.json +1 -1
  82. package/pkg/package.json +1 -1
  83. package/src/resources/extensions/gsd/auto/contracts.ts +87 -0
  84. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -3
  85. package/src/resources/extensions/gsd/auto/orchestrator.ts +161 -0
  86. package/src/resources/extensions/gsd/auto/phases.ts +88 -9
  87. package/src/resources/extensions/gsd/auto/session.ts +11 -0
  88. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  89. package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
  90. package/src/resources/extensions/gsd/auto-prompts.ts +106 -28
  91. package/src/resources/extensions/gsd/auto-recovery.ts +59 -53
  92. package/src/resources/extensions/gsd/auto-runtime-state.ts +7 -0
  93. package/src/resources/extensions/gsd/auto-start.ts +3 -2
  94. package/src/resources/extensions/gsd/auto.ts +167 -1
  95. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +14 -1
  96. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  97. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +49 -46
  98. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-shouldblock-basepath.test.ts +97 -0
  99. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +8 -4
  100. package/src/resources/extensions/gsd/commands/context.ts +1 -1
  101. package/src/resources/extensions/gsd/gsd-db.ts +35 -1
  102. package/src/resources/extensions/gsd/guided-flow.ts +47 -0
  103. package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
  104. package/src/resources/extensions/gsd/paths.ts +6 -1
  105. package/src/resources/extensions/gsd/post-execution-checks.ts +31 -6
  106. package/src/resources/extensions/gsd/preferences-types.ts +23 -4
  107. package/src/resources/extensions/gsd/preferences-validation.ts +3 -3
  108. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +32 -0
  109. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +353 -0
  110. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +108 -1
  111. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +39 -0
  112. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +3 -0
  113. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -2
  114. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +203 -0
  115. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +148 -0
  116. package/src/resources/extensions/gsd/tests/current-directory-root-homedir-fallback.test.ts +63 -0
  117. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +42 -0
  118. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +63 -2
  119. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +109 -0
  120. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +95 -0
  121. package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +14 -0
  122. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +79 -0
  123. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +134 -0
  124. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +8 -0
  125. package/src/resources/extensions/gsd/tests/paused-session-via-db.test.ts +2 -0
  126. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +27 -0
  127. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +46 -0
  128. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +3 -0
  129. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +85 -0
  130. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +2 -0
  131. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +59 -0
  132. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +38 -0
  133. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +32 -0
  134. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +109 -1
  135. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +98 -0
  136. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +132 -3
  137. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +3 -0
  138. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +84 -1
  139. package/src/resources/extensions/gsd/unit-context-composer.ts +49 -0
  140. package/src/resources/extensions/gsd/unit-context-manifest.ts +34 -0
  141. package/src/resources/extensions/gsd/uok/audit.ts +25 -9
  142. package/src/resources/extensions/gsd/uok/contracts.ts +105 -0
  143. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +4 -0
  144. package/src/resources/extensions/gsd/uok/loop-adapter.ts +60 -45
  145. package/src/resources/extensions/gsd/uok/timeline.ts +158 -0
  146. package/src/resources/extensions/shared/gsd-phase-state.ts +56 -3
  147. package/src/resources/extensions/shared/interview-ui.ts +18 -5
  148. package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +43 -1
  149. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +41 -0
  150. /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → V-3Ehy4B24f9FCGiLPWIM}/_buildManifest.js +0 -0
  151. /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → V-3Ehy4B24f9FCGiLPWIM}/_ssgManifest.js +0 -0
@@ -10,6 +10,7 @@ import { hasVerdict, getUatType } from "./verdict-parser.js";
10
10
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
11
11
  import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
12
12
  import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
13
+ import { isContextModeEnabled } from "./preferences-types.js";
13
14
  import { parseRoadmap } from "./parsers-legacy.js";
14
15
  import { getLoadedSkills } from "@gsd/pi-coding-agent";
15
16
  import { join, basename } from "node:path";
@@ -19,7 +20,7 @@ import { getPendingGatesForTurn } from "./gsd-db.js";
19
20
  import { assertGateCoverage, getGatesForTurn, } from "./gate-registry.js";
20
21
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
21
22
  import { readPhaseAnchor, formatAnchorForPrompt } from "./phase-anchor.js";
22
- import { composeInlinedContext } from "./unit-context-composer.js";
23
+ import { composeContextModeInstructions, composeInlinedContext } from "./unit-context-composer.js";
23
24
  import { logWarning } from "./workflow-logger.js";
24
25
  import { inlineGraphSubgraph } from "./graph-context.js";
25
26
  import { buildExtractionStepsBlock } from "./commands-extract-learnings.js";
@@ -71,6 +72,21 @@ function capPreamble(preamble) {
71
72
  return preamble;
72
73
  return truncateAtSectionBoundary(preamble, budget).content;
73
74
  }
75
+ function renderContextModeForPrompt(unitType, base, renderMode = "standalone") {
76
+ const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
77
+ return composeContextModeInstructions(unitType, {
78
+ enabled: isContextModeEnabled(effectivePrefs),
79
+ renderMode,
80
+ });
81
+ }
82
+ function prependContextModeToBlock(unitType, base, block, renderMode = "standalone") {
83
+ const contextMode = renderContextModeForPrompt(unitType, base, renderMode);
84
+ if (!contextMode)
85
+ return block;
86
+ if (!block.trim())
87
+ return contextMode;
88
+ return `${contextMode}\n\n${block}`;
89
+ }
74
90
  // ─── Executor Constraints ─────────────────────────────────────────────────────
75
91
  /**
76
92
  * Format executor context constraints for injection into the plan-slice prompt.
@@ -1119,6 +1135,7 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
1119
1135
  */
1120
1136
  export async function buildDiscussMilestonePrompt(mid, midTitle, base, structuredQuestionsAvailable = "false") {
1121
1137
  const discussTemplates = inlineTemplate("context", "Context");
1138
+ const contextModeInstructions = renderContextModeForPrompt("discuss-milestone", base);
1122
1139
  const basePrompt = loadPrompt("guided-discuss-milestone", {
1123
1140
  workingDirectory: base,
1124
1141
  milestoneId: mid,
@@ -1128,13 +1145,14 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
1128
1145
  commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1129
1146
  fastPathInstruction: "",
1130
1147
  });
1148
+ const promptWithContextMode = prependContextModeToBlock("discuss-milestone", base, basePrompt);
1131
1149
  // If a CONTEXT-DRAFT.md exists, append it as seed material
1132
1150
  const draftPath = resolveMilestoneFile(base, mid, "CONTEXT-DRAFT");
1133
1151
  const draftContent = draftPath ? await loadFile(draftPath) : null;
1134
1152
  if (draftContent) {
1135
- return `${basePrompt}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${draftContent}`;
1153
+ return `${promptWithContextMode}\n\n## Prior Discussion (Draft Seed)\n\nThe following draft was captured from a prior multi-milestone discussion. Use it as seed material — the user has already provided this context. Start with a brief reflection on what the draft covers, then probe for any gaps or open questions before writing the full CONTEXT.md.\n\n${draftContent}`;
1136
1154
  }
1137
- return basePrompt;
1155
+ return contextModeInstructions ? promptWithContextMode : basePrompt;
1138
1156
  }
1139
1157
  /**
1140
1158
  * Build a prompt for the workflow-preferences unit type (deep mode).
@@ -1143,10 +1161,10 @@ export async function buildDiscussMilestonePrompt(mid, midTitle, base, structure
1143
1161
  * in deep-mode bootstrap before discuss-project.
1144
1162
  */
1145
1163
  export async function buildWorkflowPreferencesPrompt(base, structuredQuestionsAvailable = "false") {
1146
- return loadPrompt("guided-workflow-preferences", {
1164
+ return prependContextModeToBlock("workflow-preferences", base, loadPrompt("guided-workflow-preferences", {
1147
1165
  workingDirectory: base,
1148
1166
  structuredQuestionsAvailable,
1149
- });
1167
+ }));
1150
1168
  }
1151
1169
  /**
1152
1170
  * Build a prompt for the research-project (parallel) unit type (deep mode).
@@ -1156,10 +1174,10 @@ export async function buildWorkflowPreferencesPrompt(base, structuredQuestionsAv
1156
1174
  * are missing. Skipped entirely if user picked "skip".
1157
1175
  */
1158
1176
  export async function buildResearchProjectPrompt(base, structuredQuestionsAvailable = "false") {
1159
- return loadPrompt("guided-research-project", {
1177
+ return prependContextModeToBlock("research-project", base, loadPrompt("guided-research-project", {
1160
1178
  workingDirectory: base,
1161
1179
  structuredQuestionsAvailable,
1162
- });
1180
+ }));
1163
1181
  }
1164
1182
  /**
1165
1183
  * Build a prompt for the research-decision unit type (deep mode).
@@ -1168,10 +1186,10 @@ export async function buildResearchProjectPrompt(base, structuredQuestionsAvaila
1168
1186
  * and before research-project-parallel.
1169
1187
  */
1170
1188
  export async function buildResearchDecisionPrompt(base, structuredQuestionsAvailable = "false") {
1171
- return loadPrompt("guided-research-decision", {
1189
+ return prependContextModeToBlock("research-decision", base, loadPrompt("guided-research-decision", {
1172
1190
  workingDirectory: base,
1173
1191
  structuredQuestionsAvailable,
1174
- });
1192
+ }));
1175
1193
  }
1176
1194
  /**
1177
1195
  * Build a prompt for the discuss-project unit type (deep mode).
@@ -1181,12 +1199,12 @@ export async function buildResearchDecisionPrompt(base, structuredQuestionsAvail
1181
1199
  */
1182
1200
  export async function buildDiscussProjectPrompt(base, structuredQuestionsAvailable = "false") {
1183
1201
  const inlinedTemplates = inlineTemplate("project", "Project");
1184
- return loadPrompt("guided-discuss-project", {
1202
+ return prependContextModeToBlock("discuss-project", base, loadPrompt("guided-discuss-project", {
1185
1203
  workingDirectory: base,
1186
1204
  inlinedTemplates,
1187
1205
  structuredQuestionsAvailable,
1188
1206
  commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1189
- });
1207
+ }));
1190
1208
  }
1191
1209
  /**
1192
1210
  * Build a prompt for the discuss-requirements unit type (deep mode).
@@ -1196,12 +1214,12 @@ export async function buildDiscussProjectPrompt(base, structuredQuestionsAvailab
1196
1214
  */
1197
1215
  export async function buildDiscussRequirementsPrompt(base, structuredQuestionsAvailable = "false") {
1198
1216
  const inlinedTemplates = inlineTemplate("requirements", "Requirements");
1199
- return loadPrompt("guided-discuss-requirements", {
1217
+ return prependContextModeToBlock("discuss-requirements", base, loadPrompt("guided-discuss-requirements", {
1200
1218
  workingDirectory: base,
1201
1219
  inlinedTemplates,
1202
1220
  structuredQuestionsAvailable,
1203
1221
  commitInstruction: "Do not commit planning artifacts — .gsd/ is managed externally.",
1204
- });
1222
+ }));
1205
1223
  }
1206
1224
  export async function buildResearchMilestonePrompt(mid, midTitle, base) {
1207
1225
  // #4782 phase 3: research-milestone migrated through the composer.
@@ -1254,7 +1272,7 @@ export async function buildResearchMilestonePrompt(mid, midTitle, base) {
1254
1272
  if (knowledgeInlineRM)
1255
1273
  parts.push(knowledgeInlineRM);
1256
1274
  }
1257
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
1275
+ const inlinedContext = prependContextModeToBlock("research-milestone", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`));
1258
1276
  const outputRelPath = relMilestoneFile(base, mid, "RESEARCH");
1259
1277
  return loadPrompt("research-milestone", {
1260
1278
  workingDirectory: base,
@@ -1324,7 +1342,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
1324
1342
  inlined.push(inlineTemplate("plan", "Slice Plan"));
1325
1343
  inlined.push(inlineTemplate("task-plan", "Task Plan"));
1326
1344
  }
1327
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1345
+ const inlinedContext = prependContextModeToBlock("plan-milestone", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`));
1328
1346
  const outputRelPath = relMilestoneFile(base, mid, "ROADMAP");
1329
1347
  const researchOutputPath = join(base, relMilestoneFile(base, mid, "RESEARCH"));
1330
1348
  const secretsOutputPath = join(base, relMilestoneFile(base, mid, "SECRETS"));
@@ -1349,7 +1367,7 @@ export async function buildPlanMilestonePrompt(mid, midTitle, base, level) {
1349
1367
  ...buildSkillDiscoveryVars(),
1350
1368
  });
1351
1369
  }
1352
- export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base) {
1370
+ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base, options) {
1353
1371
  const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1354
1372
  const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1355
1373
  const contextPath = resolveMilestoneFile(base, mid, "CONTEXT");
@@ -1400,7 +1418,7 @@ export async function buildResearchSlicePrompt(mid, _midTitle, sid, sTitle, base
1400
1418
  const overridesInline = formatOverridesSection(activeOverrides);
1401
1419
  if (overridesInline)
1402
1420
  inlined.unshift(overridesInline);
1403
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1421
+ const inlinedContext = prependContextModeToBlock("research-slice", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`), options?.contextModeRenderMode);
1404
1422
  const outputRelPath = relSliceFile(base, mid, sid, "RESEARCH");
1405
1423
  return loadPrompt("research-slice", {
1406
1424
  workingDirectory: base,
@@ -1483,7 +1501,7 @@ async function renderSlicePrompt(options) {
1483
1501
  const overridesInline = formatOverridesSection(await loadActiveOverrides(base));
1484
1502
  if (overridesInline)
1485
1503
  inlined.unshift(overridesInline);
1486
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1504
+ const inlinedContext = prependContextModeToBlock(promptTemplate, base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`), options.contextModeRenderMode);
1487
1505
  const executorContextConstraints = formatExecutorConstraints(sessionContextWindow, modelRegistry, sessionProvider);
1488
1506
  const outputRelPath = relSliceFile(base, mid, sid, "PLAN");
1489
1507
  const commitInstruction = "Do not commit — .gsd/ planning docs are managed externally and not tracked in git.";
@@ -1686,6 +1704,7 @@ export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base
1686
1704
  const etPending = getPendingGatesForTurn(mid, sid, "execute-task", tid);
1687
1705
  assertGateCoverage(etPending, "execute-task", { requireAll: false });
1688
1706
  const gatesToClose = renderGatesToCloseBlock(getGatesForTurn("execute-task"), { pending: new Set(etPending.map((g) => g.gate_id)), allowOmit: true });
1707
+ phaseAnchorSection = prependContextModeToBlock("execute-task", base, phaseAnchorSection, opts.contextModeRenderMode);
1689
1708
  return loadPrompt("execute-task", {
1690
1709
  overridesSection,
1691
1710
  runtimeContext,
@@ -1713,6 +1732,7 @@ export async function buildExecuteTaskPrompt(mid, sid, sTitle, tid, tTitle, base
1713
1732
  taskTitle: tTitle,
1714
1733
  taskPlanContent,
1715
1734
  extraContext: [taskPlanInline, slicePlanExcerpt, finalCarryForward, resumeSection],
1735
+ unitType: "execute-task",
1716
1736
  }),
1717
1737
  });
1718
1738
  }
@@ -1803,7 +1823,7 @@ export async function buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, base,
1803
1823
  const finalBody = completeOverridesInline
1804
1824
  ? `${completeOverridesInline}\n\n---\n\n${body}`
1805
1825
  : body;
1806
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${finalBody}`);
1826
+ const inlinedContext = prependContextModeToBlock("complete-slice", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${finalBody}`));
1807
1827
  const roadmapRel = relMilestoneFile(base, mid, "ROADMAP");
1808
1828
  const sliceRel = relSlicePath(base, mid, sid);
1809
1829
  const sliceSummaryPath = join(base, `${sliceRel}/${sid}-SUMMARY.md`);
@@ -1894,7 +1914,7 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
1894
1914
  if (contextInline)
1895
1915
  inlined.push(contextInline);
1896
1916
  inlined.push(inlineTemplate("milestone-summary", "Milestone Summary"));
1897
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1917
+ const inlinedContext = prependContextModeToBlock("complete-milestone", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`));
1898
1918
  const milestoneSummaryPath = join(base, `${relMilestonePath(base, mid)}/${mid}-SUMMARY.md`);
1899
1919
  const learningsRelPath = join(relMilestonePath(base, mid), `${mid}-LEARNINGS.md`);
1900
1920
  const learningsAbsPath = join(base, learningsRelPath);
@@ -2034,7 +2054,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
2034
2054
  const contextInline = await inlineFileOptional(contextPath, contextRel, "Milestone Context");
2035
2055
  if (contextInline)
2036
2056
  inlined.push(contextInline);
2037
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2057
+ const inlinedContext = prependContextModeToBlock("validate-milestone", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`));
2038
2058
  const validationOutputPath = join(base, `${relMilestonePath(base, mid)}/${mid}-VALIDATION.md`);
2039
2059
  const roadmapOutputPath = `${relMilestonePath(base, mid)}/${mid}-ROADMAP.md`;
2040
2060
  // Every milestone validation turn owns MV01–MV04 unconditionally: the
@@ -2104,7 +2124,7 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
2104
2124
  const replanOverridesInline = formatOverridesSection(replanActiveOverrides);
2105
2125
  if (replanOverridesInline)
2106
2126
  inlined.unshift(replanOverridesInline);
2107
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
2127
+ const inlinedContext = prependContextModeToBlock("replan-slice", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`));
2108
2128
  const replanPath = join(base, `${relSlicePath(base, mid, sid)}/${sid}-REPLAN.md`);
2109
2129
  // Build capture context for replan prompt (captures that triggered this replan)
2110
2130
  let captureContext = "(none)";
@@ -2171,7 +2191,7 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
2171
2191
  }
2172
2192
  };
2173
2193
  const composed = await composeInlinedContext("run-uat", resolveArtifact);
2174
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${composed}`);
2194
+ const inlinedContext = prependContextModeToBlock("run-uat", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${composed}`));
2175
2195
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "ASSESSMENT"));
2176
2196
  const uatType = getUatType(uatContent);
2177
2197
  return loadPrompt("run-uat", {
@@ -2242,7 +2262,7 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
2242
2262
  const knowledgeInlineRA = await inlineKnowledgeBudgeted(base, extractKeywords(midTitle));
2243
2263
  if (knowledgeInlineRA)
2244
2264
  parts.push(knowledgeInlineRA);
2245
- const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`);
2265
+ const inlinedContext = prependContextModeToBlock("reassess-roadmap", base, capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${parts.join("\n\n---\n\n")}`));
2246
2266
  const assessmentPath = join(base, relSliceFile(base, mid, completedSliceId, "ASSESSMENT"));
2247
2267
  // Build deferred captures context for reassess prompt
2248
2268
  let deferredCaptures = "(none)";
@@ -2313,6 +2333,7 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
2313
2333
  sessionContextWindow: opts?.sessionContextWindow,
2314
2334
  modelRegistry: opts?.modelRegistry,
2315
2335
  sessionProvider: opts?.sessionProvider,
2336
+ contextModeRenderMode: "nested",
2316
2337
  });
2317
2338
  const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
2318
2339
  subagentSections.push([
@@ -2332,7 +2353,7 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
2332
2353
  milestoneTitle: midTitle,
2333
2354
  sliceId: sid,
2334
2355
  sliceTitle: sTitle,
2335
- graphContext,
2356
+ graphContext: prependContextModeToBlock("reactive-execute", base, graphContext),
2336
2357
  readyTaskCount: String(readyTaskIds.length),
2337
2358
  readyTaskList: readyTaskListLines.join("\n"),
2338
2359
  subagentPrompts: subagentSections.join("\n\n---\n\n"),
@@ -2382,7 +2403,7 @@ export async function buildParallelResearchSlicesPrompt(mid, midTitle, slices, b
2382
2403
  const subagentSections = [];
2383
2404
  const modelSuffix = subagentModel ? ` with model: "${subagentModel}"` : "";
2384
2405
  for (const slice of slices) {
2385
- const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath);
2406
+ const slicePrompt = await buildResearchSlicePrompt(mid, midTitle, slice.id, slice.title, basePath, { contextModeRenderMode: "nested" });
2386
2407
  subagentSections.push([
2387
2408
  `### ${slice.id}: ${slice.title}`,
2388
2409
  "",
@@ -2426,6 +2447,8 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base,
2426
2447
  for (const def of gateDefs) {
2427
2448
  gateListLines.push(`- **${def.id}**: ${def.question}`);
2428
2449
  const subPrompt = [
2450
+ renderContextModeForPrompt("gate-evaluate", base, "nested"),
2451
+ "",
2429
2452
  `You are evaluating quality gate **${def.id}** for slice ${sid} (${sTitle}).`,
2430
2453
  "",
2431
2454
  `**Working directory:** \`${normalizedBase}\`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT \`cd\` to any other directory.`,
@@ -2466,7 +2489,7 @@ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base,
2466
2489
  milestoneTitle: midTitle,
2467
2490
  sliceId: sid,
2468
2491
  sliceTitle: sTitle,
2469
- slicePlanContent: planContent,
2492
+ slicePlanContent: prependContextModeToBlock("gate-evaluate", base, planContent),
2470
2493
  gateCount: String(pending.length),
2471
2494
  gateList: gateListLines.join("\n"),
2472
2495
  subagentPrompts: subagentSections.join("\n\n---\n\n"),
@@ -2536,7 +2559,7 @@ export async function buildRewriteDocsPrompt(mid, midTitle, activeSlice, base, o
2536
2559
  `**During:** ${o.appliedAt}`,
2537
2560
  ].join("\n")).join("\n\n");
2538
2561
  const documentList = docList.length > 0 ? docList.join("\n") : "- No active plan documents found.";
2539
- return loadPrompt("rewrite-docs", {
2562
+ return prependContextModeToBlock("rewrite-docs", base, loadPrompt("rewrite-docs", {
2540
2563
  workingDirectory: base,
2541
2564
  milestoneId: mid,
2542
2565
  milestoneTitle: midTitle,
@@ -2545,5 +2568,5 @@ export async function buildRewriteDocsPrompt(mid, midTitle, activeSlice, base, o
2545
2568
  overrideContent,
2546
2569
  documentList,
2547
2570
  overridesPath: relGsdRootFile("OVERRIDES"),
2548
- });
2571
+ }));
2549
2572
  }
@@ -12,7 +12,7 @@ import { appendEvent } from "./workflow-events.js";
12
12
  import { atomicWriteSync } from "./atomic-write.js";
13
13
  import { clearParseCache } from "./files.js";
14
14
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
15
- import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone } from "./gsd-db.js";
15
+ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updateTaskStatus, updateSliceStatus, insertSlice, getMilestone, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
16
16
  import { isValidationTerminal } from "./state.js";
17
17
  import { getErrorMessage } from "./error-utils.js";
18
18
  import { logWarning, logError } from "./workflow-logger.js";
@@ -257,7 +257,7 @@ function scanGsdTaggedCommits(basePath, milestoneId, gitArgs) {
257
257
  if (!commitMessageHasGsdTrailer(message))
258
258
  continue;
259
259
  const commitFiles = getChangedFilesForCommit(basePath, hash);
260
- if (!commitMatchesMilestone(message, milestoneId, commitFiles))
260
+ if (!commitMatchesMilestone(basePath, message, milestoneId, commitFiles))
261
261
  continue;
262
262
  matched = true;
263
263
  for (const file of commitFiles) {
@@ -278,22 +278,37 @@ function getChangedFilesForCommit(basePath, hash) {
278
278
  function commitMessageHasGsdTrailer(message) {
279
279
  return /^GSD-(?:Task|Unit):\s*\S+/m.test(message);
280
280
  }
281
- function commitMatchesMilestone(message, milestoneId, files) {
281
+ function commitMatchesMilestone(basePath, message, milestoneId, files) {
282
282
  if (commitTrailerStartsWithMilestone(message, milestoneId))
283
283
  return true;
284
284
  // Meaningful execute-task commits currently store task scope as Sxx/Tyy
285
285
  // rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone when
286
286
  // either the commit touched this milestone's artifacts, or — for projects
287
287
  // where .gsd/ is gitignored/external (#5033) — the message explicitly
288
- // names the milestone.
288
+ // names the milestone or local GSD state proves the task belongs here.
289
289
  if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
290
290
  if (files.some((file) => isMilestoneArtifactPath(file, milestoneId)))
291
291
  return true;
292
292
  if (commitMessageMentionsMilestone(message, milestoneId))
293
293
  return true;
294
+ if (commitTaskTrailerBelongsToMilestone(basePath, message, milestoneId))
295
+ return true;
294
296
  }
295
297
  return false;
296
298
  }
299
+ function commitTaskTrailerBelongsToMilestone(basePath, message, milestoneId) {
300
+ const match = message.match(/^GSD-Task:\s*(S[^/\s]+)\/(T[^\s]+)/m);
301
+ if (!match)
302
+ return false;
303
+ const [, sliceId, taskId] = match;
304
+ if (getTask(milestoneId, sliceId, taskId))
305
+ return true;
306
+ const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId);
307
+ if (!tasksDir)
308
+ return false;
309
+ return existsSync(join(tasksDir, `${taskId}-PLAN.md`))
310
+ || existsSync(join(tasksDir, `${taskId}-SUMMARY.md`));
311
+ }
297
312
  function commitMessageMentionsMilestone(message, milestoneId) {
298
313
  if (!MILESTONE_ID_RE.test(milestoneId))
299
314
  return false;
@@ -495,66 +510,32 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
495
510
  return false;
496
511
  }
497
512
  }
498
- // plan-slice must produce a plan with actual task entries, not just a scaffold.
499
- // The plan file may exist from a prior discussion/context step with only headings
500
- // but no tasks. Without this check the artifact is considered "complete" and the
501
- // unit gets skipped — but deriveState still returns phase:"planning" because the
502
- // plan has no tasks, creating an infinite skip loop (#699).
503
- if (unitType === "plan-slice") {
504
- const planContent = readFileSync(absPath, "utf-8");
505
- // Accept checkbox-style (- [x] **T01: ...) or heading-style (### T01 -- / ### T01: / ### T01 —)
506
- const hasCheckboxTask = /^- \[[xX ]\] \*\*T\d+:/m.test(planContent);
507
- const hasHeadingTask = /^#{2,4}\s+T\d+\s*(?:--|—|:)/m.test(planContent);
508
- if (!hasCheckboxTask && !hasHeadingTask) {
509
- logWarning("recovery", `verify-fail ${unitType} ${unitId}: plan has no task checkbox/heading (len=${planContent.length}) at ${absPath}`);
510
- return false;
511
- }
512
- }
513
- // execute-task: DB status is authoritative. Fall back to checked-checkbox
514
- // detection when the DB is unavailable (unmigrated projects), or when the
515
- // disk artifacts already reflect completion but the DB replay is one beat
516
- // behind the completion write.
517
- if (unitType === "execute-task") {
518
- const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
519
- if (mid && sid && tid) {
520
- const dbTask = getTask(mid, sid, tid);
521
- if (dbTask) {
522
- if (dbTask.status !== "complete" && dbTask.status !== "done" && !hasCheckedTaskCompletionOnDisk(base, mid, sid, tid)) {
523
- return false;
524
- }
525
- }
526
- else if (!isDbAvailable()) {
527
- // LEGACY: Pre-migration fallback for projects without DB.
528
- // Require a CHECKED checkbox — a bare heading or unchecked checkbox
529
- // does not prove gsd_complete_task ran. Summary file on disk alone
530
- // is not sufficient evidence (could be a rogue write) (#3607).
531
- if (!hasCheckedTaskCompletionOnDisk(base, mid, sid, tid))
532
- return false;
533
- }
534
- else {
535
- // DB available but task row not found — completion tool never ran (#3607)
536
- return false;
537
- }
538
- }
539
- }
540
- // plan-slice must also produce individual task plan files for every task listed
541
- // in the slice plan. Without this check, a plan-slice that wrote S{sid}-PLAN.md
542
- // but omitted T{tid}-PLAN.md files would be marked complete, causing execute-task
543
- // to dispatch with a missing task plan (see issue #739).
513
+ // plan-slice verification is DB-primary. The slice plan is a projection, so
514
+ // DB task rows prove the slice was planned even if the rendered markdown no
515
+ // longer uses legacy checkbox/heading syntax.
544
516
  if (unitType === "plan-slice") {
545
517
  const { milestone: mid, slice: sid } = parseUnitId(unitId);
546
518
  if (mid && sid) {
547
519
  try {
548
- // DB primary path — get task IDs to verify task plan files exist
549
520
  let taskIds = null;
550
521
  if (isDbAvailable()) {
551
- const tasks = getSliceTasks(mid, sid);
552
- if (tasks.length > 0)
553
- taskIds = tasks.map(t => t.id);
522
+ const refreshed = refreshOpenDatabaseFromDisk();
523
+ if (refreshed) {
524
+ const tasks = getSliceTasks(mid, sid);
525
+ if (tasks.length > 0)
526
+ taskIds = tasks.map(t => t.id);
527
+ }
554
528
  }
555
529
  if (!taskIds) {
556
- // LEGACY: DB unavailable or no tasks in DB parse plan file for task IDs
530
+ // LEGACY: DB unavailable or no tasks in DB. Require actual task
531
+ // entries so an empty scaffold cannot advance the pipeline (#699).
557
532
  const planContent = readFileSync(absPath, "utf-8");
533
+ const hasCheckboxTask = /^\s*- \[[xX ]\] \*\*T\d+:/m.test(planContent);
534
+ const hasHeadingTask = /^\s*#{2,4}\s+T\d+\s*(?:--|—|:)/m.test(planContent);
535
+ if (!hasCheckboxTask && !hasHeadingTask) {
536
+ logWarning("recovery", `verify-fail ${unitType} ${unitId}: plan has no task checkbox/heading (len=${planContent.length}) at ${absPath}`);
537
+ return false;
538
+ }
558
539
  const plan = parseLegacyPlan(planContent);
559
540
  if (plan.tasks.length > 0)
560
541
  taskIds = plan.tasks.map((t) => t.id);
@@ -580,6 +561,33 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
580
561
  }
581
562
  }
582
563
  }
564
+ // execute-task: DB status is authoritative. Fall back to checked-checkbox
565
+ // detection when the DB is unavailable (unmigrated projects), or when the
566
+ // disk artifacts already reflect completion but the DB replay is one beat
567
+ // behind the completion write.
568
+ if (unitType === "execute-task") {
569
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
570
+ if (mid && sid && tid) {
571
+ const dbTask = getTask(mid, sid, tid);
572
+ if (dbTask) {
573
+ if (dbTask.status !== "complete" && dbTask.status !== "done" && !hasCheckedTaskCompletionOnDisk(base, mid, sid, tid)) {
574
+ return false;
575
+ }
576
+ }
577
+ else if (!isDbAvailable()) {
578
+ // LEGACY: Pre-migration fallback for projects without DB.
579
+ // Require a CHECKED checkbox — a bare heading or unchecked checkbox
580
+ // does not prove gsd_complete_task ran. Summary file on disk alone
581
+ // is not sufficient evidence (could be a rogue write) (#3607).
582
+ if (!hasCheckedTaskCompletionOnDisk(base, mid, sid, tid))
583
+ return false;
584
+ }
585
+ else {
586
+ // DB available but task row not found — completion tool never ran (#3607)
587
+ return false;
588
+ }
589
+ }
590
+ }
583
591
  // complete-slice: DB status is authoritative for whether the slice is done.
584
592
  // Fall back to file-based check (roadmap [x]) when DB is unavailable.
585
593
  if (unitType === "complete-slice") {
@@ -3,11 +3,15 @@ import { AutoSession } from "./auto/session.js";
3
3
  import { isDeterministicPolicyError, isQueuedUserMessageSkip, isToolInvocationError, markToolEnd as markTrackedToolEnd, markToolStart as markTrackedToolStart, } from "./auto-tool-tracking.js";
4
4
  export const autoSession = new AutoSession();
5
5
  export function getAutoRuntimeSnapshot() {
6
+ const orchestrationStatus = autoSession.orchestration?.getStatus();
6
7
  return {
7
8
  active: autoSession.active,
8
9
  paused: autoSession.paused,
9
10
  currentUnit: autoSession.currentUnit ? { ...autoSession.currentUnit } : null,
10
11
  basePath: autoSession.basePath,
12
+ orchestrationPhase: orchestrationStatus?.phase,
13
+ orchestrationTransitionCount: orchestrationStatus?.transitionCount,
14
+ orchestrationLastTransitionAt: orchestrationStatus?.lastTransitionAt,
11
15
  };
12
16
  }
13
17
  export function isAutoActive() {
@@ -486,8 +486,9 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
486
486
  // Clear survivor flag — finalization is done
487
487
  hasSurvivorBranch = false;
488
488
  }
489
+ const effectivePrefs = loadEffectiveGSDPreferences(base)?.preferences;
489
490
  const deepProjectStagePending = !hasSurvivorBranch
490
- ? (await import("./auto-dispatch.js")).hasPendingDeepStage(loadEffectiveGSDPreferences(base)?.preferences, base)
491
+ ? (await import("./auto-dispatch.js")).hasPendingDeepStage(effectivePrefs, base)
491
492
  : false;
492
493
  if (deepProjectStagePending) {
493
494
  // Deep project-level setup runs before the first milestone exists. Let
@@ -526,7 +527,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
526
527
  const mid = state.activeMilestone.id;
527
528
  const contextFile = resolveMilestoneFile(base, mid, "CONTEXT");
528
529
  const hasContext = !!(contextFile && (await loadFile(contextFile)));
529
- if (!hasContext) {
530
+ if (!hasContext && effectivePrefs?.planning_depth !== "deep") {
530
531
  const { showSmartEntry } = await import("./guided-flow.js");
531
532
  await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
532
533
  // showSmartEntry dispatches via pi.sendMessage() which is fire-and-forget: