gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa

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 (377) 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 +178 -108
  5. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
  7. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  8. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
  11. package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
  12. package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-start.js +197 -6
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  16. package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
  17. package/dist/resources/extensions/gsd/auto.js +86 -26
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
  20. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
  21. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
  22. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
  23. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
  24. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
  26. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  27. package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
  28. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  29. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  30. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  31. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  32. package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
  33. package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
  34. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  35. package/dist/resources/extensions/gsd/git-service.js +36 -4
  36. package/dist/resources/extensions/gsd/gsd-db.js +46 -13
  37. package/dist/resources/extensions/gsd/guided-flow.js +99 -38
  38. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  39. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  40. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  41. package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
  42. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  43. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  44. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  45. package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
  46. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  47. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  48. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  49. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  50. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  52. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  53. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  54. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  55. package/dist/resources/extensions/gsd/quick.js +34 -2
  56. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  57. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  58. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  59. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  60. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  61. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  62. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  63. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  64. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  65. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  66. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  67. package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
  68. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  69. package/dist/web/standalone/.next/BUILD_ID +1 -1
  70. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  71. package/dist/web/standalone/.next/build-manifest.json +2 -2
  72. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  73. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.html +1 -1
  90. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  97. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  99. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  100. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  101. package/package.json +3 -3
  102. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  103. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  104. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  105. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  106. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  107. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  108. package/packages/native/tsconfig.tsbuildinfo +1 -1
  109. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  110. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  111. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  112. package/packages/pi-agent-core/dist/agent.d.ts +5 -0
  113. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  114. package/packages/pi-agent-core/dist/agent.js +2 -0
  115. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  116. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  117. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  118. package/packages/pi-agent-core/dist/index.js +2 -0
  119. package/packages/pi-agent-core/dist/index.js.map +1 -1
  120. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  121. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  122. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  123. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  124. package/packages/pi-agent-core/dist/types.d.ts +9 -0
  125. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  126. package/packages/pi-agent-core/dist/types.js.map +1 -1
  127. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  128. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  129. package/packages/pi-agent-core/src/agent.ts +8 -0
  130. package/packages/pi-agent-core/src/index.ts +2 -0
  131. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  132. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  133. package/packages/pi-agent-core/src/types.ts +14 -0
  134. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  135. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  136. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
  138. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
  140. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/agent-session.js +44 -7
  142. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  144. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  146. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  148. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  150. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  151. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  152. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  153. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  154. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  155. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  156. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  157. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  158. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  159. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  160. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  161. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  163. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  165. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
  167. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
  169. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +39 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  174. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  176. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  177. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  178. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  180. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
  182. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  184. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  186. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  188. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  190. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  192. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  199. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  201. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  204. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  206. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  207. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  208. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  209. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  210. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  211. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  212. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  213. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
  214. package/packages/pi-coding-agent/src/core/agent-session.ts +48 -7
  215. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  216. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  217. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  218. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  219. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  220. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  221. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
  222. package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
  223. package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
  224. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  225. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  226. package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
  227. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  228. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  229. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  230. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  231. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  232. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  233. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  234. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  235. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  236. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +18 -8
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/src/tui.ts +20 -8
  241. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  242. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
  243. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  244. package/src/resources/extensions/gsd/auto/phases.ts +251 -172
  245. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  246. package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
  247. package/src/resources/extensions/gsd/auto/session.ts +8 -0
  248. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  249. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
  250. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
  251. package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
  252. package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
  253. package/src/resources/extensions/gsd/auto-start.ts +230 -9
  254. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  255. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  256. package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
  257. package/src/resources/extensions/gsd/auto.ts +98 -21
  258. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
  259. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
  260. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
  261. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
  262. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
  263. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
  264. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
  265. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
  266. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  267. package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
  268. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  269. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  270. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  271. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  272. package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
  273. package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
  274. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  275. package/src/resources/extensions/gsd/git-service.ts +46 -8
  276. package/src/resources/extensions/gsd/gsd-db.ts +50 -13
  277. package/src/resources/extensions/gsd/guided-flow.ts +123 -45
  278. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  279. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  280. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  281. package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
  282. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  283. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  284. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  285. package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
  286. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  287. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  288. package/src/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
  289. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  290. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  291. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  292. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  294. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  295. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  296. package/src/resources/extensions/gsd/quick.ts +37 -2
  297. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
  298. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
  299. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  300. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
  301. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
  302. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
  303. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  304. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  305. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  306. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  307. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  308. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  309. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  310. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
  311. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  312. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  313. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
  315. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  316. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
  317. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
  318. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
  319. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -1
  320. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  321. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  322. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  323. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
  324. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  325. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  326. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
  327. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  328. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
  329. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
  330. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  331. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  332. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  333. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  334. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  335. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  336. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  337. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  338. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
  339. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  340. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
  341. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  342. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  343. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
  344. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  345. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  346. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  347. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
  348. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
  349. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  350. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  351. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  352. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
  353. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  354. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  355. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
  357. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  358. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  359. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
  360. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  361. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  362. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +167 -4
  363. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  364. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  365. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  366. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  367. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  368. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  369. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  370. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  371. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  372. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  373. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  374. package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
  375. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
  376. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
  377. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_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,23 @@ 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
