gsd-pi 2.80.0-dev.c5f2443b3 → 2.80.0-dev.e51d2c88c

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 (434) hide show
  1. package/README.md +4 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +2 -2
  4. package/dist/resources/extensions/github-sync/templates.js +39 -8
  5. package/dist/resources/extensions/gsd/auto/loop.js +48 -10
  6. package/dist/resources/extensions/gsd/auto/phases.js +66 -45
  7. package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
  8. package/dist/resources/extensions/gsd/auto/run-unit.js +32 -16
  9. package/dist/resources/extensions/gsd/auto-dashboard.js +51 -15
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  12. package/dist/resources/extensions/gsd/auto-prompts.js +124 -2
  13. package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
  14. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  17. package/dist/resources/extensions/gsd/auto.js +75 -5
  18. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +36 -3
  19. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
  21. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +129 -1
  22. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  23. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  24. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  25. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  26. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  27. package/dist/resources/extensions/gsd/custom-workflow-engine.js +22 -2
  28. package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
  29. package/dist/resources/extensions/gsd/db-base-schema.js +18 -2
  30. package/dist/resources/extensions/gsd/db-migration-steps.js +22 -0
  31. package/dist/resources/extensions/gsd/detection.js +106 -0
  32. package/dist/resources/extensions/gsd/graph.js +9 -3
  33. package/dist/resources/extensions/gsd/gsd-db.js +146 -13
  34. package/dist/resources/extensions/gsd/guided-flow.js +82 -16
  35. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  36. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  37. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  38. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  39. package/dist/resources/extensions/gsd/pr-evidence.js +57 -16
  40. package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
  41. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
  42. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  44. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  46. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  47. package/dist/resources/extensions/gsd/quick.js +34 -2
  48. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  49. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  50. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  51. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  52. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  53. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  54. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  55. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  56. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
  57. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  58. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  59. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  60. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  61. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  62. package/dist/web/standalone/.next/BUILD_ID +1 -1
  63. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  64. package/dist/web/standalone/.next/build-manifest.json +3 -3
  65. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  66. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/index.html +1 -1
  85. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  92. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  93. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  96. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  97. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  98. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  99. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  100. package/package.json +12 -8
  101. package/packages/contracts/package.json +1 -1
  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-ai/dist/models/fake-model.d.ts +12 -0
  110. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  111. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  112. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  113. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  114. package/packages/pi-ai/dist/models/index.js +8 -0
  115. package/packages/pi-ai/dist/models/index.js.map +1 -1
  116. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  117. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  118. package/packages/pi-ai/dist/providers/fake.js +319 -0
  119. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  120. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  121. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  122. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  123. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  124. package/packages/pi-ai/src/models/index.ts +9 -0
  125. package/packages/pi-ai/src/providers/fake.ts +376 -0
  126. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  127. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  128. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
  129. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
  132. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +76 -0
  134. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  136. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  138. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  140. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  141. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  142. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  143. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  144. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  145. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  146. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  147. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  148. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  149. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  150. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  151. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  152. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/extensions/runner.js +17 -1
  154. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
  156. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  158. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  162. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -0
  164. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/settings-manager.js +33 -0
  166. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  169. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  170. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  171. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +54 -15
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  182. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  186. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  190. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  192. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +17 -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 +109 -17
  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 +69 -2
  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 +93 -1
  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/controllers/input-controller.test.js +1 -0
  203. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  205. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  206. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  208. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +26 -0
  210. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  213. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  216. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  217. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  218. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  219. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  221. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  223. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  224. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  226. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  228. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  230. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  231. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  232. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  233. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  234. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  235. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  236. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  237. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  238. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  239. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  240. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  241. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  243. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  244. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
  245. package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
  246. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +89 -0
  247. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  248. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  249. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  250. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  251. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +110 -0
  252. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
  253. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  254. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  255. package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
  256. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  257. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  258. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +78 -15
  259. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  260. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  261. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  262. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  263. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  264. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  265. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +122 -17
  266. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +99 -1
  267. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +92 -3
  268. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  269. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  270. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -0
  271. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  272. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  273. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  274. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  275. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  276. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  277. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  278. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  279. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  280. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  281. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  282. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  283. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  284. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  285. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  286. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  287. package/packages/pi-tui/dist/index.d.ts +1 -0
  288. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  289. package/packages/pi-tui/dist/index.js +2 -0
  290. package/packages/pi-tui/dist/index.js.map +1 -1
  291. package/packages/pi-tui/dist/style.d.ts +41 -0
  292. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  293. package/packages/pi-tui/dist/style.js +158 -0
  294. package/packages/pi-tui/dist/style.js.map +1 -0
  295. package/packages/pi-tui/dist/tui.d.ts +0 -1
  296. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  297. package/packages/pi-tui/dist/tui.js +21 -16
  298. package/packages/pi-tui/dist/tui.js.map +1 -1
  299. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  300. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  301. package/packages/pi-tui/src/index.ts +9 -0
  302. package/packages/pi-tui/src/style.ts +225 -0
  303. package/packages/pi-tui/src/tui.ts +23 -16
  304. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  305. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  306. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  307. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  308. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  309. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  310. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  311. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  312. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  313. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  314. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  315. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  316. package/src/resources/GSD-WORKFLOW.md +2 -2
  317. package/src/resources/extensions/github-sync/templates.ts +38 -8
  318. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  319. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  320. package/src/resources/extensions/gsd/auto/loop.ts +67 -18
  321. package/src/resources/extensions/gsd/auto/phases.ts +77 -48
  322. package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
  323. package/src/resources/extensions/gsd/auto/run-unit.ts +42 -15
  324. package/src/resources/extensions/gsd/auto-dashboard.ts +57 -8
  325. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  326. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  327. package/src/resources/extensions/gsd/auto-prompts.ts +133 -2
  328. package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
  329. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  330. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  331. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  332. package/src/resources/extensions/gsd/auto.ts +90 -4
  333. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -2
  334. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
  335. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -1
  336. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +135 -1
  337. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  338. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  339. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  340. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  341. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  342. package/src/resources/extensions/gsd/custom-workflow-engine.ts +24 -1
  343. package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
  344. package/src/resources/extensions/gsd/db-base-schema.ts +19 -2
  345. package/src/resources/extensions/gsd/db-migration-steps.ts +25 -0
  346. package/src/resources/extensions/gsd/detection.ts +128 -0
  347. package/src/resources/extensions/gsd/graph.ts +12 -5
  348. package/src/resources/extensions/gsd/gsd-db.ts +168 -13
  349. package/src/resources/extensions/gsd/guided-flow.ts +98 -16
  350. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  351. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  352. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  353. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  354. package/src/resources/extensions/gsd/pr-evidence.ts +63 -5
  355. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  356. package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
  357. package/src/resources/extensions/gsd/prompts/complete-milestone.md +19 -19
  358. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  359. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  360. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  361. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  362. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  363. package/src/resources/extensions/gsd/quick.ts +37 -2
  364. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  365. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  366. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +33 -0
  367. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +155 -5
  368. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
  369. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
  370. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  371. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  372. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  373. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  374. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  375. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  376. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +112 -6
  377. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +40 -2
  378. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  379. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +2 -2
  380. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  381. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  382. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  383. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  384. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  385. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  386. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  387. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  388. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  389. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  390. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  391. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
  392. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  393. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  394. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  395. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  396. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  397. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  398. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  399. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  400. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
  401. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  402. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  403. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  404. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  405. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  406. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
  407. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  408. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
  409. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  410. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  411. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
  412. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  413. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  414. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
  415. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  416. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  417. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  418. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  419. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  420. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  421. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  422. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  423. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  424. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  425. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  426. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  427. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
  428. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  429. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  430. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  431. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  432. package/packages/contracts/tsconfig.tsbuildinfo +0 -1
  433. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → 8F5YpnZNBaooIWGF4GBV3}/_buildManifest.js +0 -0
  434. /package/dist/web/standalone/.next/static/{bQDK5_LtkGVS64AirQgQG → 8F5YpnZNBaooIWGF4GBV3}/_ssgManifest.js +0 -0
