gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.42bd34838

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 (241) hide show
  1. package/README.md +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +29 -15
  5. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +13 -1
  7. package/dist/resources/extensions/gsd/auto-prompts.js +13 -1
  8. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  9. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  10. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  11. package/dist/resources/extensions/gsd/auto.js +68 -4
  12. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +21 -2
  13. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
  14. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
  15. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  16. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  17. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  18. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  19. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  20. package/dist/resources/extensions/gsd/git-service.js +36 -4
  21. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  22. package/dist/resources/extensions/gsd/guided-flow.js +52 -10
  23. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  24. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  25. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  26. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  27. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  28. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +14 -13
  29. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  30. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  32. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  33. package/dist/resources/extensions/gsd/quick.js +34 -2
  34. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  35. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  36. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  37. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  38. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  39. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  40. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  41. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  42. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  43. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  44. package/dist/resources/extensions/gsd/worktree-resolver.js +33 -17
  45. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  46. package/dist/web/standalone/.next/BUILD_ID +1 -1
  47. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  48. package/dist/web/standalone/.next/build-manifest.json +2 -2
  49. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  50. package/dist/web/standalone/.next/required-server-files.json +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  60. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/index.html +1 -1
  68. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  75. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  77. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  78. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  79. package/dist/web/standalone/server.js +1 -1
  80. package/package.json +3 -3
  81. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  82. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  83. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  84. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  85. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  86. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  87. package/packages/native/tsconfig.tsbuildinfo +1 -1
  88. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  89. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
  92. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  94. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  96. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  98. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  100. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  102. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  104. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  105. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  106. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  107. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  108. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  109. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  110. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  111. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
  112. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
  114. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  115. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
  116. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  118. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  120. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  121. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  122. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  123. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  128. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  129. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  130. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  131. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  132. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  135. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  136. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  137. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  138. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  139. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  140. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  142. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  143. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  144. package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
  145. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  146. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  147. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  148. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  149. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  150. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
  151. package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
  152. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  153. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  154. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  155. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  156. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  157. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  158. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  159. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  160. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  161. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  162. package/packages/pi-tui/dist/tui.js +18 -8
  163. package/packages/pi-tui/dist/tui.js.map +1 -1
  164. package/packages/pi-tui/src/tui.ts +20 -8
  165. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  166. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  167. package/src/resources/extensions/gsd/auto/phases.ts +35 -20
  168. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  169. package/src/resources/extensions/gsd/auto/run-unit.ts +18 -1
  170. package/src/resources/extensions/gsd/auto-prompts.ts +17 -1
  171. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  172. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  173. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  174. package/src/resources/extensions/gsd/auto.ts +80 -3
  175. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -1
  176. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
  177. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  178. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  179. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  180. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  181. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  182. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  183. package/src/resources/extensions/gsd/git-service.ts +46 -8
  184. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  185. package/src/resources/extensions/gsd/guided-flow.ts +71 -10
  186. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  187. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  188. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  189. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  190. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  191. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  192. package/src/resources/extensions/gsd/prompts/complete-milestone.md +14 -13
  193. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  194. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  195. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  196. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  197. package/src/resources/extensions/gsd/quick.ts +37 -2
  198. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +71 -0
  199. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  200. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  201. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  202. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  203. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  204. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  205. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  206. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  207. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  208. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
  209. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
  210. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  211. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  212. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  213. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  214. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  215. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  216. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  217. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  218. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  219. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  220. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  221. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  222. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  223. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  224. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  225. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  226. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  227. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  228. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +63 -1
  229. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  230. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  231. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  232. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  233. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  234. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  235. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  236. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  237. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  238. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  239. package/src/resources/extensions/gsd/worktree-resolver.ts +36 -15
  240. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → tht0ltP8EIjsohPOA_WZf}/_buildManifest.js +0 -0
  241. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → tht0ltP8EIjsohPOA_WZf}/_ssgManifest.js +0 -0
@@ -16,7 +16,7 @@ import { invalidateAllCaches } from "./cache.js";
16
16
  import { startAutoDetached } from "./auto.js";
17
17
  import { clearLock } from "./crash-recovery.js";
18
18
  import { assessInterruptedSession, formatInterruptedSessionRunningMessage, formatInterruptedSessionSummary, } from "./interrupted-session.js";
19
- import { listUnitRuntimeRecords, clearUnitRuntimeRecord } from "./unit-runtime.js";
19
+ import { listUnitRuntimeRecords, clearUnitRuntimeRecord, isInFlightRuntimePhase } from "./unit-runtime.js";
20
20
  import { resolveExpectedArtifactPath } from "./auto.js";
21
21
  import { gsdHome } from "./gsd-home.js";
22
22
  import { gsdRoot, milestonesDir, resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, relSliceFile, clearPathCache, } from "./paths.js";
