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
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Registers GSD extension runtime hooks and token-saving tool policies.
1
3
  import { join } from "node:path";
2
4
  import { isToolCallEventType } from "@gsd/pi-coding-agent";
3
5
  import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
@@ -19,10 +21,149 @@ import { initNotificationWidget } from "../notification-widget.js";
19
21
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
20
22
  import { extractSubagentAgentClasses } from "./subagent-input.js";
21
23
  import { approvalGateIdForUnit, isExplicitApprovalResponse, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.js";
24
+ import { resolveSkillManifest } from "../skill-manifest.js";
22
25
  // Skip the welcome screen on the very first session_start — cli.ts already
23
26
  // printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
24
27
  let isFirstSession = true;
25
28
  let approvalQuestionAbortInFlight = false;
29
+ let deferredApprovalGate = null;
30
+ export const MINIMAL_GSD_TOOL_NAMES = [
31
+ "gsd_exec",
32
+ "gsd_exec_search",
33
+ "gsd_resume",
34
+ "gsd_milestone_status",
35
+ "gsd_checkpoint_db",
36
+ "memory_query",
37
+ "capture_thought",
38
+ ];
39
+ export const MINIMAL_AUTO_BASE_TOOL_NAMES = [
40
+ "ask_user_questions",
41
+ "bash",
42
+ "bg_shell",
43
+ "edit",
44
+ "glob",
45
+ "grep",
46
+ "ls",
47
+ "read",
48
+ "write",
49
+ ];
50
+ const AUTO_UNIT_SCOPED_TOOLS = {
51
+ "research-milestone": ["gsd_summary_save", "gsd_decision_save"],
52
+ "plan-milestone": ["gsd_plan_milestone", "gsd_decision_save", "gsd_requirement_update"],
53
+ "discuss-milestone": ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
54
+ "validate-milestone": ["gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
55
+ "complete-milestone": ["gsd_complete_milestone", "subagent"],
56
+ "research-slice": ["gsd_summary_save", "gsd_decision_save"],
57
+ "plan-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
58
+ "refine-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
59
+ "replan-slice": ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
60
+ "complete-slice": ["gsd_slice_complete", "gsd_decision_save", "gsd_requirement_update", "subagent"],
61
+ "reassess-roadmap": ["gsd_reassess_roadmap"],
62
+ "execute-task": ["gsd_task_complete", "gsd_decision_save"],
63
+ "execute-task-simple": ["gsd_task_complete", "gsd_decision_save"],
64
+ "reactive-execute": ["gsd_task_complete", "gsd_decision_save"],
65
+ "run-uat": ["gsd_summary_save"],
66
+ "gate-evaluate": ["gsd_save_gate_result"],
67
+ "rewrite-docs": ["gsd_summary_save", "gsd_decision_save"],
68
+ "workflow-preferences": ["gsd_summary_save"],
69
+ "discuss-project": ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
70
+ "discuss-requirements": ["gsd_requirement_save", "gsd_summary_save"],
71
+ "research-decision": ["gsd_summary_save"],
72
+ "research-project": ["gsd_summary_save", "gsd_decision_save"],
73
+ };
74
+ const WORKFLOW_GSD_TOOL_NAMES = [
75
+ ...MINIMAL_GSD_TOOL_NAMES,
76
+ ...Object.values(AUTO_UNIT_SCOPED_TOOLS).flat(),
77
+ ].filter(isGsdManagedTool);
78
+ function isGsdManagedTool(name) {
79
+ return name.startsWith("gsd_") || name === "memory_query" || name === "capture_thought" || name === "gsd_graph";
80
+ }
81
+ export function buildMinimalGsdToolSet(activeToolNames) {
82
+ const active = new Set(activeToolNames);
83
+ const preserved = activeToolNames.filter((name) => !isGsdManagedTool(name));
84
+ const minimal = MINIMAL_GSD_TOOL_NAMES.filter((name) => active.has(name));
85
+ return [...new Set([...preserved, ...minimal])];
86
+ }
87
+ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType) {
88
+ const active = new Set(activeToolNames);
89
+ const unitTools = unitType ? AUTO_UNIT_SCOPED_TOOLS[unitType] ?? [] : [];
90
+ const autoBaseTools = new Set(MINIMAL_AUTO_BASE_TOOL_NAMES);
91
+ const preserved = activeToolNames.filter((name) => autoBaseTools.has(name));
92
+ const scoped = [...MINIMAL_GSD_TOOL_NAMES, ...unitTools].filter((name) => active.has(name));
93
+ return [...new Set([...preserved, ...scoped])];
94
+ }
95
+ export function buildMinimalGsdWorkflowToolSet(activeToolNames) {
96
+ const active = new Set(activeToolNames);
97
+ const autoBaseTools = new Set(MINIMAL_AUTO_BASE_TOOL_NAMES);
98
+ const preserved = activeToolNames.filter((name) => autoBaseTools.has(name));
99
+ const scoped = WORKFLOW_GSD_TOOL_NAMES.filter((name) => active.has(name));
100
+ return [...new Set([...preserved, ...scoped])];
101
+ }
102
+ export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessages) {
103
+ for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
104
+ const currentCustomType = requestCustomMessages?.[index]?.customType;
105
+ if (currentCustomType === "gsd-run" ||
106
+ currentCustomType === "gsd-discuss" ||
107
+ currentCustomType === "gsd-doctor-heal" ||
108
+ currentCustomType === "gsd-triage") {
109
+ return buildMinimalGsdWorkflowToolSet(activeToolNames);
110
+ }
111
+ }
112
+ return undefined;
113
+ }
114
+ export function isFullGsdToolSurfaceRequested() {
115
+ return process.env.PI_GSD_FULL_TOOLS === "1";
116
+ }
117
+ function isGeneralGsdToolScopingRequested() {
118
+ return process.env.PI_GSD_MINIMAL_TOOLS === "1";
119
+ }
120
+ function applyMinimalGsdToolSurface(pi) {
121
+ if (isFullGsdToolSurfaceRequested())
122
+ return;
123
+ const dash = getAutoRuntimeSnapshot();
124
+ if (dash.active && dash.currentUnit) {
125
+ pi.setActiveTools(buildMinimalAutoGsdToolSet(pi.getActiveTools(), dash.currentUnit.type));
126
+ return;
127
+ }
128
+ if (!isGeneralGsdToolScopingRequested())
129
+ return;
130
+ pi.setActiveTools(buildMinimalGsdToolSet(pi.getActiveTools()));
131
+ }
132
+ export function scopeGsdWorkflowToolsForDispatch(pi, unitType) {
133
+ if (isFullGsdToolSurfaceRequested())
134
+ return null;
135
+ const current = pi.getActiveTools();
136
+ const scoped = unitType
137
+ ? buildMinimalAutoGsdToolSet(current, unitType)
138
+ : buildMinimalGsdWorkflowToolSet(current);
139
+ const toolsChanged = !(scoped.length === current.length && scoped.every((name, index) => name === current[index]));
140
+ const skillManifest = resolveSkillManifest(unitType);
141
+ const canScopeSkills = skillManifest !== null && pi.getVisibleSkills && pi.setVisibleSkills;
142
+ if (!toolsChanged && !canScopeSkills) {
143
+ return null;
144
+ }
145
+ if (toolsChanged) {
146
+ pi.setActiveTools(scoped);
147
+ }
148
+ const visibleSkills = canScopeSkills ? pi.getVisibleSkills() : undefined;
149
+ if (canScopeSkills) {
150
+ pi.setVisibleSkills(skillManifest);
151
+ }
152
+ return {
153
+ tools: toolsChanged ? current : null,
154
+ visibleSkills,
155
+ restoreVisibleSkills: Boolean(canScopeSkills),
156
+ };
157
+ }
158
+ export function restoreGsdWorkflowTools(pi, savedState) {
159
+ if (!savedState)
160
+ return;
161
+ if (savedState.tools)
162
+ pi.setActiveTools(savedState.tools);
163
+ if (savedState.restoreVisibleSkills && pi.setVisibleSkills) {
164
+ pi.setVisibleSkills(savedState.visibleSkills);
165
+ }
166
+ }
26
167
  async function deriveGsdState(basePath) {
27
168
  const { deriveState } = await import("../state.js");
28
169
  return deriveState(basePath);
@@ -52,11 +193,70 @@ async function applyDisabledModelProviderPolicy(ctx) {
52
193
  // Non-fatal: keep default provider visibility if preferences cannot be loaded.
53
194
  }
54
195
  }