@@ -1,3 +1,5 @@
1
+ // GSD-2 + src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts - Handles provider and agent-end recovery for GSD auto-mode.
2
+
1
3
  import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
2
4
 
3
5
  import { logWarning } from "../workflow-logger.js";
@@ -12,7 +14,7 @@ import { clearPathCache } from "../paths.js";
12
14
  import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
13
15
  import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
14
16
  import { pauseAutoForProviderError } from "../provider-error-pause.js";
15
- import { isSessionSwitchInFlight, resolveAgentEnd } from "../auto/resolve.js";
17
+ import { isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled } from "../auto/resolve.js";
16
18
  import { resolveModelId } from "../auto-model-selection.js";
17
19
  import { resolveProjectRoot } from "../worktree.js";
18
20
  import { clearDiscussionFlowState } from "./write-gate.js";
@@ -69,6 +71,11 @@ export function _buildAbortedPauseContext(lastMsg: { errorMessage?: unknown }):
69
71
  };
70
72
  }
71
73
 
74
+ export function isUserInitiatedAbortMessage(message: string | undefined | null): boolean {
75
+ if (!message) return false;
76
+ return /\b(?:claude code process aborted by user|request aborted by user|process aborted by user)\b/i.test(message);
77
+ }
78
+
72
79
  async function pauseTransientWithBackoff(
73
80
  cls: ErrorClass,
74
81
  pi: ExtensionAPI,
@@ -146,9 +153,29 @@ export async function handleAgentEnd(
146
153
  if (maybeHandleEmptyIntentTurn(event, isAutoActive())) return;
147
154
 
148
155
  if (!isAutoActive()) return;
149
- if (isSessionSwitchInFlight()) return;
150
156
 
151
157
  const lastMsg = event.messages[event.messages.length - 1];
158
+ if (isSessionSwitchInFlight()) {
159
+ if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
160
+ const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
161
+ if (isUserInitiatedAbortMessage(rawErrorMsg)) {
162
+ resolveAgentEndCancelled({
163
+ message: rawErrorMsg,
164
+ category: "aborted",
165
+ isTransient: false,
166
+ });
167
+ }
168
+ } else if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
169
+ const content = "content" in lastMsg ? lastMsg.content : undefined;
170
+ const hasEmptyContent = Array.isArray(content) && content.length === 0;
171
+ const hasErrorMessage = "errorMessage" in lastMsg && !!lastMsg.errorMessage;
172
+ if (!hasEmptyContent || hasErrorMessage) {
173
+ resolveAgentEndCancelled(_buildAbortedPauseContext(lastMsg as { errorMessage?: unknown }));
174
+ }
175
+ }
176
+ return;
177
+ }
178
+
152
179
  if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