+ import { buildWorkflowDispatchContent } from "./workflow-protocol.js";
55
+ import { isFullGsdToolSurfaceRequested, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "./bootstrap/register-hooks.js";
56
+ function scheduleAutoStartAfterIdle(ctx, pi, basePath, verboseMode, options, launch = startAutoDetached) {
57
+ const waitForIdle = typeof ctx.waitForIdle === "function"
58
+ ? ctx.waitForIdle.bind(ctx)
59
+ : async () => { };
60
+ void waitForIdle()
61
+ .then(() => {
62
+ setTimeout(() => launch(ctx, pi, basePath, verboseMode, options), 0);
63
+ })
64
+ .catch((err) => {
65
+ const message = err instanceof Error ? err.message : String(err);
66
+ ctx.ui.notify(`Auto-start failed while waiting for the prior turn to settle: ${message}`, "error");
67
+ logWarning("guided", `auto-start idle wait failed: ${message}`);
68
+ });
69
+ }
70
+ export const _scheduleAutoStartAfterIdleForTest = scheduleAutoStartAfterIdle;
54
71
  // ─── Scope-based validator wrappers ──────────────────────────────────────────
55
72
  // These thin wrappers accept a MilestoneScope so callers that already hold a
56
73
  // pinned scope never have to re-derive (basePath, milestoneId) separately.
@@ -71,6 +88,19 @@ export function verifyExpectedArtifactForScope(scope, unitType, unitId) {
71
88
  export function resolveExpectedArtifactPathForScope(scope, unitType, unitId) {
72
89
  return resolveExpectedArtifactPath(unitType, unitId, scope.workspace.projectRoot);
73
90
  }
91
+ async function runQuickTaskChoice(ctx, pi) {
92
+ if (!ctx.hasUI) {
93
+ ctx.ui.notify("Run /gsd quick <task> for small bounded work, or /gsd do <task> for natural-language routing.", "info");
94
+ return;
95
+ }
96
+ const task = (await ctx.ui.input("Quick task", "Describe the small task to run with /gsd quick"))?.trim();
97
+ if (!task) {
98
+ ctx.ui.notify("Quick task cancelled.", "info");
99
+ return;
100
+ }
101
+ const { handleQuick } = await import("./quick.js");
102
+ await handleQuick(task, ctx, pi);
103
+ }
74
104
  /**
75
105
  * Scope-based overload of isGhostMilestone.
76
106
  * Binds basePath and milestoneId from the scope, ensuring path resolution
@@ -312,7 +342,7 @@ async function dispatchNextDeepProjectSetupStage(entry) {
312
342
  const { DISPATCH_RULES, hasPendingDeepStage } = await import("./auto-dispatch.js");
313
343
  if (!hasPendingDeepStage(prefs, entry.basePath)) {
314
344
  pendingDeepProjectSetupMap.delete(entry.basePath);
315
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
345
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
316
346
  return true;
317
347
  }
318
348
  const state = await deriveState(entry.basePath);
@@ -346,14 +376,14 @@ async function dispatchNextDeepProjectSetupStage(entry) {
346
376
  }
347
377
  else if (hasPendingDeepStage(prefs, entry.basePath)) {
348
378
  pendingDeepProjectSetupMap.delete(entry.basePath);
349
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
379
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
350
380
  return true;
351
381
  }
352
382
  return false;
353
383
  }
354
384
  if (!USER_DRIVEN_DEEP_SETUP_UNITS.has(result.unitType)) {
355
385
  pendingDeepProjectSetupMap.delete(entry.basePath);
356
- startAutoDetached(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
386
+ scheduleAutoStartAfterIdle(entry.ctx, entry.pi, entry.basePath, false, { step: entry.step });
357
387
  return true;
358
388
  }
359
389
  entry.currentUnitType = result.unitType;
@@ -531,7 +561,7 @@ export function checkAutoStartAfterDiscuss() {
531
561
  }
532
562
  pendingAutoStartMap.delete(basePath);
533
563
  ctx.ui.notify(`Milestone ${milestoneId} ready.`, "success");
534
- startAutoDetached(ctx, pi, basePath, false, { step });
564
+ scheduleAutoStartAfterIdle(ctx, pi, basePath, false, { step });
535
565
  return true;
536
566
  }
537
567
  /**
@@ -817,38 +847,55 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType)
817
847
  return;
818
848
  }
819
849
  }
820
- // Scope tools for discuss flows (#2949).
850
+ // Scope tools for guided workflow turns (#2949, token-consumption savings).
821
851
  // Providers with grammar-based constrained decoding (xAI/Grok) return
822
852
  // "Grammar is too complex" when the combined tool schema is too large.
823
- // Discuss flows only need a small subset of GSD tools — strip the heavy
824
- // planning/execution/completion tools to keep the grammar within limits.
853
+ // Guided workflow turns only need the active unit's tool surface; strip
854
+ // unrelated GSD tools and broad non-GSD tools for this queued turn, then
855
+ // restore so the narrowed surface does not leak into future dispatches.
825
856
  let savedTools = null;
826
- if (unitType?.startsWith("discuss-")) {
857
+ try {
827
858
  const currentTools = pi.getActiveTools();
828
- savedTools = currentTools;
829
- // Keep all non-GSD tools (builtins, other extensions) and only the
830
- // GSD tools on the discuss allowlist.
831
- const scopedTools = currentTools.filter((t) => !t.startsWith("gsd_") || DISCUSS_TOOLS_ALLOWLIST.includes(t));
832
- pi.setActiveTools(scopedTools);
833
- debugLog("discuss-tool-scoping", {
834
- unitType,
835
- before: currentTools.length,
836
- after: scopedTools.length,
837
- removed: currentTools.length - scopedTools.length,
838
- });
839
- }
840
- const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(gsdHome(), "agent", "GSD-WORKFLOW.md");
841
- const workflow = readFileSync(workflowPath, "utf-8");
842
- pi.sendMessage({
843
- customType,
844
- content: `Read the following GSD workflow protocol and execute exactly.\n\n${workflow}\n\n## Your Task\n\n${note}`,
845
- display: false,
846
- }, { triggerTurn: true });
847
- // Restore full tool set after the message is queued. The LLM turn has
848
- // already captured the scoped set — restoring prevents the narrowed
849
- // tools from leaking into subsequent dispatches (#3628).
850
- if (savedTools) {
851
- pi.setActiveTools(savedTools);
859
+ savedTools = {
860
+ tools: currentTools,
861
+ visibleSkills: typeof pi.getVisibleSkills === "function" ? pi.getVisibleSkills() : undefined,
862
+ restoreVisibleSkills: typeof pi.setVisibleSkills === "function",
863
+ };
864
+ if (unitType?.startsWith("discuss-") && !isFullGsdToolSurfaceRequested()) {
865
+ // Keep all non-GSD tools (builtins, other extensions) and only the
866
+ // GSD tools on the discuss allowlist.
867
+ const scopedTools = currentTools.filter((t) => !t.startsWith("gsd_") || DISCUSS_TOOLS_ALLOWLIST.includes(t));
868
+ pi.setActiveTools(scopedTools);
869
+ const scopedState = scopeGsdWorkflowToolsForDispatch(pi, unitType);
870
+ savedTools = {
871
+ tools: currentTools,
872
+ visibleSkills: scopedState?.visibleSkills ?? savedTools.visibleSkills,
873
+ restoreVisibleSkills: scopedState?.restoreVisibleSkills ?? savedTools.restoreVisibleSkills,
874
+ };
875
+ debugLog("discuss-tool-scoping", {
876
+ unitType,
877
+ before: currentTools.length,
878
+ after: pi.getActiveTools().length,
879
+ removed: currentTools.length - pi.getActiveTools().length,
880
+ });
881
+ }
882
+ else {
883
+ savedTools = scopeGsdWorkflowToolsForDispatch(pi, unitType) ?? savedTools;
884
+ }
885
+ const workflowPath = process.env.GSD_WORKFLOW_PATH ?? join(gsdHome(), "agent", "GSD-WORKFLOW.md");
886
+ const workflow = readFileSync(workflowPath, "utf-8");
887
+ pi.sendMessage({
888
+ customType,
889
+ content: buildWorkflowDispatchContent({ workflow, workflowPath, task: note }),
890
+ display: false,
891
+ }, { triggerTurn: true });
892
+ }
893
+ finally {
894
+ // Restore full tool set after the message is queued. The LLM turn has
895
+ // already captured the scoped set — restoring prevents the narrowed
896
+ // tools from leaking into subsequent dispatches (#3628). The finally
897
+ // block ensures restoration even if sendMessage throws.
898
+ restoreGsdWorkflowTools(pi, savedTools);
852
899
  }
853
900
  }
854
901
  function getStructuredQuestionsAvailability(pi, ctx) {
@@ -1469,8 +1516,8 @@ function selfHealRuntimeRecords(basePath, ctx) {
1469
1516
  cleared++;
1470
1517
  continue;
1471
1518
  }
1472
- // Clear records stuck in dispatched or timeout phase (process died mid-unit)
1473
- if (phase === "dispatched" || phase === "timeout") {
1519
+ // Clear records stuck in an in-flight phase (process died mid-unit).
1520
+ if (isInFlightRuntimePhase(phase)) {
1474
1521
  clearUnitRuntimeRecord(basePath, unitType, unitId);
1475
1522
  cleared++;
1476
1523
  }
@@ -1695,6 +1742,20 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1695
1742
  return;
1696
1743
  }
1697
1744
  }
1745
+ if (interrupted.classification !== "recoverable") {
1746
+ try {
1747
+ const { autoImportMarkdownHierarchyIfDbMismatch } = await import("./migration-auto-check.js");
1748
+ const result = await autoImportMarkdownHierarchyIfDbMismatch(basePath);
1749
+ if (result.action === "imported") {
1750
+ 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");
1751
+ }
1752
+ }
1753
+ catch (err) {
1754
+ const message = err instanceof Error ? err.message : String(err);
1755
+ ctx.ui.notify(`GSD could not auto-import existing planning state into gsd.db: ${message}`, "warning");
1756
+ logWarning("guided", `planning state auto-import failed: ${message}`, { file: "guided-flow.ts" });
1757
+ }
1758
+ }
1698
1759
  // Always derive from the project root — the assessment may have derived
1699
1760
  // state from a worktree path that was cleaned up in the stale branch above.
1700
1761
  const state = await deriveState(basePath);
@@ -1795,7 +1856,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1795
1856
  notYetMessage: "Run /gsd when ready.",
1796
1857
  });
1797
1858
  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");
1859
+ await runQuickTaskChoice(ctx, pi);
1799
1860
  }
1800
1861
  else if (choice === "new_milestone") {
1801
1862
  setPendingAutoStart(basePath, { ctx, pi, basePath, milestoneId: nextId, step: stepMode });
@@ -1837,7 +1898,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1837
1898
  notYetMessage: "Run /gsd when ready.",
1838
1899
  });
1839
1900
  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");
1901
+ await runQuickTaskChoice(ctx, pi);
1841
1902
  }
1842
1903
  else if (choice === "new_milestone") {
1843
1904
  const milestoneIds = findMilestoneIds(basePath);
@@ -1968,7 +2029,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
1968
2029
  notYetMessage: "Run /gsd when ready.",
1969
2030
  });
1970
2031
  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");
2032
+ await runQuickTaskChoice(ctx, pi);
1972
2033
  }
1973
2034
  else if (choice === "plan") {
1974
2035
  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
+ }
@@ -5,7 +5,7 @@
5
5
  // Both READ and WRITE operations are native — push operations remain as
6
6
  // execSync calls because git2 credential handling is too complex.
7
7
  import { execFileSync } from "node:child_process";
8
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
8
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { GSDError, GSD_GIT_ERROR } from "./errors.js";
11
11
  import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
@@ -1007,6 +1007,24 @@ export function nativeRmForce(basePath, paths) {
1007
1007
  gitFileExec(basePath, ["rm", "--force", "--", path], true);
1008
1008
  }
1009
1009
  }
1010
+ function runGitWorktreeAdd(basePath, wtPath, branch, createBranch, startPoint) {
1011
+ if (createBranch) {
1012
+ const branchRef = gitExec(basePath, ["show-ref", "--verify", `refs/heads/${branch}`], true);
1013
+ if (branchRef) {
1014
+ gitExec(basePath, ["worktree", "add", wtPath, branch]);
1015
+ return;
1016
+ }
1017
+ gitExec(basePath, ["worktree", "add", "-b", branch, wtPath, startPoint ?? "HEAD"]);
1018
+ }
1019
+ else {
1020
+ gitExec(basePath, ["worktree", "add", wtPath, branch]);
1021
+ }
1022
+ }
1023
+ export function assertWorktreeMaterialized(wtPath) {
1024
+ if (existsSync(join(wtPath, ".git")))
1025
+ return;
1026
+ throw new GSDError(GSD_GIT_ERROR, `git worktree add did not materialize a valid worktree at ${wtPath}: missing .git file`);
1027
+ }
1010
1028
  /**
1011
1029
  * Add a new git worktree.
1012
1030
  * Native: libgit2 worktree API.
@@ -1016,14 +1034,20 @@ export function nativeWorktreeAdd(basePath, wtPath, branch, createBranch, startP
1016
1034
  const native = loadNative();
1017
1035
  if (native) {
1018
1036
  native.gitWorktreeAdd(basePath, wtPath, branch, createBranch, startPoint);
1019
- return;
1020
- }
1021
- if (createBranch) {
1022
- gitExec(basePath, ["worktree", "add", "-b", branch, wtPath, startPoint ?? "HEAD"]);
1023
- }
1024
- else {
1025
- gitExec(basePath, ["worktree", "add", wtPath, branch]);
1037
+ try {
1038
+ assertWorktreeMaterialized(wtPath);
1039
+ return;
1040
+ }
1041
+ catch {
1042
+ rmSync(wtPath, { recursive: true, force: true });
1043
+ gitExec(basePath, ["worktree", "prune"], true);
1044
+ runGitWorktreeAdd(basePath, wtPath, branch, createBranch, startPoint);
1045
+ assertWorktreeMaterialized(wtPath);
1046
+ return;
1047
+ }
1026
1048
  }
1049
+ runGitWorktreeAdd(basePath, wtPath, branch, createBranch, startPoint);
1050
+ assertWorktreeMaterialized(wtPath);
1027
1051
  }
1028
1052
  /**
1029
1053
  * Remove a git worktree.