55
- export function resolveNotificationStoreBasePath(cwd = process.cwd()) {
56
- return resolveWorktreeProjectRoot(cwd);
196
+ /**
197
+ * Bridge `context_management.compaction_threshold_percent` from GSD preferences
198
+ * into the agent's runtime compaction settings (#5475). The preference is
199
+ * validated to (0.5, 0.95) at load time, but defense-in-depth normalization
200
+ * here protects against a stale or hand-edited prefs file. Calling with
201
+ * `undefined` clears any prior override so a removed preference does not leak.
202
+ */
203
+ async function applyCompactionThresholdOverride(ctx) {
204
+ try {
205
+ const { loadEffectiveGSDPreferences } = await import("../preferences.js");
206
+ const prefs = loadEffectiveGSDPreferences();
207
+ const raw = prefs?.preferences.context_management?.compaction_threshold_percent;
208
+ const value = typeof raw === "number" && Number.isFinite(raw) && raw > 0 && raw < 1 ? raw : undefined;
209
+ ctx.setCompactionThresholdOverride(value);
210
+ }
211
+ catch {
212
+ // Non-fatal: leave any existing override in place.
213
+ }
214
+ }
215
+ function clearDeferredApprovalGate(basePath) {
216
+ if (!basePath || deferredApprovalGate?.basePath === basePath) {
217
+ deferredApprovalGate = null;
218
+ }
219
+ }
220
+ function deferApprovalGate(gateId, basePath) {
221
+ deferredApprovalGate = { gateId, basePath };
222
+ }
223
+ function contextBasePath(ctx) {
224
+ return typeof ctx?.cwd === "string" ? ctx.cwd : process.cwd();
225
+ }
226
+ function activateDeferredApprovalGate(basePath) {
227
+ if (deferredApprovalGate?.basePath !== basePath)
228
+ return;
229
+ setPendingGate(deferredApprovalGate.gateId, basePath);
230
+ deferredApprovalGate = null;
231
+ }
232
+ function isContextDraftSummarySave(toolName, input) {
233
+ if (toolName !== "gsd_summary_save" && toolName !== "summary_save")
234
+ return false;
235
+ if (!input || typeof input !== "object")
236
+ return false;
237
+ return input.artifact_type === "CONTEXT-DRAFT";
238
+ }
239
+ function shouldBlockDeferredApprovalTool(toolName, input, basePath) {
240
+ if (deferredApprovalGate?.basePath !== basePath)
241
+ return { block: false };
242
+ if (toolName === "ask_user_questions")
243
+ return { block: false };
244
+ if (isContextDraftSummarySave(toolName, input))
245
+ return { block: false };
246
+ return {
247
+ block: true,
248
+ reason: [
249
+ `HARD BLOCK: Approval question "${deferredApprovalGate.gateId}" has been shown to the user.`,
250
+ `Only CONTEXT-DRAFT persistence may finish in this same assistant turn.`,
251
+ `Wait for the user's answer before calling additional tools.`,
252
+ ].join(" "),
253
+ };
254
+ }
255
+ export function resolveNotificationStoreBasePath(basePath) {
256
+ return resolveWorktreeProjectRoot(basePath);
57
257
  }
58
258
  function initSessionNotifications(ctx) {
59
- initNotificationStore(resolveNotificationStoreBasePath());
259
+ initNotificationStore(resolveNotificationStoreBasePath(contextBasePath(ctx)));
60
260
  installNotifyInterceptor(ctx);
61
261
  initNotificationWidget(ctx);
62
262
  }
@@ -90,27 +290,30 @@ async function writeContextModeCompactionSnapshot(basePath) {
90
290
  }
91
291
  export function registerHooks(pi, ecosystemHandlers) {
92
292
  pi.on("session_start", async (_event, ctx) => {
293
+ const basePath = contextBasePath(ctx);
93
294
  initSessionNotifications(ctx);
94
295
  if (!isAutoActive()) {
95
296
  const { initHealthWidget } = await import("../health-widget.js");
96
297
  initHealthWidget(ctx);
97
298
  }
98
- resetWriteGateState(process.cwd());
299
+ resetWriteGateState(basePath);
99
300
  resetToolCallLoopGuard();
100
301
  approvalQuestionAbortInFlight = false;
302
+ clearDeferredApprovalGate();
101
303
  await resetAskUserQuestionsTurnCache();
102
304
  await syncServiceTierStatus(ctx);
103
305
  await applyDisabledModelProviderPolicy(ctx);
306
+ await applyCompactionThresholdOverride(ctx);
104
307
  // Skip MCP auto-prep when running inside an auto-worktree (see session_switch below).
105
308
  const { isInAutoWorktree } = await import("../auto-worktree.js");
106
- if (!isInAutoWorktree(process.cwd())) {
309
+ if (!isInAutoWorktree(basePath)) {
107
310
  const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
108
- prepareWorkflowMcpForProject(ctx, process.cwd());
311
+ prepareWorkflowMcpForProject(ctx, basePath);
109
312
  }
110
313
  // Apply show_token_cost preference (#1515)
111
314
  try {
112
315
  const { loadEffectiveGSDPreferences } = await import("../preferences.js");
113
- const prefs = loadEffectiveGSDPreferences();
316
+ const prefs = loadEffectiveGSDPreferences(basePath);
114
317
  process.env.GSD_SHOW_TOKEN_COST = prefs?.preferences.show_token_cost ? "1" : "";
115
318
  }
116
319
  catch { /* non-fatal */ }
@@ -142,21 +345,24 @@ export function registerHooks(pi, ecosystemHandlers) {
142
345
  }
143
346
  });
144
347
  pi.on("session_switch", async (_event, ctx) => {
348
+ const basePath = contextBasePath(ctx);
145
349
  initSessionNotifications(ctx);
146
- resetWriteGateState(process.cwd());
350
+ resetWriteGateState(basePath);
147
351
  resetToolCallLoopGuard();
352
+ clearDeferredApprovalGate();
148
353
  await resetAskUserQuestionsTurnCache();
149
- clearDiscussionFlowState(process.cwd());
354
+ clearDiscussionFlowState(basePath);
150
355
  await syncServiceTierStatus(ctx);
151
356
  await applyDisabledModelProviderPolicy(ctx);
357
+ await applyCompactionThresholdOverride(ctx);
152
358
  // Skip MCP auto-prep when running inside an auto-worktree. The worktree
153
359
  // already has .mcp.json from createAutoWorktree, and re-running the writer
154
360
  // post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
155
361
  // CLI path resolution), dirtying the tree and breaking the milestone merge.
156
362
  const { isInAutoWorktree } = await import("../auto-worktree.js");
157
- if (!isInAutoWorktree(process.cwd())) {
363
+ if (!isInAutoWorktree(basePath)) {
158
364
  const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
159
- prepareWorkflowMcpForProject(ctx, process.cwd());
365
+ prepareWorkflowMcpForProject(ctx, basePath);
160
366
  }
161
367
  await loadToolApiKeysForSession();
162
368
  if (!isAutoActive()) {
@@ -168,10 +374,11 @@ export function registerHooks(pi, ecosystemHandlers) {
168
374
  }
169
375
  });
170
376
  pi.on("before_agent_start", async (event, ctx) => {
377
+ applyMinimalGsdToolSurface(pi);
171
378
  // Wait for ecosystem loader to finish (no-op after first turn).
172
379
  const { getEcosystemReadyPromise } = await import("../ecosystem/loader.js");
173
380
  await getEcosystemReadyPromise();
174
- const beforeAgentBasePath = process.cwd();
381
+ const beforeAgentBasePath = contextBasePath(ctx);
175
382
  const pendingApprovalGate = getPendingGate(beforeAgentBasePath);
176
383
  if (pendingApprovalGate && isExplicitApprovalResponse(event.prompt, pendingApprovalGate)) {
177
384
  markApprovalGateVerified(pendingApprovalGate, beforeAgentBasePath);
@@ -180,13 +387,14 @@ export function registerHooks(pi, ecosystemHandlers) {
180
387
  markDepthVerified(milestoneId, beforeAgentBasePath);
181
388
  clearPendingGate(beforeAgentBasePath);
182
389
  }
390
+ clearDeferredApprovalGate(beforeAgentBasePath);
183
391
  // GSD's own context injection (existing behavior — unchanged).
184
392
  const { buildBeforeAgentStartResult } = await import("./system-context.js");
185
393
  const gsdResult = await buildBeforeAgentStartResult(event, ctx);
186
394
  // Refresh the snapshot used by ecosystem getPhase()/getActiveUnit().
187
395
  // deriveState has its own ~100ms cache so this is cheap on repeat calls.
188
396
  try {
189
- const state = await deriveGsdState(process.cwd());
397
+ const state = await deriveGsdState(beforeAgentBasePath);
190
398
  updateSnapshot(state);
191
399
  }
192
400
  catch {
@@ -223,7 +431,12 @@ export function registerHooks(pi, ecosystemHandlers) {
223
431
  resetToolCallLoopGuard();
224
432
  await resetAskUserQuestionsTurnCache();
225
433
  const { handleAgentEnd } = await import("./agent-end-recovery.js");
226
- await handleAgentEnd(pi, event, ctx);
434
+ try {
435
+ await handleAgentEnd(pi, event, ctx);
436
+ }
437
+ finally {
438
+ activateDeferredApprovalGate(contextBasePath(ctx));
439
+ }
227
440
  });
228
441
  // Squash-merge quick-task branch back to the original branch after the
229
442
  // agent turn completes (#2668). cleanupQuickBranch is a no-op when no
@@ -237,8 +450,8 @@ export function registerHooks(pi, ecosystemHandlers) {
237
450
  // Best-effort: don't break the turn lifecycle if cleanup fails.
238
451
  }
239
452
  });
240
- pi.on("session_before_compact", async () => {
241
- const basePath = process.cwd();
453
+ pi.on("session_before_compact", async (_event, ctx) => {
454
+ const basePath = contextBasePath(ctx);
242
455
  // Context Mode is default-on. Write the resumable snapshot before any
243
456
  // active-auto cancel return so auto sessions still leave re-entry context.
244
457
  await writeContextModeCompactionSnapshot(basePath);
@@ -302,7 +515,7 @@ export function registerHooks(pi, ecosystemHandlers) {
302
515
  if (!unitType) {
303
516
  try {
304
517
  const { getPendingDeepProjectSetupUnitForContext } = await import("../guided-flow.js");
305
- const pending = getPendingDeepProjectSetupUnitForContext(ctx, process.cwd());
518
+ const pending = getPendingDeepProjectSetupUnitForContext(ctx, contextBasePath(ctx));
306
519
  unitType = pending?.unitType;
307
520
  unitId = pending?.unitId;
308
521
  }
@@ -311,7 +524,7 @@ export function registerHooks(pi, ecosystemHandlers) {
311
524
  }
312
525
  }
313
526
  if (!unitType) {
314
- const milestoneId = await getDiscussionMilestoneIdFor(process.cwd());
527
+ const milestoneId = await getDiscussionMilestoneIdFor(contextBasePath(ctx));
315
528
  if (milestoneId) {
316
529
  unitType = "discuss-milestone";
317
530
  unitId = milestoneId;
@@ -321,11 +534,12 @@ export function registerHooks(pi, ecosystemHandlers) {
321
534
  return;
322
535
  const gateId = approvalGateIdForUnit(unitType, unitId);
323
536
  if (gateId)
324
- setPendingGate(gateId, process.cwd());
537
+ deferApprovalGate(gateId, contextBasePath(ctx));
325
538
  approvalQuestionAbortInFlight = true;
326
539
  ctx.ui.notify(`${unitType}${unitId ? ` ${unitId}` : ""} is waiting for your approval - pausing before more tool calls run.`, "info");
327
- // The pending gate set above blocks subsequent non-read-only tool calls
328
- // via the tool_call hook below, so we do not abort the in-flight stream.
540
+ // The durable pending gate is activated at agent_end so same-turn
541
+ // CONTEXT-DRAFT persistence can finish after the text boundary streams.
542
+ // The tool_call hook below still blocks non-draft tools in this turn.
329
543
  // Aborting mid-stream eats the model's question text on external CLI
330
544
  // providers (Claude Code SDK) because lastTextContent isn't populated
331
545
  // from in-flight builder state — the user only ever sees "Claude Code
@@ -335,7 +549,7 @@ export function registerHooks(pi, ecosystemHandlers) {
335
549
  const { isParallelActive, shutdownParallel } = await import("../parallel-orchestrator.js");
336
550
  if (isParallelActive()) {
337
551
  try {
338
- await shutdownParallel(process.cwd());
552
+ await shutdownParallel(contextBasePath(ctx));
339
553
  }
340
554
  catch {
341
555
  // best-effort
@@ -348,14 +562,17 @@ export function registerHooks(pi, ecosystemHandlers) {
348
562
  saveActivityLog(ctx, dash.basePath, dash.currentUnit.type, dash.currentUnit.id);
349
563
  }
350
564
  });
351
- pi.on("tool_call", async (event) => {
352
- const discussionBasePath = process.cwd();
565
+ pi.on("tool_call", async (event, ctx) => {
566
+ const discussionBasePath = contextBasePath(ctx);
353
567
  const toolName = canonicalToolName(event.toolName);
354
568
  // ── Loop guard: block repeated identical tool calls ──
355
569
  const loopCheck = checkToolCallLoop(toolName, event.input);
356
570
  if (loopCheck.block) {
357
571
  return { block: true, reason: loopCheck.reason };
358
572
  }
573
+ const deferredGateGuard = shouldBlockDeferredApprovalTool(toolName, event.input, discussionBasePath);
574
+ if (deferredGateGuard.block)
575
+ return deferredGateGuard;
359
576
  // ── Discussion gate enforcement: track pending gate questions ─────────
360
577
  // Only gate-shaped ask_user_questions calls should block execution.
361
578
  // The gate stays pending until the user selects the approval option.
@@ -494,7 +711,7 @@ export function registerHooks(pi, ecosystemHandlers) {
494
711
  }
495
712
  }
496
713
  });
497
- pi.on("tool_result", async (event) => {
714
+ pi.on("tool_result", async (event, ctx) => {
498
715
  if (isAutoActive() && typeof event.toolCallId === "string") {
499
716
  markToolEnd(event.toolCallId);
500
717
  }
@@ -514,7 +731,7 @@ export function registerHooks(pi, ecosystemHandlers) {
514
731
  const toolName = canonicalToolName(event.toolName);
515
732
  if (toolName !== "ask_user_questions")
516
733
  return;
517
- const basePath = process.cwd();
734
+ const basePath = contextBasePath(ctx);
518
735
  const milestoneId = await getDiscussionMilestoneIdFor(basePath);
519
736
  const queueActive = isQueuePhaseActive(basePath);
520
737
  const details = event.details;
@@ -716,8 +933,22 @@ export function registerHooks(pi, ecosystemHandlers) {
716
933
  // Tool set adaptation hook (ADR-005 Phase 4)
717
934
  // Extensions can override tool set after model selection by returning { toolNames: [...] }
718
935
  // Return undefined to let the built-in provider compatibility filtering proceed.
719
- pi.on("adjust_tool_set", async (_event) => {
720
- // Default: no override — let provider capability filtering handle tool set
936
+ pi.on("adjust_tool_set", async (event) => {
937
+ if (isFullGsdToolSurfaceRequested())
938
+ return undefined;
939
+ const removed = new Set(event.filteredTools);
940
+ const providerCompatible = event.activeToolNames.filter((name) => !removed.has(name));
941
+ const requestScoped = buildRequestScopedGsdToolSet(providerCompatible, event.requestCustomMessages);
942
+ if (requestScoped) {
943
+ return { toolNames: requestScoped };
944
+ }
945
+ const dash = getAutoRuntimeSnapshot();
946
+ if (dash.active && dash.currentUnit) {
947
+ return { toolNames: buildMinimalAutoGsdToolSet(providerCompatible, dash.currentUnit.type) };
948
+ }
949
+ if (isGeneralGsdToolScopingRequested()) {
950
+ return { toolNames: buildMinimalGsdToolSet(providerCompatible) };
951
+ }
721
952
  return undefined;
722
953
  });
723
954
  }
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: System prompt and hidden context bootstrap for GSD sessions.
1
3
  import { existsSync, readFileSync, unlinkSync } from "node:fs";
2
4
  import { join } from "node:path";
3
5
  import { logWarning } from "../workflow-logger.js";
@@ -17,6 +19,11 @@ import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile,
17
19
  import { toPosixPath } from "../../shared/mod.js";
18
20
  import { autoEnableCmuxPreferences } from "../commands-cmux.js";
19
21
  import { gsdHome } from "../gsd-home.js";
22
+ const DEFAULT_CONTEXT_MESSAGE_MAX_CHARS = 4_000;
23
+ const DEFAULT_KNOWLEDGE_MAX_CHARS = 12_000;
24
+ const DEFAULT_CODEBASE_MAX_CHARS = 8_000;
25
+ const MIN_CONTEXT_MESSAGE_MAX_CHARS = 1_000;
26
+ const MIN_KNOWLEDGE_MAX_CHARS = 1_000;
20
27
  /**
21
28
  * Bundled skill triggers — resolved dynamically at runtime instead of
22
29
  * hardcoding absolute paths in the system prompt template. Only skills
@@ -135,7 +142,6 @@ export async function buildBeforeAgentStartResult(event, ctx) {
135
142
  catch (e) {
136
143
  logWarning("bootstrap", `decisions backfill failed: ${e.message}`);
137
144
  }
138
- const memoryBlock = await loadMemoryBlock(event.prompt ?? "");
139
145
  let newSkillsBlock = "";
140
146
  if (hasSkillSnapshot()) {
141
147
  const newSkills = detectNewSkills();
@@ -165,11 +171,10 @@ export async function buildBeforeAgentStartResult(event, ctx) {
165
171
  if (rawContent) {
166
172
  // Cap injection size to ~2 000 tokens to avoid bloating every request.
167
173
  // Full map is always available at .gsd/CODEBASE.md.
168
- const MAX_CODEBASE_CHARS = 8_000;
169
174
  const generatedMatch = rawContent.match(/Generated: (\S+)/);
170
175
  const generatedAt = generatedMatch?.[1] ?? "unknown";
171
- const content = rawContent.length > MAX_CODEBASE_CHARS
172
- ? rawContent.slice(0, MAX_CODEBASE_CHARS) + "\n\n*(truncated — see .gsd/CODEBASE.md for full map)*"
176
+ const content = rawContent.length > DEFAULT_CODEBASE_MAX_CHARS
177
+ ? rawContent.slice(0, DEFAULT_CODEBASE_MAX_CHARS) + "\n\n*(truncated — see .gsd/CODEBASE.md for full map)*"
173
178
  : rawContent;
174
179
  codebaseBlock = `\n\n[PROJECT CODEBASE — File structure and descriptions (generated ${generatedAt}, auto-refreshed when GSD detects tracked file changes; use /gsd codebase stats for status)]\n\n${content}`;
175
180
  }
@@ -180,6 +185,9 @@ export async function buildBeforeAgentStartResult(event, ctx) {
180
185
  }
181
186
  warnDeprecatedAgentInstructions();
182
187
  const injection = await buildGuidedExecuteContextInjection(event.prompt, process.cwd());
188
+ const memoryBlock = await loadMemoryBlock(event.prompt ?? "", {
189
+ includePromptRelevant: !(injection && isLowEntropyResumePrompt(event.prompt ?? "")),
190
+ });
183
191
  // Re-inject forensics context on follow-up turns (#2941)
184
192
  const forensicsInjection = !injection ? buildForensicsContextInjection(process.cwd(), event.prompt) : null;
185
193
  const worktreeBlock = buildWorktreeContextBlock();
@@ -188,12 +196,9 @@ export async function buildBeforeAgentStartResult(event, ctx) {
188
196
  ? `\n\n## Subagent Model\n\nWhen spawning subagents via the \`subagent\` tool, always pass \`model: "${subagentModelConfig.primary}"\` in the tool call parameters. Never omit this — always specify it explicitly.`
189
197
  : "";
190
198
  // memoryBlock is FTS-queried against the user prompt and changes per call.
191
- // Removing it from `fullSystem` keeps the system-prompt cache breakpoint
192
- // stable across calls the only scoped goal of this fix. The pi-ai
193
- // Anthropic adapter additionally cache-marks the last user turn, so the
194
- // memoryBlock injected via the context message may itself be cached up to
195
- // that boundary; that's orthogonal and unchanged from prior behavior. The
196
- // load-bearing win here is preserving the system+tools cache hit. (#5019)
199
+ // Keeping it out of `fullSystem` preserves provider prompt-cache stability
200
+ // for the static system/tool prefix. The dynamic memory block rides the
201
+ // volatile context message instead. (#5019)
197
202
  const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${codebaseBlock}${newSkillsBlock}${worktreeBlock}${subagentModelBlock}`;
198
203
  stopContextTimer({
199
204
  systemPromptSize: fullSystem.length,
@@ -217,20 +222,49 @@ export async function buildBeforeAgentStartResult(event, ctx) {
217
222
  * filesystem and DB dependencies to exercise this routing logic in-place.
218
223
  */
219
224
  export function buildContextMessage(opts) {
220
- const memoryContent = opts.memoryBlock.trim();
225
+ const contextCharLimit = getContextMessageCharLimit();
226
+ const memoryContent = markMemoryContextSupplied(opts.memoryBlock.trim());
221
227
  if (opts.injection) {
222
- const content = memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection;
228
+ const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection, contextCharLimit);
223
229
  return { customType: "gsd-guided-context", content, display: false };
224
230
  }
225
231
  if (opts.forensicsInjection) {
226
- const content = memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection;
232
+ const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection, contextCharLimit);
227
233
  return { customType: "gsd-forensics", content, display: false };
228
234
  }
229
235
  if (memoryContent) {
230
- return { customType: "gsd-memory", content: memoryContent, display: false };
236
+ return {
237
+ customType: "gsd-memory",
238
+ content: limitContextMessageContent(memoryContent, contextCharLimit),
239
+ display: false,
240
+ };
231
241
  }
232
242
  return null;
233
243
  }
244
+ function getContextMessageCharLimit() {
245
+ const raw = process.env.PI_GSD_CONTEXT_MAX_CHARS;
246
+ if (!raw)
247
+ return DEFAULT_CONTEXT_MESSAGE_MAX_CHARS;
248
+ if (raw === "0")
249
+ return null;
250
+ const parsed = Number(raw);
251
+ if (!Number.isFinite(parsed) || parsed < MIN_CONTEXT_MESSAGE_MAX_CHARS) {
252
+ return DEFAULT_CONTEXT_MESSAGE_MAX_CHARS;
253
+ }
254
+ return Math.floor(parsed);
255
+ }
256
+ function limitContextMessageContent(content, limit) {
257
+ if (!limit || content.length <= limit)
258
+ return content;
259
+ const suffix = "\n\n[GSD Context Truncated]\nFull context is available from the referenced .gsd files and tools; read on demand only if this excerpt lacks required evidence.";
260
+ const headBudget = Math.max(0, limit - suffix.length);
261
+ return `${content.slice(0, headBudget).trimEnd()}${suffix}`;
262
+ }
263
+ function markMemoryContextSupplied(memoryContent) {
264
+ if (!memoryContent)
265
+ return "";
266
+ return `[GSD Context Metadata]\n- Memory supplied: yes\n\n${memoryContent}`;
267
+ }
234
268
  /**
235
269
  * ADR-013 step 4 — auto-injection parity for the memories table.
236
270
  *
@@ -249,7 +283,7 @@ export function buildContextMessage(opts) {
249
283
  * with a token-budget cap. Failures degrade gracefully — the function never
250
284
  * throws and returns "" so the system prompt construction continues.
251
285
  */
252
- export async function loadMemoryBlock(userPrompt) {
286
+ export async function loadMemoryBlock(userPrompt, opts = {}) {
253
287
  try {
254
288
  const { formatMemoriesForPrompt, getActiveMemoriesRanked, queryMemoriesRanked } = await import("../memory-store.js");
255
289
  // Categories that belong in every turn. Pre-ADR-013 this was just
@@ -268,7 +302,7 @@ export async function loadMemoryBlock(userPrompt) {
268
302
  const criticalIds = new Set(critical.map((m) => m.id));
269
303
  let relevant = [];
270
304
  const trimmed = userPrompt.trim();
271
- if (trimmed) {
305
+ if (trimmed && opts.includePromptRelevant !== false) {
272
306
  const hits = queryMemoriesRanked({ query: trimmed, k: QUERY_K });
273
307
  relevant = hits.map((h) => h.memory).filter((m) => !criticalIds.has(m.id));
274
308
  }
@@ -319,15 +353,37 @@ export function loadKnowledgeBlock(gsdHomeDir, cwd) {
319
353
  return { block: "", globalSizeKb: 0 };
320
354
  }
321
355
  const parts = [];
322
- if (globalKnowledge)
323
- parts.push(`## Global Knowledge\n\n${globalKnowledge}`);
324
- if (projectKnowledge)
325
- parts.push(`## Project Knowledge\n\n${projectKnowledge}`);
356
+ if (globalKnowledge) {
357
+ parts.push(`## Global Knowledge\nSource: \`${globalKnowledgePath}\`\n\n${globalKnowledge}`);
358
+ }
359
+ if (projectKnowledge) {
360
+ parts.push(`## Project Knowledge\nSource: \`${knowledgePath}\`\n\n${projectKnowledge}`);
361
+ }
362
+ const body = limitKnowledgeBlock(parts.join("\n\n"), getKnowledgeCharLimit());
326
363
  return {
327
- block: `\n\n[KNOWLEDGE — Rules, patterns, and lessons learned]\n\n${parts.join("\n\n")}`,
364
+ block: `\n\n[KNOWLEDGE — Rules, patterns, and lessons learned]\n\n${body}`,
328
365
  globalSizeKb,
329
366
  };
330
367
  }
368
+ function getKnowledgeCharLimit() {
369
+ const raw = process.env.PI_GSD_KNOWLEDGE_MAX_CHARS;
370
+ if (!raw)
371
+ return DEFAULT_KNOWLEDGE_MAX_CHARS;
372
+ if (raw === "0")
373
+ return null;
374
+ const parsed = Number(raw);
375
+ if (!Number.isFinite(parsed) || parsed < MIN_KNOWLEDGE_MAX_CHARS) {
376
+ return DEFAULT_KNOWLEDGE_MAX_CHARS;
377
+ }
378
+ return Math.floor(parsed);
379
+ }
380
+ function limitKnowledgeBlock(content, limit) {
381
+ if (!limit || content.length <= limit)
382
+ return content;
383
+ const suffix = "\n\n[Knowledge Truncated]\nFull KNOWLEDGE.md content remains available at the source path(s) above; read on demand only if this excerpt lacks a required rule.";
384
+ const headBudget = Math.max(0, limit - suffix.length);
385
+ return `${content.slice(0, headBudget).trimEnd()}${suffix}`;
386
+ }
331
387
  function buildWorktreeContextBlock() {
332
388
  const worktreeName = getActiveWorktreeName();
333
389
  const worktreeMainCwd = getWorktreeOriginalCwd();
@@ -376,6 +432,10 @@ function buildWorktreeContextBlock() {
376
432
  * Tested against the trimmed, lowercased prompt with trailing punctuation stripped.
377
433
  */
378
434
  const RESUME_INTENT_PATTERNS = /^(continue|resume|ok|go|go ahead|proceed|keep going|carry on|next|yes|yeah|yep|sure|do it|let's go|pick up where you left off)$/;
435
+ export function isLowEntropyResumePrompt(prompt) {
436
+ const trimmed = prompt.trim().toLowerCase().replace(/[.!?,]+$/g, "");
437
+ return RESUME_INTENT_PATTERNS.test(trimmed);
438
+ }
379
439
  async function buildGuidedExecuteContextInjection(prompt, basePath) {
380
440
  const ensureStateDbOpen = async () => {
381
441
  const { ensureDbOpen } = await import("./dynamic-tools.js");
@@ -402,8 +462,7 @@ async function buildGuidedExecuteContextInjection(prompt, basePath) {
402
462
  // control/help/diagnostic prompts with unrelated execution context.
403
463
  // Phase-gated: only fire during "executing" to avoid misrouting during
404
464
  // replanning, gate evaluation, or other non-execution phases.
405
- const trimmed = prompt.trim().toLowerCase().replace(/[.!?,]+$/g, "");
406
- if (RESUME_INTENT_PATTERNS.test(trimmed)) {
465
+ if (isLowEntropyResumePrompt(prompt)) {
407
466
  await ensureStateDbOpen();
408
467
  const state = await deriveState(basePath);
409
468
  if (state.phase === "executing" && state.activeTask && state.activeMilestone && state.activeSlice) {