153
180
  // Empty content with aborted stopReason is a non-fatal agent stop (the LLM
154
181
  // chose to end without producing output). Only pause on genuine fatal aborts
@@ -180,6 +207,14 @@ export async function handleAgentEnd(
180
207
  // is in the assistant message text content. Fall back to content when
181
208
  // errorMessage looks uninformative.
182
209
  const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
210
+ if (isUserInitiatedAbortMessage(rawErrorMsg)) {
211
+ resolveAgentEndCancelled({
212
+ message: rawErrorMsg,
213
+ category: "aborted",
214
+ isTransient: false,
215
+ });
216
+ return;
217
+ }
183
218
  const isUseless = !rawErrorMsg || /^(success|ok|true|error|unknown)$/i.test(rawErrorMsg.trim());
184
219
  // #3588: When errorMessage is uninformative, extract the real error from
185
220
  // the assistant message text content for display purposes only.
@@ -6,23 +6,36 @@
6
6
  import { Type } from "@sinclair/typebox";
7
7
  import type { ExtensionAPI } from "@gsd/pi-coding-agent";
8
8
 
9
+ async function loadContextModePreferences(baseDir: string) {
10
+ const [{ loadEffectiveGSDPreferences }, { logWarning }] = await Promise.all([
11
+ import("../preferences.js"),
12
+ import("../workflow-logger.js"),
13
+ ]);
14
+ try {
15
+ return loadEffectiveGSDPreferences(baseDir)?.preferences ?? null;
16
+ } catch (err) {
17
+ logWarning("tool", `Context Mode tool could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
18
+ return null;
19
+ }
20
+ }
21
+
9
22
  export function registerExecTools(pi: ExtensionAPI): void {
10
23
  pi.registerTool({
11
24
  name: "gsd_exec",
12
25
  label: "Exec (Sandboxed)",
13
26
  description:
14
- "Run a short script (bash/node/python) in a subprocess. Full stdout/stderr persist to " +
27
+ "Run a short script (bash/node/python) in a subprocess. Capped stdout/stderr and metadata persist to " +
15
28
  ".gsd/exec/<id>.{stdout,stderr,meta.json}; only a short digest returns in context. Use " +
16
29
  "this instead of reading many files or emitting large tool outputs — e.g. have the script " +
17
30
  "count/grep/summarize and log the finding. Enabled by default; opt out via " +
18
31
  "preferences.context_mode.enabled=false.",
19
32
  promptSnippet:
20
- "Run a bash/node/python script in a sandbox; full output is saved to disk and only a digest returns",
33
+ "Run a bash/node/python script in a sandbox; capped output is saved to disk and only a digest returns",
21
34
  promptGuidelines: [
22
35
  "Prefer gsd_exec for analyses that would otherwise read >3 files or produce large tool output.",
23
36
  "Write scripts that log the finding (counts, matches, summaries) rather than raw dumps.",
24
37
  "The digest is the last ~300 chars of stdout — size your log output accordingly.",
25
- "Need the full output? Read the stdout_path returned in details (file on local disk).",
38
+ "Need persisted output? Read the stdout_path returned in details (file on local disk).",
26
39
  ],
27
40
  parameters: Type.Object({
28
41
  runtime: Type.Union(
@@ -40,20 +53,11 @@ export function registerExecTools(pi: ExtensionAPI): void {
40
53
  ),
41
54
  }),
42
55
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
43
- const [{ executeGsdExec }, { loadEffectiveGSDPreferences }, { logWarning }] = await Promise.all([
44
- import("../tools/exec-tool.js"),
45
- import("../preferences.js"),
46
- import("../workflow-logger.js"),
47
- ]);
48
- let prefs: ReturnType<typeof loadEffectiveGSDPreferences> | null = null;
49
- try {
50
- prefs = loadEffectiveGSDPreferences();
51
- } catch (err) {
52
- logWarning("tool", `gsd_exec could not load preferences: ${err instanceof Error ? err.message : String(err)}`);
53
- }
56
+ const { executeGsdExec } = await import("../tools/exec-tool.js");
57
+ const baseDir = process.cwd();
54
58
  return executeGsdExec(params as Parameters<typeof executeGsdExec>[0], {
55
- baseDir: process.cwd(),
56
- preferences: prefs?.preferences ?? null,
59
+ baseDir,
60
+ preferences: await loadContextModePreferences(baseDir),
57
61
  });
58
62
  },
59
63
  });
@@ -67,7 +71,7 @@ export function registerExecTools(pi: ExtensionAPI): void {
67
71
  promptSnippet: "Search prior gsd_exec runs by substring, runtime, or failing-only filter",
68
72
  promptGuidelines: [
69
73
  "Use this before re-running an expensive analysis — the prior run's stdout file may still answer.",
70
- "The preview shows the trailing ~300 chars of stdout; read stdout_path for the full transcript.",
74
+ "The preview shows the trailing ~300 chars of stdout; read stdout_path for persisted output.",
71
75
  ],
72
76
  parameters: Type.Object({
73
77
  query: Type.Optional(Type.String({ description: "Substring matched against id and purpose (case-insensitive)." })),
@@ -81,8 +85,10 @@ export function registerExecTools(pi: ExtensionAPI): void {
81
85
  }),
82
86
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
83
87
  const { executeExecSearch } = await import("../tools/exec-search-tool.js");
88
+ const baseDir = process.cwd();
84
89
  return executeExecSearch(params as Parameters<typeof executeExecSearch>[0], {
85
- baseDir: process.cwd(),
90
+ baseDir,
91
+ preferences: await loadContextModePreferences(baseDir),
86
92
  });
87
93
  },
88
94
  });
@@ -102,8 +108,10 @@ export function registerExecTools(pi: ExtensionAPI): void {
102
108
  parameters: Type.Object({}),
103
109
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
104
110
  const { executeResume } = await import("../tools/resume-tool.js");
111
+ const baseDir = process.cwd();
105
112
  return executeResume(params as Parameters<typeof executeResume>[0], {
106
- baseDir: process.cwd(),
113
+ baseDir,
114
+ preferences: await loadContextModePreferences(baseDir),
107
115
  });
108
116
  },
109
117
  });
@@ -7,7 +7,7 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
7
7
  import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
8
8
 
9
9
  import { buildMilestoneFileName, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
10
- import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
10
+ import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
11
11
  import { resolveManifest } from "../unit-context-manifest.js";
12
12
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
13
13
  import { loadFile, saveFile, formatContinue } from "../files.js";
@@ -65,6 +65,26 @@ async function applyDisabledModelProviderPolicy(ctx: ExtensionContext): Promise<
65
65
  }
66
66
  }
67
67
 
68
+ /**
69
+ * Bridge `context_management.compaction_threshold_percent` from GSD preferences
70
+ * into the agent's runtime compaction settings (#5475). The preference is
71
+ * validated to (0.5, 0.95) at load time, but defense-in-depth normalization
72
+ * here protects against a stale or hand-edited prefs file. Calling with
73
+ * `undefined` clears any prior override so a removed preference does not leak.
74
+ */
75
+ async function applyCompactionThresholdOverride(ctx: ExtensionContext): Promise<void> {
76
+ try {
77
+ const { loadEffectiveGSDPreferences } = await import("../preferences.js");
78
+ const prefs = loadEffectiveGSDPreferences();
79
+ const raw = prefs?.preferences.context_management?.compaction_threshold_percent;
80
+ const value =
81
+ typeof raw === "number" && Number.isFinite(raw) && raw > 0 && raw < 1 ? raw : undefined;
82
+ ctx.setCompactionThresholdOverride(value);
83
+ } catch {
84
+ // Non-fatal: leave any existing override in place.
85
+ }
86
+ }
87
+
68
88
  export function resolveNotificationStoreBasePath(cwd: string = process.cwd()): string {
69
89
  return resolveWorktreeProjectRoot(cwd);
70
90
  }
@@ -123,6 +143,7 @@ export function registerHooks(
123
143
  await resetAskUserQuestionsTurnCache();
124
144
  await syncServiceTierStatus(ctx);
125
145
  await applyDisabledModelProviderPolicy(ctx);
146
+ await applyCompactionThresholdOverride(ctx);
126
147
  // Skip MCP auto-prep when running inside an auto-worktree (see session_switch below).
127
148
  const { isInAutoWorktree } = await import("../auto-worktree.js");
128
149
  if (!isInAutoWorktree(process.cwd())) {
@@ -172,6 +193,7 @@ export function registerHooks(
172
193
  clearDiscussionFlowState(process.cwd());
173
194
  await syncServiceTierStatus(ctx);
174
195
  await applyDisabledModelProviderPolicy(ctx);
196
+ await applyCompactionThresholdOverride(ctx);
175
197
  // Skip MCP auto-prep when running inside an auto-worktree. The worktree
176
198
  // already has .mcp.json from createAutoWorktree, and re-running the writer
177
199
  // post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
@@ -482,6 +504,22 @@ export function registerHooks(
482
504
  }
483
505
  }
484
506
 
507
+ // ── Worktree-isolation write gate (#5199) ────────────────────────────
508
+ // Block planning-write tools from landing code at the project root when
509
+ // git.isolation=worktree but auto-mode hasn't created the milestone
510
+ // worktree yet. Without this, writes silently orphan outside git history.
511
+ if (isToolCallEventType("write", event) || isToolCallEventType("edit", event)) {
512
+ const wtBasePath = resolveWorktreeProjectRoot(dash.basePath ?? discussionBasePath);
513
+ const wtGuard = shouldBlockWorktreeWrite(
514
+ event.toolName,
515
+ event.input.path,
516
+ wtBasePath,
517
+ isAutoActive(),
518
+ dash.currentUnit?.type,
519
+ );
520
+ if (wtGuard.block) return wtGuard;
521
+ }
522
+
485
523
  // ── Single-writer engine: block direct writes to STATE.md ──────────
486
524
  // Covers write, edit, and bash tools to prevent bypass vectors.
487
525
  if (isToolCallEventType("write", event)) {
@@ -1,10 +1,12 @@
1
- import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
1
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
3
 
4
4
  import { minimatch } from "minimatch";
5
5
 
6
+ import { getIsolationMode } from "../preferences.js";
6
7
  import type { ToolsPolicy } from "../unit-context-manifest.js";
7
8
  import { logWarning } from "../workflow-logger.js";
9
+ import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
8
10
 
9
11
  /**
10
12
  * Regex matching milestone CONTEXT.md file names in both legacy M001
@@ -882,3 +884,135 @@ export function shouldBlockPlanningUnit(
882
884
  // avoids breaking gsd_* MCP tools or future safe additions.
883
885
  return { block: false };
884
886
  }
887
+
888
+ // ─── Worktree isolation write gate (#5199) ────────────────────────────────
889
+ //
890
+ // When `git.isolation: worktree` is configured, the per-unit commit pipeline
891
+ // only runs inside the auto-mode loop (`auto-post-unit.ts`). If the LLM
892
+ // authors code at the project root before auto-mode is started, those writes
893
+ // land in the working tree but never reach a commit — they're silently
894
+ // orphaned outside git history. This guard blocks those writes at the
895
+ // tool_call seam so the agent receives a clear error instead.
896
+
897
+ const WORKTREE_GATE_BOOTSTRAP_UNITS = new Set([
898
+ "discuss-milestone",
899
+ "plan-milestone",
900
+ "init",
901
+ ]);
902
+
903
+ function realpathOrResolve(p: string): string {
904
+ const abs = resolve(p);
905
+ try {
906
+ return realpathSync(abs);
907
+ } catch {
908
+ // Path doesn't exist (yet) — realpath the deepest existing ancestor so
909
+ // platforms where /tmp -> /private/tmp don't break containment checks.
910
+ let dir = abs;
911
+ const tail: string[] = [];
912
+ while (dir && dir !== resolve(dir, "..")) {
913
+ try {
914
+ const real = realpathSync(dir);
915
+ return tail.length ? join(real, ...tail.reverse()) : real;
916
+ } catch {
917
+ const idx = dir.lastIndexOf(sep);
918
+ if (idx <= 0) break;
919
+ tail.push(dir.slice(idx + 1));
920
+ dir = dir.slice(0, idx) || sep;
921
+ }
922
+ }
923
+ return abs;
924
+ }
925
+ }
926
+
927
+ function isPathContained(target: string, container: string): boolean {
928
+ if (target === container) return true;
929
+ return target.startsWith(container.endsWith(sep) ? container : container + sep);
930
+ }
931
+
932
+ /**
933
+ * Block planning-write tool calls that would land code at the project root
934
+ * while `git.isolation: worktree` is in effect and auto-mode hasn't created
935
+ * (or flipped cwd into) the milestone worktree.
936
+ *
937
+ * Pure / unit-testable. Callers in `register-hooks.ts` supply the resolved
938
+ * project root and current auto liveness; this function does no I/O beyond
939
+ * realpath resolution.
940
+ *
941
+ * Allow rules (in order):
942
+ * 1. Tool isn't a planning-write (write/edit/multi_edit/notebook_edit).
943
+ * 2. `GSD_DISABLE_WORKTREE_WRITE_GUARD=1` self-hosting bypass.
944
+ * 3. Isolation mode is not "worktree".
945
+ * 4. Active unit is a bootstrap unit (discuss-milestone/plan-milestone/init).
946
+ * 5. Target is inside `<projectRoot>/.gsd/worktrees/` (a real worktree).
947
+ * 6. Target is inside `<projectRoot>/.gsd/` and isn't masquerading as a
948
+ * worktrees sibling (rejects the `.gsd/worktrees-extra/…` prefix trick).
949
+ * 7. Auto is live AND `effectiveBasePath` is itself a `.gsd/worktrees/…` path.
950
+ *
951
+ * Otherwise: block with a message that points the agent at `/gsd` to start
952
+ * auto-mode.
953
+ */
954
+ export function shouldBlockWorktreeWrite(
955
+ toolName: string,
956
+ targetPath: string,
957
+ effectiveBasePath: string,
958
+ isAutoLive: boolean,
959
+ currentUnitType?: string | null,
960
+ ): { block: boolean; reason?: string } {
961
+ const tool = canonicalToolName(toolName);
962
+ if (!PLANNING_WRITE_TOOLS.has(tool)) return { block: false };
963
+ if (process.env.GSD_DISABLE_WORKTREE_WRITE_GUARD === "1") return { block: false };
964
+ if (getIsolationMode(effectiveBasePath) !== "worktree") return { block: false };
965
+ if (currentUnitType && WORKTREE_GATE_BOOTSTRAP_UNITS.has(currentUnitType)) return { block: false };
966
+
967
+ if (!targetPath) {
968
+ return {
969
+ block: true,
970
+ reason: [
971
+ `HARD BLOCK: ${tool} called with empty path while \`git.isolation: worktree\` is configured`,
972
+ `and auto-mode is not active. Refusing to allow writes that cannot be located.`,
973
+ ].join(" "),
974
+ };
975
+ }
976
+
977
+ // Resolve the target relative to the project root, then realpath to defeat
978
+ // symlink-based escapes and prefix tricks (e.g. .gsd/worktrees-extra/).
979
+ const projectRoot = resolveWorktreeProjectRoot(effectiveBasePath);
980
+ const absTarget = isAbsolute(targetPath) ? targetPath : resolve(projectRoot, targetPath);
981
+ const realTarget = realpathOrResolve(absTarget);
982
+ const realRoot = realpathOrResolve(projectRoot);
983
+ const realGsd = realpathOrResolve(join(projectRoot, ".gsd"));
984
+ const realWorktreesDir = realpathOrResolve(join(projectRoot, ".gsd", "worktrees"));
985
+
986
+ // Allow writes inside the legitimate worktrees subtree.
987
+ if (isPathContained(realTarget, realWorktreesDir)) return { block: false };
988
+
989
+ // Allow writes to .gsd/ planning artifacts, but reject siblings whose name
990
+ // starts with "worktrees" (the worktrees-extra prefix trick — case 4).
991
+ if (isPathContained(realTarget, realGsd)) {
992
+ const rel = relative(realGsd, realTarget);
993
+ const firstSeg = rel.split(/[\/\\]/)[0] ?? "";
994
+ if (!firstSeg.startsWith("worktrees")) return { block: false };
995
+ // fall through: looks like worktrees<something> sibling — block
996
+ }
997
+
998
+ // Auto is live and the caller is operating inside a worktree path —
999
+ // host tool's write happens in worktree context; let it through.
1000
+ if (isAutoLive && isGsdWorktreePath(effectiveBasePath)) return { block: false };
1001
+
1002
+ // Block. Provide enough context that the agent can self-correct.
1003
+ const displayTarget = isPathContained(realTarget, realRoot)
1004
+ ? relative(realRoot, realTarget) || "."
1005
+ : realTarget;
1006
+ return {
1007
+ block: true,
1008
+ reason: [
1009
+ `HARD BLOCK: Worktree isolation is configured (\`git.isolation: worktree\`) but auto-mode is`,
1010
+ `not running and the target "${displayTarget}" is not inside \`.gsd/worktrees/<MID>/\`.`,
1011
+ `Code edits at the project root would be lost — only the auto-mode commit pipeline`,
1012
+ `(auto-post-unit) commits work, and it never runs outside the loop.`,
1013
+ `Required action: start auto-mode with \`/gsd\` so the milestone worktree is created,`,
1014
+ `then write inside it. To disable this guard for self-hosting development, set`,
1015
+ `GSD_DISABLE_WORKTREE_WRITE_GUARD=1.`,
1016
+ ].join(" "),
1017
+ };
1018
+ }
@@ -21,10 +21,34 @@ import { nativeHasChanges } from "./native-git-bridge.js";
21
21
  export interface PreflightResult {
22
22
  /** true when a stash was pushed and postflightPopStash should be called */
23
23
  stashPushed: boolean;
24
+ /** Unique marker embedded in the stash message for targeted restoration */
25
+ stashMarker?: string;
24
26
  /** human-readable summary of what happened (empty string for clean trees) */
25
27
  summary: string;
26
28
  }