@@ -51,6 +51,21 @@ export { showQueue, handleQueueReorder, showQueueAdd, buildExistingMilestonesCon
51
51
  import { logWarning } from "./workflow-logger.js";
52
52
  import { deleteRuntimeKv } from "./db/runtime-kv.js";
53
53
  import { PAUSED_SESSION_KV_KEY } from "./interrupted-session.js";
54
+ function scheduleAutoStartAfterIdle(ctx, pi, basePath, verboseMode, options, launch = startAutoDetached) {
55
+ const waitForIdle = typeof ctx.waitForIdle === "function"
56
+ ? ctx.waitForIdle.bind(ctx)
57
+ : async () => { };
58
+ void waitForIdle()
59
+ .then(() => {
60
+ setTimeout(() => launch(ctx, pi, basePath, verboseMode, options), 0);
61
+ })
62
+ .catch((err) => {
63
+ const message = err instanceof Error ? err.message : String(err);
64
+ ctx.ui.notify(`Auto-start failed while waiting for the prior turn to settle: ${message}`, "error");
65
+ logWarning("guided", `auto-start idle wait failed: ${message}`);
66
+ });
67
+ }
68
+ export const _scheduleAutoStartAfterIdleForTest = scheduleAutoStartAfterIdle;
54
69
  // ─── Scope-based validator wrappers ──────────────────────────────────────────
55
70
  // These thin wrappers accept a MilestoneScope so callers that already hold a
56
71
  // pinned scope never have to re-derive (basePath, milestoneId) separately.
@@ -71,6 +86,19 @@ export function verifyExpectedArtifactForScope(scope, unitType, unitId) {
71
86
  export function resolveExpectedArtifactPathForScope(scope, unitType, unitId) {
72
87
  return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
73
88
  }
89
+ async function runQuickTaskChoice(ctx, pi) {
90
+ if (!ctx.hasUI) {
91
+ ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
92
+ return;
93
+ }
94
+ const task = (await ctx.ui.input("Quick task", "Describe the small task to run with /gsd quick"))?.trim();
95
+ if (!task) {
96
+ ctx.ui.notify("Quick task cancelled.", "info");
97
+ return;
98
+ }
99
+ const { handleQuick } = await import("./quick.js");
100
+ await handleQuick(task, ctx, pi);
101
+ }
74
102
  /**
75
103
  * Scope-based overload of isGhostMilestone.
76
104
  * Binds basePath and milestoneId from the scope, ensuring path resolution
@@ -312,7 +340,7 @@ async function dispatchNextDeepProjectSetupStage(entry) {
312
340
  const { DISPATCH_RULES, hasPendingDeepStage } = await import("./auto-dispatch.js");
313
341
  if (!hasPendingDeepStage(prefs, entry.basePath)) {
314
342
  pendingDeepProjectSetupMap.delete(entry.basePath);
315
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
343
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
316
344
  return true;
317
345
  }
318
346
  const state = await deriveState(entry.basePath);
@@ -346,14 +374,14 @@ async function dispatchNextDeepProjectSetupStage(entry) {
346
374
  }
347
375
  else if (hasPendingDeepStage(prefs, entry.basePath)) {
348
376
  pendingDeepProjectSetupMap.delete(entry.basePath);
349
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
377
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
350
378
  return true;
351
379
  }
352
380
  return false;
353
381
  }
354
382
  if (!USER_DRIVEN_DEEP_SETUP_UNITS.has(result.unitType)) {
355
383
  pendingDeepProjectSetupMap.delete(entry.basePath);
356
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
384
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
357
385
  return true;
358
386
  }
359
387
  entry.currentUnitType = result.unitType;
@@ -531,7 +559,7 @@ export function checkAutoStartAfterDiscuss() {
531
559
  }
532
560
  pendingAutoStartMap.delete(basePath);
533
561
  ctx.ui.notify(`Milestone ${milestoneId} ready.`, "success");
534
- startAutoDetached(ctx, pi, basePath, false, { step });
562
+ scheduleAutoStartAfterIdle(ctx, pi, basePath, false, { step });
535
563
  return true;
536
564
  }
537
565
  /**
@@ -1469,8 +1497,8 @@ function selfHealRuntimeRecords(basePath, ctx) {
1469
1497
  cleared++;
1470
1498
  continue;
1471
1499
  }
1472
- // Clear records stuck in dispatched or timeout phase (process died mid-unit)
1473
- if (phase === "dispatched" || phase === "timeout") {
1500
+ // Clear records stuck in an in-flight phase (process died mid-unit).
1501
+ if (isInFlightRuntimePhase(phase)) {
1474
1502
  clearUnitRuntimeRecord(basePath, unitType, unitId);
1475
1503
  cleared++;
1476
1504
  }
@@ -1695,6 +1723,20 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1695
1723
  return;
1696
1724
  }
1697
1725
  }
1726
+ if (interrupted.classification !== "recoverable") {
1727
+ try {
1728
+ const { autoImportMarkdownHierarchyIfDbMismatch } = await import("./migration-auto-check.js");
1729
+ const result = await autoImportMarkdownHierarchyIfDbMismatch(basePath);
1730
+ if (result.action === "imported") {
1731
+ ctx.ui.notify(`Recovered migrated planning state into gsd.db (${result.reason}): ${result.afterDb.milestones} milestone(s), ${result.afterDb.slices} slice(s), ${result.afterDb.tasks} task(s).`, "info");
1732
+ }
1733
+ }
1734
+ catch (err) {
1735
+ const message = err instanceof Error ? err.message : String(err);
1736
+ ctx.ui.notify(`GSD could not auto-import existing planning state into gsd.db: ${message}`, "warning");
1737
+ logWarning("guided", `planning state auto-import failed: ${message}`, { file: "guided-flow.ts" });
1738
+ }
1739
+ }
1698
1740
  // Always derive from the project root — the assessment may have derived
1699
1741
  // state from a worktree path that was cleaned up in the stale branch above.
1700
1742
  const state = await deriveState(basePath);
@@ -1795,7 +1837,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1795
1837
  notYetMessage: "Run /gsd when ready.",
1796
1838
  });
1797
1839
  if (choice === "quick_task") {
1798
- ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
1840
+ await runQuickTaskChoice(ctx, pi);
1799
1841
  }
1800
1842
  else if (choice === "new_milestone") {
1801
1843
  setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
@@ -1837,7 +1879,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1837
1879
  notYetMessage: "Run /gsd when ready.",
1838
1880
  });
1839
1881
  if (choice === "quick_task") {
1840
- ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
1882
+ await runQuickTaskChoice(ctx, pi);
1841
1883
  }
1842
1884
  else if (choice === "new_milestone") {
1843
1885
  const milestoneIds = findMilestoneIds(basePath);
@@ -1968,7 +2010,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1968
2010
  notYetMessage: "Run /gsd when ready.",
1969
2011
  });
1970
2012
  if (choice === "quick_task") {
1971
- ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
2013
+ await runQuickTaskChoice(ctx, pi);
1972
2014
  }
1973
2015
  else if (choice === "plan") {
1974
2016
  setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId, step: stepMode });
@@ -14,6 +14,27 @@ const CATEGORY_PRIORITY = {
14
14
  environment: 4,
15
15
  preference: 5,
16
16
  };
17
+ // ─── Scoring Helpers ─────────────────────────────────────────────────────────
18
+ /**
19
+ * Time-decay factor for memory relevance scoring.
20
+ * Returns 1.0 for never-hit or recently-hit memories, decaying linearly to
21
+ * 0.7 for memories not accessed in 90+ days. Floor at 0.7 keeps old-but-valid
22
+ * knowledge from being fully suppressed.
23
+ *
24
+ * Defensive parsing: invalid timestamp strings (NaN from Date.parse) are
25
+ * treated as "no decay" rather than propagating NaN into score arithmetic.
26
+ * Future timestamps (clock skew, manual DB edits) clamp to daysAgo=0 so the
27
+ * factor stays in the documented [0.7, 1.0] contract.
28
+ */
29
+ export function memoryDecayFactor(lastHitAt) {
30
+ if (!lastHitAt)
31
+ return 1.0;
32
+ const ts = Date.parse(lastHitAt);
33
+ if (!Number.isFinite(ts))
34
+ return 1.0;
35
+ const daysAgo = Math.max(0, (Date.now() - ts) / 86_400_000);
36
+ return Math.max(0.7, 1.0 - 0.3 * Math.min(1.0, daysAgo / 90));
37
+ }
17
38
  // ─── Row Mapping ────────────────────────────────────────────────────────────
18
39
  function rowToMemory(row) {
19
40
  return {
@@ -31,6 +52,7 @@ function rowToMemory(row) {
31
52
  scope: row['scope'] ?? 'project',
32
53
  tags: parseTags(row['tags']),
33
54
  structured_fields: parseStructuredFields(row['structured_fields']),
55
+ last_hit_at: row['last_hit_at'] ?? null,
34
56
  };
35
57
  }
36
58
  function parseStructuredFields(raw) {
@@ -114,15 +136,37 @@ export function queryMemoriesRanked(opts) {
114
136
  ? semanticSearch(adapter, opts.queryVector, activeClause, 50)
115
137
  : [];
116
138
  if (keywordHits.length === 0 && semanticHits.length === 0 && !trimmedQuery) {
117
- // No query at all — fall back to the existing ranked-by-score listing.
118
- return getActiveMemoriesRanked(k).map((memory) => ({
119
- memory,
120
- score: memory.confidence * (1 + memory.hit_count * 0.1),
121
- keywordRank: null,
122
- semanticRank: null,
123
- confidenceBoost: memory.confidence * (1 + memory.hit_count * 0.1),
124
- reason: 'ranked',
125
- })).filter((hit) => passesFilters(hit.memory, opts));
139
+ // No query at all — return top-k by decay-aware ranked score.
140
+ //
141
+ // Build the candidate pool from a direct SQL query that honors the
142
+ // request's activeClause (i.e. include_superseded). Using
143
+ // getActiveMemoriesRanked here would silently drop superseded rows even
144
+ // when the caller explicitly opted in, and would slice by raw score
145
+ // before decay/filters had a chance to reorder.
146
+ const candidatePool = Math.min(Math.max(k * 5, 50), 500);
147
+ const rows = adapter
148
+ .prepare(`SELECT * FROM memories ${activeClause}
149
+ ORDER BY (confidence * (1.0 + hit_count * 0.1)) DESC
150
+ LIMIT :limit`)
151
+ .all({ ':limit': candidatePool });
152
+ const ranked = [];
153
+ for (const row of rows) {
154
+ const memory = rowToMemory(row);
155
+ if (!passesFilters(memory, opts))
156
+ continue;
157
+ const decay = memoryDecayFactor(memory.last_hit_at);
158
+ const score = memory.confidence * (1 + memory.hit_count * 0.1) * decay;
159
+ ranked.push({
160
+ memory,
161
+ score,
162
+ keywordRank: null,
163
+ semanticRank: null,
164
+ confidenceBoost: score,
165
+ reason: 'ranked',
166
+ });
167
+ }
168
+ ranked.sort((a, b) => b.score - a.score);
169
+ return ranked.slice(0, k);
126
170
  }
127
171
  // 3) Reciprocal rank fusion — each hit contributes 1/(rrfK + rank).
128
172
  const fused = new Map();
@@ -155,7 +199,7 @@ export function queryMemoriesRanked(opts) {
155
199
  for (const entry of fused.values()) {
156
200
  if (!passesFilters(entry.memory, opts))
157
201
  continue;
158
- const boost = entry.memory.confidence * (1 + entry.memory.hit_count * 0.1);
202
+ const boost = entry.memory.confidence * (1 + entry.memory.hit_count * 0.1) * memoryDecayFactor(entry.memory.last_hit_at);
159
203
  const reason = entry.kwRank != null && entry.semRank != null
160
204
  ? 'both'
161
205
  : entry.kwRank != null
@@ -194,6 +238,7 @@ function passesFilters(memory, filters) {
194
238
  }
195
239
  return true;
196
240
  }
241
+ let ftsWarningEmitted = false;
197
242
  function keywordSearch(adapter, rawQuery, activeClause, limit) {
198
243
  const ftsAvailable = isFtsAvailable(adapter);
199
244
  if (ftsAvailable) {
@@ -215,14 +260,26 @@ function keywordSearch(adapter, rawQuery, activeClause, limit) {
215
260
  // fall through to LIKE
216
261
  }
217
262
  }
218
- // LIKE fallback — scans the candidate pool.
263
+ // LIKE fallback — scans a capped candidate pool.
264
+ if (!ftsWarningEmitted) {
265
+ ftsWarningEmitted = true;
266
+ logWarning('memory-store', 'FTS5 unavailable — using LIKE fallback scan (consider enabling FTS5)');
267
+ }
219
268
  const terms = rawQuery
220
269
  .toLowerCase()
221
270
  .split(/[^a-z0-9_]+/)
222
271
  .filter((t) => t.length >= 2);
223
272
  if (terms.length === 0)
224
273
  return [];
225
- const rows = adapter.prepare(`SELECT * FROM memories ${activeClause}`).all();
274
+ const preScanCap = Math.min(limit * 20, 2000);
275
+ // ORDER BY confidence-weighted hit_count DESC so the cap keeps the most
276
+ // valuable candidates instead of the oldest-by-rowid (which would silently
277
+ // exclude recently-stored memories on tables larger than preScanCap).
278
+ const rows = adapter
279
+ .prepare(`SELECT * FROM memories ${activeClause}
280
+ ORDER BY (confidence * (1.0 + hit_count * 0.1)) DESC
281
+ LIMIT :preScanCap`)
282
+ .all({ ':preScanCap': preScanCap });
226
283
  const scored = [];
227
284
  for (const row of rows) {
228
285
  const memory = rowToMemory(row);
@@ -15,6 +15,43 @@ import { fileURLToPath } from "node:url";
15
15
  import { showNextAction } from "../../shared/tui.js";
16
16
  import { validatePlanningDirectory, parsePlanningDirectory, transformToGSD, generatePreview, writeGSDDirectory, } from "./index.js";
17
17
  import { homedir } from "node:os";
18
+ import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
19
+ import { clearEngineHierarchy, transaction } from "../gsd-db.js";
20
+ import { migrateFromMarkdown } from "../md-importer.js";
21
+ import { invalidateStateCache } from "../state.js";
22
+ function assertMigrationImportMatchesPreview(imported, preview) {
23
+ const mismatches = [];
24
+ if (imported.hierarchy.milestones !== preview.milestoneCount) {
25
+ mismatches.push(`milestones ${imported.hierarchy.milestones}/${preview.milestoneCount}`);
26
+ }
27
+ if (imported.hierarchy.slices !== preview.totalSlices) {
28
+ mismatches.push(`slices ${imported.hierarchy.slices}/${preview.totalSlices}`);
29
+ }
30
+ if (imported.hierarchy.tasks !== preview.totalTasks) {
31
+ mismatches.push(`tasks ${imported.hierarchy.tasks}/${preview.totalTasks}`);
32
+ }
33
+ if (imported.requirements !== preview.requirements.total) {
34
+ mismatches.push(`requirements ${imported.requirements}/${preview.requirements.total}`);
35
+ }
36
+ if (mismatches.length > 0) {
37
+ throw new Error(`migration DB import verification failed: ${mismatches.join(", ")}`);
38
+ }
39
+ }
40
+ export async function importWrittenMigrationToDb(basePath, preview) {
41
+ const opened = await ensureDbOpen(basePath);
42
+ if (!opened) {
43
+ throw new Error(`failed to open or create the GSD database at ${basePath}`);
44
+ }
45
+ const counts = transaction(() => {
46
+ clearEngineHierarchy();
47
+ const imported = migrateFromMarkdown(basePath);
48
+ if (preview)
49
+ assertMigrationImportMatchesPreview(imported, preview);
50
+ return imported;
51
+ });
52
+ invalidateStateCache();
53
+ return counts;
54
+ }
18
55
  /** Format preview stats for embedding in the review prompt. */
19
56
  function formatPreviewStats(preview) {
20
57
  const lines = [
@@ -126,12 +163,14 @@ export async function handleMigrate(args, ctx, pi) {
126
163
  ctx.ui.notify("Writing .gsd directory…", "info");
127
164
  const result = await writeGSDDirectory(project, process.cwd());
128
165
  const gsdPath = gsdRoot(process.cwd());
129
- ctx.ui.notify(`✓ Migration complete ${result.paths.length} file(s) written to .gsd/`, "info");
166
+ const imported = await importWrittenMigrationToDb(process.cwd(), preview);
167
+ ctx.ui.notify(`✓ Migration complete — ${result.paths.length} file(s) written to .gsd/ and ${imported.hierarchy.milestones}M/${imported.hierarchy.slices}S/${imported.hierarchy.tasks}T imported to the database`, "info");
130
168
  // ── Post-write review offer ────────────────────────────────────────────────
131
169
  const reviewChoice = await showNextAction(ctx, {
132
170
  title: "Migration written",
133
171
  summary: [
134
172
  `${result.paths.length} files written to .gsd/`,
173
+ `${imported.hierarchy.milestones} milestone(s), ${imported.hierarchy.slices} slice(s), and ${imported.hierarchy.tasks} task(s) imported to gsd.db`,
135
174
  "",
136
175
  "The agent can now review the migrated output against GSD-2 standards —",
137
176
  "checking structure, content quality, deriveState() round-trip, and",
@@ -0,0 +1,87 @@
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
3
+ import { clearEngineHierarchy, getAllMilestones, getMilestoneSlices, getSliceTasks, isDbAvailable, transaction, } from "./gsd-db.js";
4
+ import { migrateHierarchyToDb } from "./md-importer.js";
5
+ import { parsePlan, parseRoadmap } from "./parsers-legacy.js";
6
+ import { milestonesDir, resolveMilestoneFile, resolveSliceFile, } from "./paths.js";
7
+ import { invalidateStateCache } from "./state.js";
8
+ function zeroCounts() {
9
+ return { milestones: 0, slices: 0, tasks: 0 };
10
+ }
11
+ function sameCounts(a, b) {
12
+ return a.milestones === b.milestones && a.slices === b.slices && a.tasks === b.tasks;
13
+ }
14
+ export function countMarkdownHierarchy(basePath) {
15
+ const root = milestonesDir(basePath);
16
+ if (!existsSync(root))
17
+ return zeroCounts();
18
+ const counts = zeroCounts();
19
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
20
+ if (!entry.isDirectory() || !/^M\d+/.test(entry.name))
21
+ continue;
22
+ counts.milestones++;
23
+ const roadmapPath = resolveMilestoneFile(basePath, entry.name, "ROADMAP");
24
+ if (!roadmapPath || !existsSync(roadmapPath))
25
+ continue;
26
+ const roadmap = parseRoadmap(readFileSync(roadmapPath, "utf-8"));
27
+ counts.slices += roadmap.slices.length;
28
+ for (const slice of roadmap.slices) {
29
+ const planPath = resolveSliceFile(basePath, entry.name, slice.id, "PLAN");
30
+ if (!planPath || !existsSync(planPath))
31
+ continue;
32
+ const plan = parsePlan(readFileSync(planPath, "utf-8"));
33
+ counts.tasks += plan.tasks.length;
34
+ }
35
+ }
36
+ return counts;
37
+ }
38
+ export function countDbHierarchy() {
39
+ if (!isDbAvailable())
40
+ return zeroCounts();
41
+ const counts = zeroCounts();
42
+ const milestones = getAllMilestones();
43
+ counts.milestones = milestones.length;
44
+ for (const milestone of milestones) {
45
+ const slices = getMilestoneSlices(milestone.id);
46
+ counts.slices += slices.length;
47
+ for (const slice of slices) {
48
+ counts.tasks += getSliceTasks(milestone.id, slice.id).length;
49
+ }
50
+ }
51
+ return counts;
52
+ }
53
+ export async function autoImportMarkdownHierarchyIfDbMismatch(basePath) {
54
+ const markdown = countMarkdownHierarchy(basePath);
55
+ if (sameCounts(markdown, zeroCounts())) {
56
+ return {
57
+ action: "none",
58
+ reason: "no-markdown",
59
+ markdown,
60
+ beforeDb: zeroCounts(),
61
+ afterDb: zeroCounts(),
62
+ };
63
+ }
64
+ const opened = await ensureDbOpen(basePath);
65
+ if (!opened || !isDbAvailable()) {
66
+ throw new Error(`failed to open or create the GSD database at ${basePath}`);
67
+ }
68
+ const beforeDb = countDbHierarchy();
69
+ if (sameCounts(markdown, beforeDb)) {
70
+ return { action: "none", reason: "in-sync", markdown, beforeDb, afterDb: beforeDb };
71
+ }
72
+ const reason = sameCounts(beforeDb, zeroCounts()) ? "db-empty" : "count-mismatch";
73
+ const imported = transaction(() => {
74
+ clearEngineHierarchy();
75
+ return migrateHierarchyToDb(basePath);
76
+ });
77
+ invalidateStateCache();
78
+ const afterDb = {
79
+ milestones: imported.milestones,
80
+ slices: imported.slices,
81
+ tasks: imported.tasks,
82
+ };
83
+ if (!sameCounts(markdown, afterDb)) {
84
+ throw new Error(`migration auto-import verification failed: markdown ${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T, db ${afterDb.milestones}M/${afterDb.slices}S/${afterDb.tasks}T`);
85
+ }
86
+ return { action: "imported", reason, markdown, beforeDb, afterDb };
87
+ }
@@ -0,0 +1,26 @@
1
+ import { isAbsolute, relative, resolve } from "node:path";
2
+ import { normalizePlannedFileReference } from "./files.js";
3
+ function isInsideBase(basePath, candidate) {
4
+ const base = resolve(basePath);
5
+ const abs = resolve(candidate);
6
+ const rel = relative(base, abs);
7
+ return rel === "" || (!!rel && !rel.startsWith("..") && !isAbsolute(rel));
8
+ }
9
+ /**
10
+ * Planning IO fields are execution contracts. Absolute paths are only safe when
11
+ * they stay inside the active working directory; in worktree mode, an absolute
12
+ * path to the original checkout makes executors edit the wrong tree.
13
+ */
14
+ export function validatePlanningPathScope(basePath, fields) {
15
+ for (const { field, values } of fields) {
16
+ for (const raw of values) {
17
+ const candidate = normalizePlannedFileReference(raw);
18
+ if (!isAbsolute(candidate))
19
+ continue;
20
+ if (isInsideBase(basePath, candidate))
21
+ continue;
22
+ return `${field} contains absolute path outside working directory: ${candidate}. Use a path relative to ${basePath}.`;
23
+ }
24
+ }
25
+ return null;
26
+ }
@@ -111,15 +111,41 @@ function warmCache() {
111
111
  }
112
112
  }
113
113
  let warmCacheScheduled = false;
114
+ let warmCacheRan = false;
115
+ let warmCacheTimer;
116
+ /**
117
+ * Synchronously snapshot the prompt/template tree into the cache.
118
+ *
119
+ * Safe to call immediately after `initResources()` because that function uses
120
+ * synchronous fs APIs — there is no race window that requires deferring the
121
+ * cache warm via setTimeout. Idempotent: subsequent calls are no-ops.
122
+ *
123
+ * Cancels the fallback `scheduleWarmCache` timer if it is still pending.
124
+ */
125
+ export function primeCache() {
126
+ if (warmCacheRan)
127
+ return;
128
+ if (warmCacheTimer) {
129
+ clearTimeout(warmCacheTimer);
130
+ warmCacheTimer = undefined;
131
+ }
132
+ warmCacheScheduled = true;
133
+ warmCacheRan = true;
134
+ warmCache();
135
+ }
114
136
  function scheduleWarmCache() {
115
137
  if (warmCacheScheduled)
116
138
  return;
117
139
  warmCacheScheduled = true;
118
140
  const run = () => {
141
+ warmCacheTimer = undefined;
142
+ if (warmCacheRan)
143
+ return;
144
+ warmCacheRan = true;
119
145
  warmCache();
120
146
  };
121
- const timer = setTimeout(run, 1000);
122
- timer.unref?.();
147
+ warmCacheTimer = setTimeout(run, 1000);
148
+ warmCacheTimer.unref?.();
123
149
  }
124
150
  // Snapshot the full prompt/template tree after import so extension startup only
125
151
  // pays for prompts that are actually needed immediately.
@@ -29,14 +29,15 @@ Subagents report only; they do not write user source. Fold any findings into Dec
29
29
 
30
30
  ## Steps
31
31
 
32
- 1. Use the **Milestone Summary** output template from the inlined context above
33
- 2. {{skillActivation}}
34
- 3. **Verify code changes exist.** Compare milestone work against the integration branch (`main`, `master`, or recorded branch), using merge-base as older revision and `HEAD` as newer. If the diff lists non-`.gsd/` files, pass. If `HEAD` equals the integration branch/merge-base, treat it as a self-diff retry: inspect milestone-scoped commit evidence (`GSD-Unit: {{milestoneId}}` or production `GSD-Task: Sxx/Tyy` trailers touching `.gsd/milestones/{{milestoneId}}/`) and verify those commits touched non-`.gsd/` files. Record **verification failure** only when neither source shows implementation files.
35
- 4. Verify every **success criterion** from `{{roadmapPath}}`. If passing validation is present, summarize the validation evidence instead of re-auditing it; otherwise verify with evidence from summaries, tests, or observable behavior. Record unmet criteria as **verification failure**.
36
- 5. Verify **definition of done**: all slices `[x]`, summaries exist, and integrations work. If passing validation is present, trust its integration/verification verdict unless inconsistent with current artifacts. Record unmet items as **verification failure**.
37
- 6. If the roadmap includes a **Horizontal Checklist**, verify each item and note unchecked items in the summary.
38
- 7. Fill the **Decision Re-evaluation** table: compare each key `.gsd/DECISIONS.md` decision from this milestone with what shipped, and flag decisions to revisit.
39
- 8. Validate **requirement status transitions**. For each changed requirement, confirm evidence supports the new status. Requirements may move between Active, Validated, Deferred, Blocked, or Out of Scope only with proof.
32
+ 1. **Duplicate completion guard:** Call `gsd_milestone_status` for `{{milestoneId}}` before any durable writes. If the returned milestone **status is `complete`**, this is a stale or duplicate closeout turn: do NOT mutate requirements, do NOT refresh the project document, do NOT write LEARNINGS, and do NOT persist milestone completion again. Say: "Milestone {{milestoneId}} is already complete." and stop.
33
+ 2. Use the **Milestone Summary** output template from the inlined context above
34
+ 3. {{skillActivation}}
35
+ 4. **Verify code changes exist.** Compare milestone work against the integration branch (`main`, `master`, or recorded branch), using merge-base as older revision and `HEAD` as newer. If the diff lists non-`.gsd/` files, pass. If `HEAD` equals the integration branch/merge-base, treat it as a self-diff retry: inspect milestone-scoped commit evidence (`GSD-Unit: {{milestoneId}}` or production `GSD-Task: Sxx/Tyy` trailers touching `.gsd/milestones/{{milestoneId}}/`) and verify those commits touched non-`.gsd/` files. Record **verification failure** only when neither source shows implementation files.
36
+ 5. Verify every **success criterion** from `{{roadmapPath}}`. If passing validation is present, summarize the validation evidence instead of re-auditing it; otherwise verify with evidence from summaries, tests, or observable behavior. Record unmet criteria as **verification failure**.
37
+ 6. Verify **definition of done**: all slices `[x]`, summaries exist, and integrations work. If passing validation is present, trust its integration/verification verdict unless inconsistent with current artifacts. Record unmet items as **verification failure**.
38
+ 7. If the roadmap includes a **Horizontal Checklist**, verify each item and note unchecked items in the summary.
39
+ 8. Fill the **Decision Re-evaluation** table: compare each key `.gsd/DECISIONS.md` decision from this milestone with what shipped, and flag decisions to revisit.
40
+ 9. Validate **requirement status transitions**. For each changed requirement, confirm evidence supports the new status. Requirements may move between Active, Validated, Deferred, Blocked, or Out of Scope only with proof.
40
41
 
41
42
  **DB access safety:** Do NOT query `.gsd/gsd.db` directly via `sqlite3` or `node -e require('better-sqlite3')`; the engine owns the WAL connection. Use `gsd_milestone_status`, inlined context, or `gsd_*` tools; never direct SQL.
42
43
 
@@ -53,13 +54,13 @@ Subagents report only; they do not write user source. Fold any findings into Dec
53
54
 
54
55
  **Success path** (all verifications passed):
55
56
 
56
- 9. For each requirement whose status changed in step 8, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically. Do this BEFORE completing the milestone so requirement updates are persisted.
57
- 10. Update `.gsd/PROJECT.md`: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting milestone completion and current project state. Do NOT use the `edit` tool for this — PROJECT.md is a full-document refresh.
58
- 11. Extract structured learnings from this milestone and persist them to the GSD memory store. Follow the procedure block immediately below — it writes `{{milestoneId}}-LEARNINGS.md` as the audit trail and persists Patterns, Lessons, and Decisions via `capture_thought` (categories: pattern, gotcha/convention, architecture). The memory store is the single source of truth for cross-session durable knowledge (ADR-013).
57
+ 10. For each requirement whose status changed in step 9, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically. Do this BEFORE completing the milestone so requirement updates are persisted.
58
+ 11. Update `.gsd/PROJECT.md`: use the `write` tool with `path: ".gsd/PROJECT.md"` and `content` containing the full updated document reflecting milestone completion and current project state. Do NOT use the `edit` tool for this — PROJECT.md is a full-document refresh.
59
+ 12. Extract structured learnings from this milestone and persist them to the GSD memory store. Follow the procedure block immediately below — it writes `{{milestoneId}}-LEARNINGS.md` as the audit trail and persists Patterns, Lessons, and Decisions via `capture_thought` (categories: pattern, gotcha/convention, architecture). The memory store is the single source of truth for cross-session durable knowledge (ADR-013).
59
60
 
60
61
  {{extractLearningsSteps}}
61
62
 
62
- 12. **Persist completion through `gsd_complete_milestone`.** Call it with the parameters below. This must be the final persistent write in the unit. The tool updates the milestone status in the DB, renders `{{milestoneSummaryPath}}`, and validates all slices are complete.
63
+ 13. **Persist completion through `gsd_complete_milestone`.** Call it with the parameters below. This must be the final persistent write in the unit. The tool updates the milestone status in the DB, renders `{{milestoneSummaryPath}}`, and validates all slices are complete.
63
64
 
64
65
  **Required parameters:**
65
66
  - `milestoneId` (string) — Milestone ID (e.g. M001)
@@ -78,7 +79,7 @@ Subagents report only; they do not write user source. Fold any findings into Dec
78
79
  - `followUps` (string) — Follow-up items for future milestones
79
80
  - `deviations` (string) — Deviations from the original plan
80
81
 
81
- 13. Do not commit manually — the system auto-commits your changes after this unit completes.
82
+ 14. Do not commit manually — the system auto-commits your changes after this unit completes.
82
83
  - Say: "Milestone {{milestoneId}} complete."
83
84
 
84
85
  **Important:** Do NOT skip code-change, success-criteria, or definition-of-done verification (steps 3-5). The summary must reflect verified outcomes. Verification failures block completion; there is no override. If a verification tool fails, errors, or returns unexpected output, treat it as failure.
@@ -16,7 +16,7 @@ Dispatch ALL slices simultaneously using the `subagent` tool in **parallel mode*
16
16
 
17
17
  1. Call `subagent` with `tasks: [...]` containing one entry per slice below
18
18
  2. Wait for ALL subagents to complete
19
- 3. Verify each slice's RESEARCH file was written (check the `.gsd/{{mid}}/` directory)
19
+ 3. Verify each slice's RESEARCH file was written (check `.gsd/milestones/{{mid}}/slices/<slice-id>/`)
20
20
  4. If a subagent failed to write its RESEARCH file, retry it **once** individually
21
21
  5. If it fails a second time, write a partial RESEARCH file for that slice with a `## BLOCKER` section explaining the failure — do NOT retry again
22
22
  6. Report which slices completed research and which (if any) needed a blocker note
@@ -39,7 +39,7 @@ If slice research is inlined, trust it. Explore enough code to confirm paths, bo
39
39
  5. Define slice verification before tasks. Non-trivial slices need real tests or executable assertions; boundary contracts need contract-exercising checks. Tests must not read .gitignore/gitignored paths such as `.gsd/`, `.planning/`, or `.audits/`.
40
40
  6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
41
41
  7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
42
- 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path.
42
+ 8. Each task needs a concrete title, Why / Files / Do / Verify / Done when, plus task-plan description, steps, must-haves, verification, inputs, and expected output. Inputs and Expected Output must include concrete backtick-wrapped paths; each task needs at least one output path. Use paths relative to `{{workingDirectory}}`; do not put absolute paths to the original checkout or any directory outside `{{workingDirectory}}` in `files`, `inputs`, `expectedOutput`, or verification commands.
43
43
  9. Persist with `gsd_plan_slice` using goal, successCriteria, optional proofLevel/integrationClosure/observabilityImpact, and tasks. `gsd_plan_slice` handles task persistence transactionally and renders `{{outputPath}}` plus task plans; do not call `gsd_plan_task`. The DB-backed tool is the canonical write path. Do **not** rely on direct `PLAN.md` writes as the source of truth.
44
44
  10. Self-audit before finishing: goal/demo closure, requirement coverage, locked decisions, concrete paths, dependency order, wiring, scope size, proof truthfulness, feature completeness, and quality gates. Quality gates: non-trivial slices/tasks include specific Q3-Q7 coverage where applicable.
45
45
  11. If planning creates structural decisions, append them to `.gsd/DECISIONS.md`.
@@ -17,11 +17,7 @@ You are executing a GSD quick task — a lightweight, focused unit of work outsi
17
17
  5. Verify your work:
18
18
  - Run tests if applicable.
19
19
  - Verify both happy path and failure modes for non-trivial changes.
20
- 6. Commit your changes atomically:
21
- - Use conventional commit messages (feat:, fix:, refactor:, etc.)
22
- - Stage only relevant files — never commit secrets or runtime files.
23
- - Commit logical units separately if the task involves distinct changes.
24
- - Quick tasks run outside the auto-mode lifecycle — there is no system auto-commit, so commit directly here.
20
+ 6. {{commitInstruction}}
25
21
  7. Write a brief summary to `{{summaryPath}}`:
26
22
  - Quick tasks operate outside the milestone/slice/task DB structure, so `gsd_summary_save` (which requires a `milestone_id`) cannot be used here. Write the file directly.
27
23
 
@@ -27,13 +27,13 @@ Roadmap, slice summaries, assessments, requirements, decisions, and project cont
27
27
  Call `subagent` with `tasks: [...]` containing ALL THREE reviewers simultaneously:
28
28
 
29
29
  **Reviewer A - Requirements Coverage**
30
- Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Read `.gsd/{{milestoneId}}/REQUIREMENTS.md` or equivalent. For each requirement, check slice SUMMARY files in `.gsd/{{milestoneId}}/` and mark COVERED, PARTIAL, or MISSING. Output table: Requirement | Status | Evidence. End with one-line verdict: PASS if all covered, NEEDS-ATTENTION if partials exist, FAIL if any missing."
30
+ Prompt: "Review milestone {{milestoneId}} requirements coverage. Working directory: {{workingDirectory}}. Read `.gsd/REQUIREMENTS.md` or use the inlined requirements context. For each requirement, check slice SUMMARY files under `.gsd/milestones/{{milestoneId}}/slices/` and mark COVERED, PARTIAL, or MISSING. Output table: Requirement | Status | Evidence. End with one-line verdict: PASS if all covered, NEEDS-ATTENTION if partials exist, FAIL if any missing."
31
31
 
32
32
  **Reviewer B - Cross-Slice Integration**
33
33
  Prompt: "Review milestone {{milestoneId}} cross-slice integration. Working directory: {{workingDirectory}}. Read `{{roadmapPath}}` and find the boundary map (produces/consumes contracts). For each boundary, confirm producer SUMMARY produced the artifact and consumer SUMMARY consumed it. Output table: Boundary | Producer Summary | Consumer Summary | Status. End with one-line verdict: PASS if all boundaries honored, NEEDS-ATTENTION if any gaps."
34
34
 
35
35
  **Reviewer C - Assessment & Acceptance Criteria**
36
- Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Read `.gsd/{{milestoneId}}/CONTEXT.md` for criteria. Check slice ASSESSMENT files. Verify each criterion maps to a passing assessment or clear SUMMARY evidence. Then review inlined milestone verification classes. For each non-empty planned class, output table: Class | Planned Check | Evidence | Verdict. Use the exact class names `Contract`, `Integration`, `Operational`, and `UAT` whenever those classes are present. If no verification classes were planned, say that explicitly. Output sections `Acceptance Criteria` with checklist `[ ] Criterion | Evidence`, and `Verification Classes` with the table. End with one-line verdict: PASS if all criteria and classes are covered, NEEDS-ATTENTION if gaps exist."
36
+ Prompt: "Review milestone {{milestoneId}} assessment evidence and acceptance criteria. Working directory: {{workingDirectory}}. Read `.gsd/milestones/{{milestoneId}}/{{milestoneId}}-CONTEXT.md` for criteria. Check slice SUMMARY/UAT files under `.gsd/milestones/{{milestoneId}}/slices/`. Verify each criterion maps to passing evidence. Then review inlined milestone verification classes. For each non-empty planned class, output table: Class | Planned Check | Evidence | Verdict. Use the exact class names `Contract`, `Integration`, `Operational`, and `UAT` whenever those classes are present. If no verification classes were planned, say that explicitly. Output sections `Acceptance Criteria` with checklist `[ ] Criterion | Evidence`, and `Verification Classes` with the table. End with one-line verdict: PASS if all criteria and classes are covered, NEEDS-ATTENTION if gaps exist."
37
37
 
38
38
  ### Step 2 - Synthesize Findings
39
39