27
29
 
30
+ function findPreflightStashRef(basePath: string, milestoneId: string, stashMarker?: string): string | null {
31
+ const markerPrefix = `gsd-preflight-stash:${milestoneId}:`;
32
+ let fallbackRef: string | null = null;
33
+ try {
34
+ const list = execFileSync("git", ["stash", "list", "--format=%gd%x00%s"], {
35
+ cwd: basePath,
36
+ stdio: ["ignore", "pipe", "pipe"],
37
+ encoding: "utf-8",
38
+ env: GIT_NO_PROMPT_ENV,
39
+ });
40
+ for (const line of list.split("\n")) {
41
+ const [ref, subject] = line.split("\x00");
42
+ if (!ref || !subject) continue;
43
+ if (stashMarker && subject.includes(stashMarker)) return ref;
44
+ if (!fallbackRef && subject.includes(markerPrefix)) fallbackRef = ref;
45
+ }
46
+ } catch (err) {
47
+ logWarning("preflight", `stash list failed before restore: ${err instanceof Error ? err.message : String(err)}`);
48
+ }
49
+ return fallbackRef;
50
+ }
51
+
28
52
  /**
29
53
  * Check the working tree for dirty files before a milestone merge.
30
54
  *
@@ -62,7 +86,8 @@ export function preflightCleanRoot(
62
86
 
63
87
  // Push the stash
64
88
  try {
65
- execFileSync("git", ["stash", "push", "--include-untracked", "-m", "gsd-preflight-stash"], {
89
+ const stashMarker = `gsd-preflight-stash:${milestoneId}:${process.pid}:${Date.now()}:${process.hrtime.bigint().toString(36)}`;
90
+ execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd-preflight-stash [${stashMarker}]`], {
66
91
  cwd: basePath,
67
92
  stdio: ["ignore", "pipe", "pipe"],
68
93
  encoding: "utf-8",
@@ -70,6 +95,7 @@ export function preflightCleanRoot(
70
95
  });
71
96
  return {
72
97
  stashPushed: true,
98
+ stashMarker,
73
99
  summary: `Stashed uncommitted changes before merge (milestone ${milestoneId}).`,
74
100
  };
75
101
  } catch (err) {
@@ -91,10 +117,19 @@ export function preflightCleanRoot(
91
117
  export function postflightPopStash(
92
118
  basePath: string,
93
119
  milestoneId: string,
120
+ stashMarker: string | undefined,
94
121
  notify: (message: string, level: "info" | "warning" | "error") => void,
95
122
  ): void {
123
+ let stashRef: string | null = null;
96
124
  try {
97
- execFileSync("git", ["stash", "pop"], {
125
+ stashRef = findPreflightStashRef(basePath, milestoneId, stashMarker);
126
+ if (!stashRef) {
127
+ const msg = `No matching GSD preflight stash found for milestone ${milestoneId}; leaving stash list untouched.`;
128
+ logWarning("preflight", msg);
129
+ notify(msg, "warning");
130
+ return;
131
+ }
132
+ execFileSync("git", ["stash", "pop", stashRef], {
98
133
  cwd: basePath,
99
134
  stdio: ["ignore", "pipe", "pipe"],
100
135
  encoding: "utf-8",
@@ -104,7 +139,10 @@ export function postflightPopStash(
104
139
  } catch (err) {
105
140
  // Pop conflicts mean the merged code collides with the stashed changes.
106
141
  // Log a warning — the user needs to resolve manually, but the merge succeeded.
107
- const msg = `git stash pop failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. Run "git stash pop" manually to restore your changes.`;
142
+ const restoreHint = stashRef
143
+ ? `Run "git stash pop ${stashRef}" or "git stash apply ${stashRef}" manually to restore the correct stash.`
144
+ : `Run "git stash list" to find the matching GSD preflight stash before restoring manually.`;
145
+ const msg = `git stash pop ${stashRef ?? ""}`.trim() + ` failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. ${restoreHint}`;
108
146
  logWarning("preflight", msg);
109
147
  notify(msg, "warning");
110
148
  }
@@ -45,5 +45,11 @@ export async function handleGSDCommand(
45
45
 
46
46
  if (handled) return;
47
47
 
48
+ if (trimmed.includes(" ")) {
49
+ const { handleDo } = await import("../commands-do.js");
50
+ await handleDo(trimmed, ctx, pi);
51
+ return;
52
+ }
53
+
48
54
  ctx.ui.notify(`Unknown: /gsd ${trimmed}. Run /gsd help for available commands.`, "warning");
49
55
  }
@@ -222,14 +222,19 @@ Using the \`write\` tool, persist the full structured report to
222
222
  LEARNINGS.md is the full, cited audit trail. Write it first — subsequent steps
223
223
  feed from its content.
224
224
 
225
- ### Step 3 — Optionally pre-query the memory store for semantic duplicates
225
+ ### Step 3 — Run one bounded duplicate check
226
226
 
227
- Before persisting any extracted item in Steps 4–6, you may call
228
- \`memory_query\` with 2–3 keywords from the item to check whether the
229
- memory store already holds a semantically equivalent entry at high
230
- confidence. Skip those items in their respective steps. The memory store
231
- is the single source of truth for cross-session durable knowledge — no
232
- other persistence call is part of this flow.
227
+ Before persisting extracted items in Steps 4–6, do at most one duplicate-check
228
+ pass for the durable Decisions, Lessons, and Patterns from this milestone. Use
229
+ the already-written LEARNINGS.md content and call \`memory_query\` once with a
230
+ compact keyword summary for the whole batch. If that result clearly shows a
231
+ semantically equivalent high-confidence memory for an item, mark only that item
232
+ as already captured and skip it in its respective persistence step.
233
+
234
+ Do not re-read milestone artefacts or repeat memory queries category-by-category
235
+ after this point. The memory store is the single source of truth for
236
+ cross-session durable knowledge — no other persistence call is part of this
237
+ flow.
233
238
 
234
239
  ### Step 4 — Persist Patterns via \`capture_thought\`
235
240
 
@@ -268,11 +273,11 @@ later projection back to a human-visible decisions register stays lossless
268
273
 
269
274
  ### Step 7 — Deduplication rule (applies to Steps 4, 5, 6)
270
275
 
271
- Before each \`capture_thought\` call, optionally call \`memory_query\` with 2–3
272
- keywords from the entry. If a semantically equivalent memory is returned at
273
- high confidence, skip the capture entirely. Prefer skipping a near-duplicate
274
- over creating a second slightly-different row — redundancy degrades the
275
- signal.
276
+ Use only the duplicate-check result from Step 3. If that bounded check returned
277
+ a semantically equivalent memory at high confidence for an extracted item, skip
278
+ the capture entirely. Otherwise, persist the item once via \`capture_thought\`.
279
+ Prefer skipping a near-duplicate over creating a second slightly-different row
280
+ — redundancy degrades the signal.
276
281
 
277
282
  ### Step 8 — Surprises stay only in LEARNINGS.md
278
283
 
@@ -8,7 +8,12 @@
8
8
  * @see D001 (module location), D002 (200K fallback), D003 (section-boundary truncation)
9
9
  */
10
10
 
11
- import { type TokenProvider, getCharsPerToken } from "./token-counter.js";
11
+ import {
12
+ type TokenProvider,
13
+ getCharsPerToken,
14
+ isAccurateCountingAvailable,
15
+ countTokensSync,
16
+ } from "./token-counter.js";
12
17
 
13
18
  // ─── Budget ratio constants ──────────────────────────────────────────────────
14
19
  // Percentages of total context window allocated to each budget category.
@@ -32,6 +37,24 @@ const DEFAULT_CONTEXT_WINDOW = 200_000;
32
37
  /** Conservative effective context for Claude Code subscription routing (#4676) */
33
38
  const CLAUDE_CODE_EFFECTIVE_CONTEXT_WINDOW = 200_000;
34
39
 
40
+ /**
41
+ * Cached empirical chars-per-token from a tiktoken probe, keyed by provider.
42
+ * countTokensSync's fallback path is provider-aware, so we cache per-provider
43
+ * to preserve that distinction once the encoder warms. The cl100k_base encoder
44
+ * itself gives a stable ratio for ASCII English so a single probe per provider
45
+ * key is sufficient. Empty map means "not yet probed" or "encoder unavailable".
46
+ */
47
+ const _empiricalCharsPerTokenByProvider = new Map<string, number>();
48
+
49
+ /**
50
+ * Test hook — clears the empirical chars-per-token cache so test cases that
51
+ * assert against the static char-ratio fallback aren't polluted by a prior
52
+ * tiktoken-warmed run in the same process. Production code must not call this.
53
+ */
54
+ export function _resetEmpiricalCacheForTest(): void {
55
+ _empiricalCharsPerTokenByProvider.clear();
56
+ }
57
+
35
58
  /** Percentage of context consumed before suggesting a continue-here checkpoint */
36
59
  const CONTINUE_THRESHOLD_PERCENT = 70;
37
60
 
@@ -101,7 +124,26 @@ export interface MinimalPreferences {
101
124
  export function computeBudgets(contextWindow: number, provider?: TokenProvider): BudgetAllocation {
102
125
  const effectiveWindow = contextWindow > 0 ? contextWindow : DEFAULT_CONTEXT_WINDOW;
103
126
  const charsPerToken = provider ? getCharsPerToken(provider) : CHARS_PER_TOKEN;
104
- const totalChars = effectiveWindow * charsPerToken;
127
+
128
+ // Prefer the tiktoken encoder for total-char estimation when it has been
129
+ // warmed (initTokenCounter resolved). The cl100k_base ratio is stable for
130
+ // ASCII English, so probe once per provider and cache — computeBudgets is
131
+ // called multiple times per prompt build and the probe encode is otherwise
132
+ // wasted work.
133
+ let totalChars: number;
134
+ if (isAccurateCountingAvailable()) {
135
+ const providerKey = provider ?? "__default__";
136
+ let empirical = _empiricalCharsPerTokenByProvider.get(providerKey);
137
+ if (empirical === undefined) {
138
+ const probe = "the quick brown fox jumps over the lazy dog ".repeat(64);
139
+ const probeTokens = countTokensSync(probe, provider);
140
+ empirical = probeTokens > 0 ? probe.length / probeTokens : charsPerToken;
141
+ _empiricalCharsPerTokenByProvider.set(providerKey, empirical);
142
+ }
143
+ totalChars = effectiveWindow * empirical;
144
+ } else {
145
+ totalChars = effectiveWindow * charsPerToken;
146
+ }
105
147
 
106
148
  return {
107
149
  summaryBudgetChars: Math.floor(totalChars * SUMMARY_RATIO),