gsd-pi 2.34.0-dev.ed0bfbf → 2.35.0-dev.30eec3f

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 (334) hide show
  1. package/dist/cli.js +7 -2
  2. package/dist/resource-loader.d.ts +1 -1
  3. package/dist/resource-loader.js +13 -1
  4. package/dist/resources/extensions/async-jobs/await-tool.js +0 -2
  5. package/dist/resources/extensions/async-jobs/job-manager.js +0 -6
  6. package/dist/resources/extensions/bg-shell/output-formatter.js +1 -19
  7. package/dist/resources/extensions/bg-shell/process-manager.js +0 -4
  8. package/dist/resources/extensions/bg-shell/types.js +0 -2
  9. package/dist/resources/extensions/context7/index.js +5 -0
  10. package/dist/resources/extensions/get-secrets-from-user.js +2 -30
  11. package/dist/resources/extensions/google-search/index.js +5 -0
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +43 -1
  13. package/dist/resources/extensions/gsd/auto-loop.js +10 -1
  14. package/dist/resources/extensions/gsd/auto-recovery.js +35 -0
  15. package/dist/resources/extensions/gsd/auto-start.js +35 -2
  16. package/dist/resources/extensions/gsd/auto.js +59 -4
  17. package/dist/resources/extensions/gsd/changelog.js +162 -0
  18. package/dist/resources/extensions/gsd/commands-bootstrap.js +1 -0
  19. package/dist/resources/extensions/gsd/commands-handlers.js +2 -2
  20. package/dist/resources/extensions/gsd/commands-inspect.js +10 -3
  21. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +5 -1
  22. package/dist/resources/extensions/gsd/commands.js +8 -1
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  24. package/dist/resources/extensions/gsd/doctor-checks.js +113 -5
  25. package/dist/resources/extensions/gsd/doctor-environment.js +26 -17
  26. package/dist/resources/extensions/gsd/doctor-proactive.js +22 -0
  27. package/dist/resources/extensions/gsd/doctor.js +36 -0
  28. package/dist/resources/extensions/gsd/files.js +11 -2
  29. package/dist/resources/extensions/gsd/gitignore.js +54 -7
  30. package/dist/resources/extensions/gsd/guided-flow.js +5 -3
  31. package/dist/resources/extensions/gsd/health-widget-core.js +96 -0
  32. package/dist/resources/extensions/gsd/health-widget.js +97 -46
  33. package/dist/resources/extensions/gsd/index.js +10 -1
  34. package/dist/resources/extensions/gsd/migrate-external.js +55 -2
  35. package/dist/resources/extensions/gsd/paths.js +74 -7
  36. package/dist/resources/extensions/gsd/post-unit-hooks.js +4 -1
  37. package/dist/resources/extensions/gsd/preferences-validation.js +54 -1
  38. package/dist/resources/extensions/gsd/preferences.js +2 -0
  39. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  40. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  41. package/dist/resources/extensions/gsd/roadmap-mutations.js +55 -0
  42. package/dist/resources/extensions/gsd/session-lock.js +26 -2
  43. package/dist/resources/extensions/gsd/templates/plan.md +8 -0
  44. package/dist/resources/extensions/gsd/worktree-resolver.js +12 -0
  45. package/dist/resources/extensions/remote-questions/remote-command.js +2 -22
  46. package/dist/resources/extensions/shared/mod.js +1 -1
  47. package/dist/resources/extensions/shared/sanitize.js +30 -0
  48. package/dist/resources/extensions/subagent/index.js +6 -14
  49. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  50. package/package.json +2 -1
  51. package/packages/pi-agent-core/dist/agent-loop.d.ts +14 -0
  52. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  53. package/packages/pi-agent-core/dist/agent-loop.js +24 -27
  54. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  55. package/packages/pi-agent-core/dist/agent.d.ts +1 -0
  56. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  57. package/packages/pi-agent-core/dist/agent.js +11 -22
  58. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  59. package/packages/pi-agent-core/dist/proxy.d.ts.map +1 -1
  60. package/packages/pi-agent-core/dist/proxy.js +2 -8
  61. package/packages/pi-agent-core/dist/proxy.js.map +1 -1
  62. package/packages/pi-agent-core/src/agent-loop.ts +30 -27
  63. package/packages/pi-agent-core/src/agent.ts +12 -23
  64. package/packages/pi-agent-core/src/proxy.ts +2 -8
  65. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  66. package/packages/pi-ai/dist/providers/azure-openai-responses.js +5 -41
  67. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  68. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  69. package/packages/pi-ai/dist/providers/openai-completions.js +10 -73
  70. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  71. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  72. package/packages/pi-ai/dist/providers/openai-responses.js +9 -80
  73. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  74. package/packages/pi-ai/dist/providers/openai-shared.d.ts +65 -0
  75. package/packages/pi-ai/dist/providers/openai-shared.d.ts.map +1 -0
  76. package/packages/pi-ai/dist/providers/openai-shared.js +146 -0
  77. package/packages/pi-ai/dist/providers/openai-shared.js.map +1 -0
  78. package/packages/pi-ai/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  79. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js +7 -135
  80. package/packages/pi-ai/dist/utils/oauth/google-antigravity.js.map +1 -1
  81. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  82. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js +7 -135
  83. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  84. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts +46 -0
  85. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.d.ts.map +1 -0
  86. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js +160 -0
  87. package/packages/pi-ai/dist/utils/oauth/google-oauth-utils.js.map +1 -0
  88. package/packages/pi-ai/src/providers/azure-openai-responses.ts +11 -45
  89. package/packages/pi-ai/src/providers/openai-completions.ts +16 -86
  90. package/packages/pi-ai/src/providers/openai-responses.ts +16 -96
  91. package/packages/pi-ai/src/providers/openai-shared.ts +193 -0
  92. package/packages/pi-ai/src/utils/oauth/google-antigravity.ts +14 -162
  93. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.ts +13 -161
  94. package/packages/pi-ai/src/utils/oauth/google-oauth-utils.ts +201 -0
  95. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +16 -63
  96. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/agent-session.js +104 -641
  98. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +0 -1
  100. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/auth-storage.js +4 -35
  102. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  104. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js +5 -43
  105. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  106. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  107. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +11 -69
  108. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +40 -0
  110. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  111. package/packages/pi-coding-agent/dist/core/compaction/utils.js +78 -0
  112. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  113. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +77 -0
  114. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -0
  115. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +331 -0
  116. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -0
  117. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +2 -2
  118. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/extensions/index.js +1 -1
  120. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +15 -0
  122. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/runner.js +129 -243
  124. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +49 -42
  126. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/extensions/types.js +2 -21
  128. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts +39 -0
  130. package/packages/pi-coding-agent/dist/core/lock-utils.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/core/lock-utils.js +89 -0
  132. package/packages/pi-coding-agent/dist/core/lock-utils.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts +2 -0
  134. package/packages/pi-coding-agent/dist/core/lsp/config.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/lsp/config.js +4 -1
  136. package/packages/pi-coding-agent/dist/core/lsp/config.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/lsp/index.d.ts.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/lsp/index.js +52 -107
  139. package/packages/pi-coding-agent/dist/core/lsp/index.js.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/lsp/lspmux.d.ts.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js +2 -21
  142. package/packages/pi-coding-agent/dist/core/lsp/lspmux.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts +0 -1
  144. package/packages/pi-coding-agent/dist/core/lsp/types.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/lsp/types.js +0 -28
  146. package/packages/pi-coding-agent/dist/core/lsp/types.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/package-manager.js +2 -4
  149. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +2 -4
  151. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/resource-loader.js +46 -60
  153. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts +87 -0
  155. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -0
  156. package/packages/pi-coding-agent/dist/core/retry-handler.js +295 -0
  157. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -0
  158. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +0 -1
  159. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -28
  161. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +8 -0
  163. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  164. package/packages/pi-coding-agent/dist/core/settings-manager.js +76 -166
  165. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/skills.js +1 -3
  168. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  170. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  171. package/packages/pi-coding-agent/dist/index.js +1 -1
  172. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js +9 -26
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/session-selector.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -13
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts +44 -0
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.d.ts.map +1 -0
  182. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js +61 -0
  183. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-render-utils.js.map +1 -0
  184. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js +6 -9
  186. package/packages/pi-coding-agent/dist/modes/interactive/components/tree-selector.js.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +65 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  189. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +6 -16
  190. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  191. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts +12 -0
  192. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  193. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +175 -0
  194. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -0
  195. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts +6 -0
  196. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.d.ts.map +1 -0
  197. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js +15 -0
  198. package/packages/pi-coding-agent/dist/modes/interactive/utils/shorten-path.js.map +1 -0
  199. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  200. package/packages/pi-coding-agent/dist/modes/print-mode.js +2 -30
  201. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  202. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  203. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -28
  204. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  205. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts +19 -0
  206. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.d.ts.map +1 -0
  207. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js +45 -0
  208. package/packages/pi-coding-agent/dist/modes/shared/command-context-actions.js.map +1 -0
  209. package/packages/pi-coding-agent/dist/utils/error.d.ts +5 -0
  210. package/packages/pi-coding-agent/dist/utils/error.d.ts.map +1 -0
  211. package/packages/pi-coding-agent/dist/utils/error.js +7 -0
  212. package/packages/pi-coding-agent/dist/utils/error.js.map +1 -0
  213. package/packages/pi-coding-agent/package.json +1 -1
  214. package/packages/pi-coding-agent/src/core/agent-session.ts +117 -745
  215. package/packages/pi-coding-agent/src/core/auth-storage.ts +4 -38
  216. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +7 -53
  217. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +14 -74
  218. package/packages/pi-coding-agent/src/core/compaction/utils.ts +100 -0
  219. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +424 -0
  220. package/packages/pi-coding-agent/src/core/extensions/index.ts +1 -21
  221. package/packages/pi-coding-agent/src/core/extensions/runner.ts +119 -243
  222. package/packages/pi-coding-agent/src/core/extensions/types.ts +50 -69
  223. package/packages/pi-coding-agent/src/core/lock-utils.ts +113 -0
  224. package/packages/pi-coding-agent/src/core/lsp/config.ts +4 -1
  225. package/packages/pi-coding-agent/src/core/lsp/index.ts +83 -152
  226. package/packages/pi-coding-agent/src/core/lsp/lspmux.ts +2 -22
  227. package/packages/pi-coding-agent/src/core/lsp/types.ts +0 -29
  228. package/packages/pi-coding-agent/src/core/package-manager.ts +1 -4
  229. package/packages/pi-coding-agent/src/core/resource-loader.ts +56 -69
  230. package/packages/pi-coding-agent/src/core/retry-handler.ts +359 -0
  231. package/packages/pi-coding-agent/src/core/session-manager.ts +3 -30
  232. package/packages/pi-coding-agent/src/core/settings-manager.ts +85 -164
  233. package/packages/pi-coding-agent/src/core/skills.ts +1 -4
  234. package/packages/pi-coding-agent/src/index.ts +1 -7
  235. package/packages/pi-coding-agent/src/modes/interactive/components/session-selector.ts +17 -29
  236. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -13
  237. package/packages/pi-coding-agent/src/modes/interactive/components/tree-render-utils.ts +81 -0
  238. package/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts +14 -19
  239. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +7 -18
  240. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +196 -0
  241. package/packages/pi-coding-agent/src/modes/interactive/utils/shorten-path.ts +14 -0
  242. package/packages/pi-coding-agent/src/modes/print-mode.ts +2 -30
  243. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -28
  244. package/packages/pi-coding-agent/src/modes/shared/command-context-actions.ts +53 -0
  245. package/packages/pi-coding-agent/src/utils/error.ts +6 -0
  246. package/packages/pi-tui/dist/components/markdown.d.ts +5 -0
  247. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  248. package/packages/pi-tui/dist/components/markdown.js +25 -31
  249. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  250. package/packages/pi-tui/dist/keys.d.ts +0 -4
  251. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  252. package/packages/pi-tui/dist/keys.js +94 -162
  253. package/packages/pi-tui/dist/keys.js.map +1 -1
  254. package/packages/pi-tui/src/components/markdown.ts +25 -29
  255. package/packages/pi-tui/src/keys.ts +94 -173
  256. package/pkg/dist/modes/interactive/theme/theme.d.ts +65 -0
  257. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  258. package/pkg/dist/modes/interactive/theme/theme.js +6 -16
  259. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  260. package/pkg/dist/modes/interactive/theme/themes.d.ts +12 -0
  261. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -0
  262. package/pkg/dist/modes/interactive/theme/themes.js +175 -0
  263. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -0
  264. package/pkg/package.json +1 -1
  265. package/src/resources/extensions/async-jobs/await-tool.ts +0 -2
  266. package/src/resources/extensions/async-jobs/job-manager.ts +0 -7
  267. package/src/resources/extensions/bg-shell/output-formatter.ts +0 -17
  268. package/src/resources/extensions/bg-shell/process-manager.ts +0 -4
  269. package/src/resources/extensions/bg-shell/types.ts +0 -12
  270. package/src/resources/extensions/context7/index.ts +7 -0
  271. package/src/resources/extensions/get-secrets-from-user.ts +2 -35
  272. package/src/resources/extensions/google-search/index.ts +7 -0
  273. package/src/resources/extensions/gsd/auto-dispatch.ts +49 -1
  274. package/src/resources/extensions/gsd/auto-loop.ts +11 -1
  275. package/src/resources/extensions/gsd/auto-recovery.ts +39 -0
  276. package/src/resources/extensions/gsd/auto-start.ts +42 -2
  277. package/src/resources/extensions/gsd/auto.ts +61 -3
  278. package/src/resources/extensions/gsd/changelog.ts +213 -0
  279. package/src/resources/extensions/gsd/commands-bootstrap.ts +1 -0
  280. package/src/resources/extensions/gsd/commands-handlers.ts +2 -2
  281. package/src/resources/extensions/gsd/commands-inspect.ts +10 -3
  282. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +5 -1
  283. package/src/resources/extensions/gsd/commands.ts +9 -1
  284. package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  285. package/src/resources/extensions/gsd/doctor-checks.ts +107 -5
  286. package/src/resources/extensions/gsd/doctor-environment.ts +26 -16
  287. package/src/resources/extensions/gsd/doctor-proactive.ts +24 -0
  288. package/src/resources/extensions/gsd/doctor-types.ts +9 -1
  289. package/src/resources/extensions/gsd/doctor.ts +35 -0
  290. package/src/resources/extensions/gsd/files.ts +12 -2
  291. package/src/resources/extensions/gsd/gitignore.ts +54 -7
  292. package/src/resources/extensions/gsd/guided-flow.ts +5 -3
  293. package/src/resources/extensions/gsd/health-widget-core.ts +129 -0
  294. package/src/resources/extensions/gsd/health-widget.ts +103 -59
  295. package/src/resources/extensions/gsd/index.ts +10 -1
  296. package/src/resources/extensions/gsd/migrate-external.ts +47 -2
  297. package/src/resources/extensions/gsd/paths.ts +73 -7
  298. package/src/resources/extensions/gsd/post-unit-hooks.ts +5 -1
  299. package/src/resources/extensions/gsd/preferences-validation.ts +54 -1
  300. package/src/resources/extensions/gsd/preferences.ts +2 -0
  301. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  302. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  303. package/src/resources/extensions/gsd/roadmap-mutations.ts +66 -0
  304. package/src/resources/extensions/gsd/session-lock.ts +29 -2
  305. package/src/resources/extensions/gsd/templates/plan.md +8 -0
  306. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
  307. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +98 -2
  308. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +59 -3
  309. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +20 -0
  310. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +214 -0
  311. package/src/resources/extensions/gsd/tests/health-widget.test.ts +158 -0
  312. package/src/resources/extensions/gsd/tests/paths.test.ts +113 -0
  313. package/src/resources/extensions/gsd/tests/preferences.test.ts +40 -2
  314. package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
  315. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +15 -0
  316. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -0
  317. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +32 -0
  318. package/src/resources/extensions/gsd/worktree-resolver.ts +11 -0
  319. package/src/resources/extensions/remote-questions/remote-command.ts +2 -23
  320. package/src/resources/extensions/shared/mod.ts +1 -1
  321. package/src/resources/extensions/shared/sanitize.ts +36 -0
  322. package/src/resources/extensions/subagent/index.ts +6 -12
  323. package/src/resources/skills/create-gsd-extension/references/events-reference.md +4 -4
  324. package/dist/resources/extensions/shared/wizard-ui.js +0 -478
  325. package/packages/pi-coding-agent/dist/modes/interactive/theme/dark.json +0 -85
  326. package/packages/pi-coding-agent/dist/modes/interactive/theme/light.json +0 -84
  327. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.json +0 -335
  328. package/packages/pi-coding-agent/src/modes/interactive/theme/dark.json +0 -85
  329. package/packages/pi-coding-agent/src/modes/interactive/theme/light.json +0 -84
  330. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.json +0 -335
  331. package/pkg/dist/modes/interactive/theme/dark.json +0 -85
  332. package/pkg/dist/modes/interactive/theme/light.json +0 -84
  333. package/pkg/dist/modes/interactive/theme/theme-schema.json +0 -335
  334. package/src/resources/extensions/shared/wizard-ui.ts +0 -551
@@ -14,19 +14,21 @@
14
14
  */
15
15
  import { readFileSync } from "node:fs";
16
16
  import { basename, dirname, join } from "node:path";
17
- import { isContextOverflow, modelsAreEqual, resetApiProviders, supportsXhigh } from "@gsd/pi-ai";
17
+ import { modelsAreEqual, resetApiProviders, supportsXhigh } from "@gsd/pi-ai";
18
18
  import { getDocsPath } from "../config.js";
19
+ import { getErrorMessage } from "../utils/error.js";
19
20
  import { theme } from "../modes/interactive/theme/theme.js";
20
21
  import { stripFrontmatter } from "../utils/frontmatter.js";
21
- import { sleep } from "../utils/sleep.js";
22
22
  import { executeBash as executeBashCommand, executeBashWithOperations } from "./bash-executor.js";
23
- import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, generateBranchSummary, prepareCompaction, shouldCompact, } from "./compaction/index.js";
23
+ import { calculateContextTokens, collectEntriesForBranchSummary, estimateContextTokens, generateBranchSummary, } from "./compaction/index.js";
24
+ import { CompactionOrchestrator } from "./compaction-orchestrator.js";
24
25
  import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
25
26
  import { exportSessionToHtml } from "./export-html/index.js";
26
27
  import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
27
28
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
28
29
  import { FallbackResolver } from "./fallback-resolver.js";
29
30
  import { expandPromptTemplate } from "./prompt-templates.js";
31
+ import { RetryHandler } from "./retry-handler.js";
30
32
  import { getLatestCompactionEntry } from "./session-manager.js";
31
33
  import { BUILTIN_SLASH_COMMANDS } from "./slash-commands.js";
32
34
  import { buildSystemPrompt } from "./system-prompt.js";
@@ -66,17 +68,11 @@ export class AgentSession {
66
68
  this._followUpMessages = [];
67
69
  /** Messages queued to be included with the next user prompt as context ("asides"). */
68
70
  this._pendingNextTurnMessages = [];
69
- // Compaction state
70
- this._compactionAbortController = undefined;
71
- this._autoCompactionAbortController = undefined;
72
- this._overflowRecoveryAttempted = false;
73
- // Branch summarization state
74
- this._branchSummaryAbortController = undefined;
75
- // Retry state
76
- this._retryAbortController = undefined;
77
- this._retryAttempt = 0;
78
- this._retryPromise = undefined;
79
- this._retryResolve = undefined;
71
+ // Cumulative session stats — survives compaction (#1423)
72
+ this._cumulativeCost = 0;
73
+ this._cumulativeInputTokens = 0;
74
+ this._cumulativeOutputTokens = 0;
75
+ this._cumulativeToolCalls = 0;
80
76
  // Bash execution state
81
77
  this._bashAbortController = undefined;
82
78
  this._pendingBashMessages = [];
@@ -96,7 +92,7 @@ export class AgentSession {
96
92
  this._handleAgentEvent = (event) => {
97
93
  // Create retry promise synchronously before queueing async processing.
98
94
  // Agent.emit() calls this handler synchronously, and prompt() calls waitForRetry()
99
- // as soon as agent.prompt() resolves. If _retryPromise is created only inside
95
+ // as soon as agent.prompt() resolves. If the retry promise is created only inside
100
96
  // _processAgentEvent, slow earlier queued events can delay agent_end processing
101
97
  // and waitForRetry() can miss the in-flight retry.
102
98
  this._createRetryPromiseForAgentEnd(event);
@@ -116,6 +112,30 @@ export class AgentSession {
116
112
  this._extensionRunnerRef = config.extensionRunnerRef;
117
113
  this._initialActiveToolNames = config.initialActiveToolNames;
118
114
  this._baseToolsOverride = config.baseToolsOverride;
115
+ // Initialize delegated subsystems
116
+ this._retryHandler = new RetryHandler({
117
+ agent: this.agent,
118
+ settingsManager: this.settingsManager,
119
+ modelRegistry: this._modelRegistry,
120
+ fallbackResolver: this._fallbackResolver,
121
+ getModel: () => this.model,
122
+ getSessionId: () => this.sessionId,
123
+ emit: (event) => this._emit(event),
124
+ onModelChange: (model) => this.sessionManager.appendModelChange(model.provider, model.id),
125
+ });
126
+ this._compactionOrchestrator = new CompactionOrchestrator({
127
+ agent: this.agent,
128
+ sessionManager: this.sessionManager,
129
+ settingsManager: this.settingsManager,
130
+ modelRegistry: this._modelRegistry,
131
+ getModel: () => this.model,
132
+ getSessionId: () => this.sessionId,
133
+ getExtensionRunner: () => this._extensionRunner,
134
+ emit: (event) => this._emit(event),
135
+ disconnectFromAgent: () => this._disconnectFromAgent(),
136
+ reconnectToAgent: () => this._reconnectToAgent(),
137
+ abort: () => this.abort(),
138
+ });
119
139
  // Always subscribe to agent events for internal handling
120
140
  // (session persistence, extensions, auto-compaction, retry logic)
121
141
  this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
@@ -146,35 +166,15 @@ export class AgentSession {
146
166
  }
147
167
  }
148
168
  _createRetryPromiseForAgentEnd(event) {
149
- if (event.type !== "agent_end" || this._retryPromise) {
150
- return;
151
- }
152
- const settings = this.settingsManager.getRetrySettings();
153
- if (!settings.enabled) {
154
- return;
155
- }
156
- const lastAssistant = this._findLastAssistantInMessages(event.messages);
157
- if (!lastAssistant || !this._isRetryableError(lastAssistant)) {
169
+ if (event.type !== "agent_end")
158
170
  return;
159
- }
160
- this._retryPromise = new Promise((resolve) => {
161
- this._retryResolve = resolve;
162
- });
163
- }
164
- _findLastAssistantInMessages(messages) {
165
- for (let i = messages.length - 1; i >= 0; i--) {
166
- const message = messages[i];
167
- if (message.role === "assistant") {
168
- return message;
169
- }
170
- }
171
- return undefined;
171
+ this._retryHandler.createRetryPromiseForAgentEnd(event.messages);
172
172
  }
173
173
  async _processAgentEvent(event) {
174
174
  // When a user message starts, check if it's from either queue and remove it BEFORE emitting
175
175
  // This ensures the UI sees the updated queue state
176
176
  if (event.type === "message_start" && event.message.role === "user") {
177
- this._overflowRecoveryAttempted = false;
177
+ this._compactionOrchestrator.resetOverflowRecovery();
178
178
  const messageText = this._getUserMessageText(event.message);
179
179
  if (messageText) {
180
180
  // Check steering queue first
@@ -212,20 +212,19 @@ export class AgentSession {
212
212
  // Track assistant message for auto-compaction (checked on agent_end)
213
213
  if (event.message.role === "assistant") {
214
214
  this._lastAssistantMessage = event.message;
215
+ // Accumulate session stats that survive compaction (#1423)
215
216
  const assistantMsg = event.message;
217
+ this._cumulativeCost += assistantMsg.usage?.cost?.total ?? 0;
218
+ this._cumulativeInputTokens += assistantMsg.usage?.input ?? 0;
219
+ this._cumulativeOutputTokens += assistantMsg.usage?.output ?? 0;
220
+ this._cumulativeToolCalls += assistantMsg.content.filter((c) => c.type === "toolCall").length;
216
221
  if (assistantMsg.stopReason !== "error") {
217
- this._overflowRecoveryAttempted = false;
222
+ this._compactionOrchestrator.clearOverflowRecovery();
218
223
  }
219
224
  // Reset retry counter immediately on successful assistant response
220
225
  // This prevents accumulation across multiple LLM calls within a turn
221
- if (assistantMsg.stopReason !== "error" && this._retryAttempt > 0) {
222
- this._emit({
223
- type: "auto_retry_end",
224
- success: true,
225
- attempt: this._retryAttempt,
226
- });
227
- this._retryAttempt = 0;
228
- this._resolveRetry();
226
+ if (assistantMsg.stopReason !== "error") {
227
+ this._retryHandler.handleSuccessfulResponse();
229
228
  }
230
229
  }
231
230
  }
@@ -234,20 +233,12 @@ export class AgentSession {
234
233
  const msg = this._lastAssistantMessage;
235
234
  this._lastAssistantMessage = undefined;
236
235
  // Check for retryable errors first (overloaded, rate limit, server errors)
237
- if (this._isRetryableError(msg)) {
238
- const didRetry = await this._handleRetryableError(msg);
236
+ if (this._retryHandler.isRetryableError(msg)) {
237
+ const didRetry = await this._retryHandler.handleRetryableError(msg);
239
238
  if (didRetry)
240
239
  return; // Retry was initiated, don't proceed to compaction
241
240
  }
242
- await this._checkCompaction(msg);
243
- }
244
- }
245
- /** Resolve the pending retry promise */
246
- _resolveRetry() {
247
- if (this._retryResolve) {
248
- this._retryResolve();
249
- this._retryResolve = undefined;
250
- this._retryPromise = undefined;
241
+ await this._compactionOrchestrator.checkCompaction(msg);
251
242
  }
252
243
  }
253
244
  /**
@@ -280,10 +271,7 @@ export class AgentSession {
280
271
  }
281
272
  }
282
273
  catch (err) {
283
- if (err instanceof Error) {
284
- return { block: true, reason: err.message };
285
- }
286
- return { block: true, reason: `Extension failed, blocking execution: ${String(err)}` };
274
+ return { block: true, reason: err instanceof Error ? err.message : `Extension failed, blocking execution: ${String(err)}` };
287
275
  }
288
276
  return undefined;
289
277
  });
@@ -480,7 +468,7 @@ export class AgentSession {
480
468
  }
481
469
  /** Current retry attempt (0 if not retrying) */
482
470
  get retryAttempt() {
483
- return this._retryAttempt;
471
+ return this._retryHandler.retryAttempt;
484
472
  }
485
473
  /**
486
474
  * Get the names of currently active tools.
@@ -522,9 +510,7 @@ export class AgentSession {
522
510
  }
523
511
  /** Whether compaction or branch summarization is currently running */
524
512
  get isCompacting() {
525
- return (this._autoCompactionAbortController !== undefined ||
526
- this._compactionAbortController !== undefined ||
527
- this._branchSummaryAbortController !== undefined);
513
+ return this._compactionOrchestrator.isCompacting;
528
514
  }
529
515
  /**
530
516
  * Switch edit mode between standard (text-match) and hashline (LINE#ID anchors).
@@ -736,7 +722,7 @@ export class AgentSession {
736
722
  // Check if we need to compact before sending (catches aborted responses)
737
723
  const lastAssistant = this._findLastAssistantMessage();
738
724
  if (lastAssistant) {
739
- await this._checkCompaction(lastAssistant, false);
725
+ await this._compactionOrchestrator.checkCompaction(lastAssistant, false);
740
726
  }
741
727
  // Build messages array (custom message if any, then user message)
742
728
  const messages = [];
@@ -781,7 +767,7 @@ export class AgentSession {
781
767
  }
782
768
  }
783
769
  await this.agent.prompt(messages);
784
- await this.waitForRetry();
770
+ await this._retryHandler.waitForRetry();
785
771
  }
786
772
  /**
787
773
  * Try to execute an extension command. Returns true if command was found and executed.
@@ -807,7 +793,7 @@ export class AgentSession {
807
793
  this._extensionRunner.emitError({
808
794
  extensionPath: `command:${commandName}`,
809
795
  event: "command",
810
- error: err instanceof Error ? err.message : String(err),
796
+ error: getErrorMessage(err),
811
797
  });
812
798
  return true;
813
799
  }
@@ -837,7 +823,7 @@ export class AgentSession {
837
823
  this._extensionRunner?.emitError({
838
824
  extensionPath: skill.filePath,
839
825
  event: "skill_expansion",
840
- error: err instanceof Error ? err.message : String(err),
826
+ error: getErrorMessage(err),
841
827
  });
842
828
  return text; // Return original on error
843
829
  }
@@ -1030,7 +1016,7 @@ export class AgentSession {
1030
1016
  * Abort current operation and wait for agent to become idle.
1031
1017
  */
1032
1018
  async abort() {
1033
- this.abortRetry();
1019
+ this._retryHandler.abortRetry();
1034
1020
  this.agent.abort();
1035
1021
  await this.agent.waitForIdle();
1036
1022
  // Ensure agent_end is emitted even when abort interrupts a tool call (#1414).
@@ -1120,6 +1106,20 @@ export class AgentSession {
1120
1106
  source,
1121
1107
  });
1122
1108
  }
1109
+ /**
1110
+ * Apply a model change: set the model on the agent, persist to session/settings,
1111
+ * re-clamp thinking level, and emit the model_select event.
1112
+ */
1113
+ async _applyModelChange(model, thinkingLevel, source, options) {
1114
+ const previousModel = this.model;
1115
+ this.agent.setModel(model);
1116
+ this.sessionManager.appendModelChange(model.provider, model.id);
1117
+ if (options?.persist !== false) {
1118
+ this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1119
+ }
1120
+ this.setThinkingLevel(thinkingLevel);
1121
+ await this._emitModelSelect(model, previousModel, source);
1122
+ }
1123
1123
  /**
1124
1124
  * Set model directly.
1125
1125
  * Validates API key, saves to session and settings.
@@ -1130,16 +1130,8 @@ export class AgentSession {
1130
1130
  if (!apiKey) {
1131
1131
  throw new Error(`No API key for ${model.provider}/${model.id}`);
1132
1132
  }
1133
- const previousModel = this.model;
1134
1133
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1135
- this.agent.setModel(model);
1136
- this.sessionManager.appendModelChange(model.provider, model.id);
1137
- if (options?.persist !== false) {
1138
- this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1139
- }
1140
- // Re-clamp thinking level for new model's capabilities
1141
- this.setThinkingLevel(thinkingLevel);
1142
- await this._emitModelSelect(model, previousModel, "set");
1134
+ await this._applyModelChange(model, thinkingLevel, "set", options);
1143
1135
  }
1144
1136
  /**
1145
1137
  * Cycle to next/previous model.
@@ -1183,19 +1175,10 @@ export class AgentSession {
1183
1175
  const len = scopedModels.length;
1184
1176
  const nextIndex = direction === "forward" ? (currentIndex + 1) % len : (currentIndex - 1 + len) % len;
1185
1177
  const next = scopedModels[nextIndex];
1178
+ // Explicit scoped model thinking level overrides current session level;
1179
+ // undefined scoped model thinking level inherits the current session preference.
1186
1180
  const thinkingLevel = this._getThinkingLevelForModelSwitch(next.thinkingLevel);
1187
- // Apply model
1188
- this.agent.setModel(next.model);
1189
- this.sessionManager.appendModelChange(next.model.provider, next.model.id);
1190
- if (options?.persist !== false) {
1191
- this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
1192
- }
1193
- // Apply thinking level.
1194
- // - Explicit scoped model thinking level overrides current session level
1195
- // - Undefined scoped model thinking level inherits the current session preference
1196
- // setThinkingLevel clamps to model capabilities.
1197
- this.setThinkingLevel(thinkingLevel);
1198
- await this._emitModelSelect(next.model, currentModel, "cycle");
1181
+ await this._applyModelChange(next.model, thinkingLevel, "cycle", options);
1199
1182
  return { model: next.model, thinkingLevel: this.thinkingLevel, isScoped: true };
1200
1183
  }
1201
1184
  async _cycleAvailableModel(direction, options) {
@@ -1214,14 +1197,7 @@ export class AgentSession {
1214
1197
  throw new Error(`No API key for ${nextModel.provider}/${nextModel.id}`);
1215
1198
  }
1216
1199
  const thinkingLevel = this._getThinkingLevelForModelSwitch();
1217
- this.agent.setModel(nextModel);
1218
- this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
1219
- if (options?.persist !== false) {
1220
- this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
1221
- }
1222
- // Re-clamp thinking level for new model's capabilities
1223
- this.setThinkingLevel(thinkingLevel);
1224
- await this._emitModelSelect(nextModel, currentModel, "cycle");
1200
+ await this._applyModelChange(nextModel, thinkingLevel, "cycle", options);
1225
1201
  return { model: nextModel, thinkingLevel: this.thinkingLevel, isScoped: false };
1226
1202
  }
1227
1203
  // =========================================================================
@@ -1336,315 +1312,23 @@ export class AgentSession {
1336
1312
  * @param customInstructions Optional instructions for the compaction summary
1337
1313
  */
1338
1314
  async compact(customInstructions) {
1339
- this._disconnectFromAgent();
1340
- await this.abort();
1341
- this._compactionAbortController = new AbortController();
1342
- try {
1343
- if (!this.model) {
1344
- throw new Error("No model selected");
1345
- }
1346
- const apiKey = await this._modelRegistry.getApiKey(this.model, this.sessionId);
1347
- if (!apiKey) {
1348
- throw new Error(`No API key for ${this.model.provider}`);
1349
- }
1350
- const pathEntries = this.sessionManager.getBranch();
1351
- const settings = this.settingsManager.getCompactionSettings();
1352
- const preparation = prepareCompaction(pathEntries, settings);
1353
- if (!preparation) {
1354
- // Check why we can't compact
1355
- const lastEntry = pathEntries[pathEntries.length - 1];
1356
- if (lastEntry?.type === "compaction") {
1357
- throw new Error("Already compacted");
1358
- }
1359
- throw new Error("Nothing to compact (session too small)");
1360
- }
1361
- let extensionCompaction;
1362
- let fromExtension = false;
1363
- if (this._extensionRunner?.hasHandlers("session_before_compact")) {
1364
- const result = (await this._extensionRunner.emit({
1365
- type: "session_before_compact",
1366
- preparation,
1367
- branchEntries: pathEntries,
1368
- customInstructions,
1369
- signal: this._compactionAbortController.signal,
1370
- }));
1371
- if (result?.cancel) {
1372
- throw new Error("Compaction cancelled");
1373
- }
1374
- if (result?.compaction) {
1375
- extensionCompaction = result.compaction;
1376
- fromExtension = true;
1377
- }
1378
- }
1379
- let summary;
1380
- let firstKeptEntryId;
1381
- let tokensBefore;
1382
- let details;
1383
- if (extensionCompaction) {
1384
- // Extension provided compaction content
1385
- summary = extensionCompaction.summary;
1386
- firstKeptEntryId = extensionCompaction.firstKeptEntryId;
1387
- tokensBefore = extensionCompaction.tokensBefore;
1388
- details = extensionCompaction.details;
1389
- }
1390
- else {
1391
- // Generate compaction result
1392
- const result = await compact(preparation, this.model, apiKey, customInstructions, this._compactionAbortController.signal);
1393
- summary = result.summary;
1394
- firstKeptEntryId = result.firstKeptEntryId;
1395
- tokensBefore = result.tokensBefore;
1396
- details = result.details;
1397
- }
1398
- if (this._compactionAbortController.signal.aborted) {
1399
- throw new Error("Compaction cancelled");
1400
- }
1401
- this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
1402
- const newEntries = this.sessionManager.getEntries();
1403
- const sessionContext = this.sessionManager.buildSessionContext();
1404
- this.agent.replaceMessages(sessionContext.messages);
1405
- // Get the saved compaction entry for the extension event
1406
- const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
1407
- if (this._extensionRunner && savedCompactionEntry) {
1408
- await this._extensionRunner.emit({
1409
- type: "session_compact",
1410
- compactionEntry: savedCompactionEntry,
1411
- fromExtension,
1412
- });
1413
- }
1414
- return {
1415
- summary,
1416
- firstKeptEntryId,
1417
- tokensBefore,
1418
- details,
1419
- };
1420
- }
1421
- finally {
1422
- this._compactionAbortController = undefined;
1423
- this._reconnectToAgent();
1424
- }
1315
+ return this._compactionOrchestrator.compact(customInstructions);
1425
1316
  }
1426
- /**
1427
- * Cancel in-progress compaction (manual or auto).
1428
- */
1317
+ /** Cancel in-progress compaction (manual or auto) */
1429
1318
  abortCompaction() {
1430
- this._compactionAbortController?.abort();
1431
- this._autoCompactionAbortController?.abort();
1319
+ this._compactionOrchestrator.abortCompaction();
1432
1320
  }
1433
- /**
1434
- * Cancel in-progress branch summarization.
1435
- */
1321
+ /** Cancel in-progress branch summarization */
1436
1322
  abortBranchSummary() {
1437
- this._branchSummaryAbortController?.abort();
1438
- }
1439
- /**
1440
- * Check if compaction is needed and run it.
1441
- * Called after agent_end and before prompt submission.
1442
- *
1443
- * Two cases:
1444
- * 1. Overflow: LLM returned context overflow error, remove error message from agent state, compact, auto-retry
1445
- * 2. Threshold: Context over threshold, compact, NO auto-retry (user continues manually)
1446
- *
1447
- * @param assistantMessage The assistant message to check
1448
- * @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
1449
- */
1450
- async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
1451
- const settings = this.settingsManager.getCompactionSettings();
1452
- if (!settings.enabled)
1453
- return;
1454
- // Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
1455
- if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
1456
- return;
1457
- const contextWindow = this.model?.contextWindow ?? 0;
1458
- // Skip overflow check if the message came from a different model.
1459
- // This handles the case where user switched from a smaller-context model (e.g. opus)
1460
- // to a larger-context model (e.g. codex) - the overflow error from the old model
1461
- // shouldn't trigger compaction for the new model.
1462
- const sameModel = this.model && assistantMessage.provider === this.model.provider && assistantMessage.model === this.model.id;
1463
- // Skip compaction checks if this assistant message is older than the latest
1464
- // compaction boundary. This prevents a stale pre-compaction usage/error
1465
- // from retriggering compaction on the first prompt after compaction.
1466
- const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
1467
- const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
1468
- if (assistantIsFromBeforeCompaction) {
1469
- return;
1470
- }
1471
- // Case 1: Overflow - LLM returned context overflow error
1472
- if (sameModel && isContextOverflow(assistantMessage, contextWindow)) {
1473
- if (this._overflowRecoveryAttempted) {
1474
- this._emit({
1475
- type: "auto_compaction_end",
1476
- result: undefined,
1477
- aborted: false,
1478
- willRetry: false,
1479
- errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
1480
- });
1481
- return;
1482
- }
1483
- this._overflowRecoveryAttempted = true;
1484
- // Remove the error message from agent state (it IS saved to session for history,
1485
- // but we don't want it in context for the retry)
1486
- const messages = this.agent.state.messages;
1487
- if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
1488
- this.agent.replaceMessages(messages.slice(0, -1));
1489
- }
1490
- await this._runAutoCompaction("overflow", true);
1491
- return;
1492
- }
1493
- // Case 2: Threshold - context is getting large
1494
- // For error messages (no usage data), estimate from last successful response.
1495
- // This ensures sessions that hit persistent API errors (e.g. 529) can still compact.
1496
- let contextTokens;
1497
- if (assistantMessage.stopReason === "error") {
1498
- const messages = this.agent.state.messages;
1499
- const estimate = estimateContextTokens(messages);
1500
- if (estimate.lastUsageIndex === null)
1501
- return; // No usage data at all
1502
- // Verify the usage source is post-compaction. Kept pre-compaction messages
1503
- // have stale usage reflecting the old (larger) context and would falsely
1504
- // trigger compaction right after one just finished.
1505
- const usageMsg = messages[estimate.lastUsageIndex];
1506
- if (compactionEntry &&
1507
- usageMsg.role === "assistant" &&
1508
- usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
1509
- return;
1510
- }
1511
- contextTokens = estimate.tokens;
1512
- }
1513
- else {
1514
- contextTokens = calculateContextTokens(assistantMessage.usage);
1515
- }
1516
- if (shouldCompact(contextTokens, contextWindow, settings)) {
1517
- await this._runAutoCompaction("threshold", false);
1518
- }
1519
- }
1520
- /**
1521
- * Internal: Run auto-compaction with events.
1522
- */
1523
- async _runAutoCompaction(reason, willRetry) {
1524
- const settings = this.settingsManager.getCompactionSettings();
1525
- this._emit({ type: "auto_compaction_start", reason });
1526
- this._autoCompactionAbortController = new AbortController();
1527
- try {
1528
- if (!this.model) {
1529
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1530
- return;
1531
- }
1532
- const apiKey = await this._modelRegistry.getApiKey(this.model, this.sessionId);
1533
- if (!apiKey) {
1534
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1535
- return;
1536
- }
1537
- const pathEntries = this.sessionManager.getBranch();
1538
- const preparation = prepareCompaction(pathEntries, settings);
1539
- if (!preparation) {
1540
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: false, willRetry: false });
1541
- return;
1542
- }
1543
- let extensionCompaction;
1544
- let fromExtension = false;
1545
- if (this._extensionRunner?.hasHandlers("session_before_compact")) {
1546
- const extensionResult = (await this._extensionRunner.emit({
1547
- type: "session_before_compact",
1548
- preparation,
1549
- branchEntries: pathEntries,
1550
- customInstructions: undefined,
1551
- signal: this._autoCompactionAbortController.signal,
1552
- }));
1553
- if (extensionResult?.cancel) {
1554
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1555
- return;
1556
- }
1557
- if (extensionResult?.compaction) {
1558
- extensionCompaction = extensionResult.compaction;
1559
- fromExtension = true;
1560
- }
1561
- }
1562
- let summary;
1563
- let firstKeptEntryId;
1564
- let tokensBefore;
1565
- let details;
1566
- if (extensionCompaction) {
1567
- // Extension provided compaction content
1568
- summary = extensionCompaction.summary;
1569
- firstKeptEntryId = extensionCompaction.firstKeptEntryId;
1570
- tokensBefore = extensionCompaction.tokensBefore;
1571
- details = extensionCompaction.details;
1572
- }
1573
- else {
1574
- // Generate compaction result
1575
- const compactResult = await compact(preparation, this.model, apiKey, undefined, this._autoCompactionAbortController.signal);
1576
- summary = compactResult.summary;
1577
- firstKeptEntryId = compactResult.firstKeptEntryId;
1578
- tokensBefore = compactResult.tokensBefore;
1579
- details = compactResult.details;
1580
- }
1581
- if (this._autoCompactionAbortController.signal.aborted) {
1582
- this._emit({ type: "auto_compaction_end", result: undefined, aborted: true, willRetry: false });
1583
- return;
1584
- }
1585
- this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension);
1586
- const newEntries = this.sessionManager.getEntries();
1587
- const sessionContext = this.sessionManager.buildSessionContext();
1588
- this.agent.replaceMessages(sessionContext.messages);
1589
- // Get the saved compaction entry for the extension event
1590
- const savedCompactionEntry = newEntries.find((e) => e.type === "compaction" && e.summary === summary);
1591
- if (this._extensionRunner && savedCompactionEntry) {
1592
- await this._extensionRunner.emit({
1593
- type: "session_compact",
1594
- compactionEntry: savedCompactionEntry,
1595
- fromExtension,
1596
- });
1597
- }
1598
- const result = {
1599
- summary,
1600
- firstKeptEntryId,
1601
- tokensBefore,
1602
- details,
1603
- };
1604
- this._emit({ type: "auto_compaction_end", result, aborted: false, willRetry });
1605
- if (willRetry) {
1606
- const messages = this.agent.state.messages;
1607
- const lastMsg = messages[messages.length - 1];
1608
- if (lastMsg?.role === "assistant" && lastMsg.stopReason === "error") {
1609
- this.agent.replaceMessages(messages.slice(0, -1));
1610
- }
1611
- setTimeout(() => {
1612
- this.agent.continue().catch(() => { });
1613
- }, 100);
1614
- }
1615
- else if (this.agent.hasQueuedMessages()) {
1616
- // Auto-compaction can complete while follow-up/steering/custom messages are waiting.
1617
- // Kick the loop so queued messages are actually delivered.
1618
- setTimeout(() => {
1619
- this.agent.continue().catch(() => { });
1620
- }, 100);
1621
- }
1622
- }
1623
- catch (error) {
1624
- const errorMessage = error instanceof Error ? error.message : "compaction failed";
1625
- this._emit({
1626
- type: "auto_compaction_end",
1627
- result: undefined,
1628
- aborted: false,
1629
- willRetry: false,
1630
- errorMessage: reason === "overflow"
1631
- ? `Context overflow recovery failed: ${errorMessage}`
1632
- : `Auto-compaction failed: ${errorMessage}`,
1633
- });
1634
- }
1635
- finally {
1636
- this._autoCompactionAbortController = undefined;
1637
- }
1323
+ this._compactionOrchestrator.abortBranchSummary();
1638
1324
  }
1639
- /**
1640
- * Toggle auto-compaction setting.
1641
- */
1325
+ /** Toggle auto-compaction setting */
1642
1326
  setAutoCompactionEnabled(enabled) {
1643
- this.settingsManager.setCompactionEnabled(enabled);
1327
+ this._compactionOrchestrator.setAutoCompactionEnabled(enabled);
1644
1328
  }
1645
1329
  /** Whether auto-compaction is enabled */
1646
1330
  get autoCompactionEnabled() {
1647
- return this.settingsManager.getCompactionEnabled();
1331
+ return this._compactionOrchestrator.autoCompactionEnabled;
1648
1332
  }
1649
1333
  async bindExtensions(bindings) {
1650
1334
  if (bindings.uiContext !== undefined) {
@@ -1753,7 +1437,7 @@ export class AgentSession {
1753
1437
  runner.emitError({
1754
1438
  extensionPath: "<runtime>",
1755
1439
  event: "send_message",
1756
- error: err instanceof Error ? err.message : String(err),
1440
+ error: getErrorMessage(err),
1757
1441
  });
1758
1442
  });
1759
1443
  },
@@ -1762,7 +1446,7 @@ export class AgentSession {
1762
1446
  runner.emitError({
1763
1447
  extensionPath: "<runtime>",
1764
1448
  event: "send_user_message",
1765
- error: err instanceof Error ? err.message : String(err),
1449
+ error: getErrorMessage(err),
1766
1450
  });
1767
1451
  });
1768
1452
  },
@@ -1775,7 +1459,7 @@ export class AgentSession {
1775
1459
  runner.emitError({
1776
1460
  extensionPath: "<runtime>",
1777
1461
  event: "retry_last_turn",
1778
- error: err instanceof Error ? err.message : String(err),
1462
+ error: getErrorMessage(err),
1779
1463
  });
1780
1464
  });
1781
1465
  }
@@ -1944,244 +1628,23 @@ export class AgentSession {
1944
1628
  }
1945
1629
  }
1946
1630
  // =========================================================================
1947
- // Auto-Retry
1631
+ // Auto-Retry (delegated to RetryHandler)
1948
1632
  // =========================================================================
1949
- /**
1950
- * Check if an error is retryable (overloaded, rate limit, server errors).
1951
- * Context overflow errors are NOT retryable (handled by compaction instead).
1952
- */
1953
- _isRetryableError(message) {
1954
- if (message.stopReason !== "error" || !message.errorMessage)
1955
- return false;
1956
- // Context overflow is handled by compaction, not retry
1957
- const contextWindow = this.model?.contextWindow ?? 0;
1958
- if (isContextOverflow(message, contextWindow))
1959
- return false;
1960
- const err = message.errorMessage;
1961
- // Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection errors, fetch failed, terminated, retry delay exceeded, network unavailable / auth expired (transient network failures)
1962
- return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated|retry delay|network.?(?:is\s+)?unavailable|credentials.*expired|temporarily backed off/i.test(err);
1963
- }
1964
- /**
1965
- * Classify an error message into a usage-limit error type for credential backoff.
1966
- */
1967
- _classifyErrorType(errorMessage) {
1968
- const err = errorMessage.toLowerCase();
1969
- if (/quota|billing|exceeded.*limit|usage.*limit/i.test(err))
1970
- return "quota_exhausted";
1971
- if (/rate.?limit|too many requests|429/i.test(err))
1972
- return "rate_limit";
1973
- if (/500|502|503|504|server.?error|internal.?error|service.?unavailable/i.test(err))
1974
- return "server_error";
1975
- return "unknown";
1976
- }
1977
- /**
1978
- * Handle retryable errors with exponential backoff.
1979
- * When multiple credentials are available, marks the failing credential
1980
- * as backed off and retries immediately with the next one.
1981
- * @returns true if retry was initiated, false if max retries exceeded or disabled
1982
- */
1983
- async _handleRetryableError(message) {
1984
- const settings = this.settingsManager.getRetrySettings();
1985
- if (!settings.enabled) {
1986
- this._resolveRetry();
1987
- return false;
1988
- }
1989
- // Retry promise is created synchronously in _handleAgentEvent for agent_end.
1990
- // Keep a defensive fallback here in case a future refactor bypasses that path.
1991
- if (!this._retryPromise) {
1992
- this._retryPromise = new Promise((resolve) => {
1993
- this._retryResolve = resolve;
1994
- });
1995
- }
1996
- // Try credential fallback before counting against retry budget.
1997
- // If another credential is available, switch to it and retry immediately.
1998
- // Only attempt credential rotation for errors that indicate a credential-level
1999
- // problem (rate limit, quota exhaustion, server error). Transport failures
2000
- // ("unknown") like connection resets are not credential-specific — rotating
2001
- // won't help and backing off the only credential causes "Authentication failed".
2002
- if (this.model && message.errorMessage) {
2003
- const errorType = this._classifyErrorType(message.errorMessage);
2004
- const isCredentialError = errorType !== "unknown";
2005
- const hasAlternate = isCredentialError && this._modelRegistry.authStorage.markUsageLimitReached(this.model.provider, this.sessionId, { errorType });
2006
- if (hasAlternate) {
2007
- // Remove error message from agent state
2008
- const messages = this.agent.state.messages;
2009
- if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
2010
- this.agent.replaceMessages(messages.slice(0, -1));
2011
- }
2012
- this._emit({
2013
- type: "auto_retry_start",
2014
- attempt: this._retryAttempt + 1,
2015
- maxAttempts: settings.maxRetries,
2016
- delayMs: 0,
2017
- errorMessage: `${message.errorMessage} (switching credential)`,
2018
- });
2019
- // Retry immediately with the next credential - don't increment _retryAttempt
2020
- setTimeout(() => {
2021
- this.agent.continue().catch(() => {
2022
- // Retry failed - will be caught by next agent_end
2023
- });
2024
- }, 0);
2025
- return true;
2026
- }
2027
- // All credentials are backed off. Try cross-provider fallback before giving up.
2028
- if (isCredentialError) {
2029
- const fallbackResult = await this._fallbackResolver.findFallback(this.model, errorType);
2030
- if (fallbackResult) {
2031
- // Swap to fallback model — don't persist to settings
2032
- const previousProvider = this.model.provider;
2033
- this.agent.setModel(fallbackResult.model);
2034
- this.sessionManager.appendModelChange(fallbackResult.model.provider, fallbackResult.model.id);
2035
- // Remove error message from agent state
2036
- const msgs = this.agent.state.messages;
2037
- if (msgs.length > 0 && msgs[msgs.length - 1].role === "assistant") {
2038
- this.agent.replaceMessages(msgs.slice(0, -1));
2039
- }
2040
- this._emit({
2041
- type: "fallback_provider_switch",
2042
- from: `${previousProvider}/${this.model?.id}`,
2043
- to: `${fallbackResult.model.provider}/${fallbackResult.model.id}`,
2044
- reason: fallbackResult.reason,
2045
- });
2046
- this._emit({
2047
- type: "auto_retry_start",
2048
- attempt: this._retryAttempt + 1,
2049
- maxAttempts: settings.maxRetries,
2050
- delayMs: 0,
2051
- errorMessage: `${message.errorMessage} (${fallbackResult.reason})`,
2052
- });
2053
- // Retry immediately with fallback provider - don't increment _retryAttempt
2054
- setTimeout(() => {
2055
- this.agent.continue().catch(() => {
2056
- // Retry failed - will be caught by next agent_end
2057
- });
2058
- }, 0);
2059
- return true;
2060
- }
2061
- // No fallback available either
2062
- if (errorType === "quota_exhausted") {
2063
- this._emit({
2064
- type: "fallback_chain_exhausted",
2065
- reason: `All providers exhausted for ${this.model.provider}/${this.model.id}`,
2066
- });
2067
- this._emit({
2068
- type: "auto_retry_end",
2069
- success: false,
2070
- attempt: this._retryAttempt,
2071
- finalError: message.errorMessage,
2072
- });
2073
- this._retryAttempt = 0;
2074
- this._resolveRetry();
2075
- return false;
2076
- }
2077
- }
2078
- }
2079
- this._retryAttempt++;
2080
- if (this._retryAttempt > settings.maxRetries) {
2081
- // Max retries exceeded, emit final failure and reset
2082
- this._emit({
2083
- type: "auto_retry_end",
2084
- success: false,
2085
- attempt: this._retryAttempt - 1,
2086
- finalError: message.errorMessage,
2087
- });
2088
- this._retryAttempt = 0;
2089
- this._resolveRetry(); // Resolve so waitForRetry() completes
2090
- return false;
2091
- }
2092
- // Use server-requested delay when available (rate limit headers), capped by maxDelayMs.
2093
- // Fall back to exponential backoff when no server hint is present.
2094
- const exponentialDelayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
2095
- let delayMs;
2096
- if (message.retryAfterMs !== undefined) {
2097
- const cap = settings.maxDelayMs > 0 ? settings.maxDelayMs : Infinity;
2098
- if (message.retryAfterMs > cap) {
2099
- // Server wants us to wait longer than maxDelayMs — give up to let auto-mode handle recovery
2100
- this._emit({
2101
- type: "auto_retry_end",
2102
- success: false,
2103
- attempt: this._retryAttempt - 1,
2104
- finalError: `Rate limit reset in ${Math.ceil(message.retryAfterMs / 1000)}s (max: ${Math.ceil(cap / 1000)}s). ${message.errorMessage || ""}`.trim(),
2105
- });
2106
- this._retryAttempt = 0;
2107
- this._resolveRetry();
2108
- return false;
2109
- }
2110
- delayMs = message.retryAfterMs;
2111
- }
2112
- else {
2113
- delayMs = exponentialDelayMs;
2114
- }
2115
- this._emit({
2116
- type: "auto_retry_start",
2117
- attempt: this._retryAttempt,
2118
- maxAttempts: settings.maxRetries,
2119
- delayMs,
2120
- errorMessage: message.errorMessage || "Unknown error",
2121
- });
2122
- // Remove error message from agent state (keep in session for history)
2123
- const messages = this.agent.state.messages;
2124
- if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
2125
- this.agent.replaceMessages(messages.slice(0, -1));
2126
- }
2127
- // Wait with exponential backoff (abortable)
2128
- this._retryAbortController = new AbortController();
2129
- try {
2130
- await sleep(delayMs, this._retryAbortController.signal);
2131
- }
2132
- catch {
2133
- // Aborted during sleep - emit end event so UI can clean up
2134
- const attempt = this._retryAttempt;
2135
- this._retryAttempt = 0;
2136
- this._retryAbortController = undefined;
2137
- this._emit({
2138
- type: "auto_retry_end",
2139
- success: false,
2140
- attempt,
2141
- finalError: "Retry cancelled",
2142
- });
2143
- this._resolveRetry();
2144
- return false;
2145
- }
2146
- this._retryAbortController = undefined;
2147
- // Retry via continue() - use setTimeout to break out of event handler chain
2148
- setTimeout(() => {
2149
- this.agent.continue().catch(() => {
2150
- // Retry failed - will be caught by next agent_end
2151
- });
2152
- }, 0);
2153
- return true;
2154
- }
2155
- /**
2156
- * Cancel in-progress retry.
2157
- */
1633
+ /** Cancel in-progress retry */
2158
1634
  abortRetry() {
2159
- this._retryAbortController?.abort();
2160
- // Note: _retryAttempt is reset in the catch block of _autoRetry
2161
- this._resolveRetry();
2162
- }
2163
- /**
2164
- * Wait for any in-progress retry to complete.
2165
- * Returns immediately if no retry is in progress.
2166
- */
2167
- async waitForRetry() {
2168
- if (this._retryPromise) {
2169
- await this._retryPromise;
2170
- }
1635
+ this._retryHandler.abortRetry();
2171
1636
  }
2172
1637
  /** Whether auto-retry is currently in progress */
2173
1638
  get isRetrying() {
2174
- return this._retryPromise !== undefined;
1639
+ return this._retryHandler.isRetrying;
2175
1640
  }
2176
1641
  /** Whether auto-retry is enabled */
2177
1642
  get autoRetryEnabled() {
2178
- return this.settingsManager.getRetryEnabled();
1643
+ return this._retryHandler.autoRetryEnabled;
2179
1644
  }
2180
- /**
2181
- * Toggle auto-retry setting.
2182
- */
1645
+ /** Toggle auto-retry setting */
2183
1646
  setAutoRetryEnabled(enabled) {
2184
- this.settingsManager.setRetryEnabled(enabled);
1647
+ this._retryHandler.setAutoRetryEnabled(enabled);
2185
1648
  }
2186
1649
  // =========================================================================
2187
1650
  // Bash Execution
@@ -2445,7 +1908,7 @@ export class AgentSession {
2445
1908
  label,
2446
1909
  };
2447
1910
  // Set up abort controller for summarization
2448
- this._branchSummaryAbortController = new AbortController();
1911
+ this._compactionOrchestrator.branchSummaryAbortController = new AbortController();
2449
1912
  let extensionSummary;
2450
1913
  let fromExtension = false;
2451
1914
  // Emit session_before_tree event
@@ -2453,7 +1916,7 @@ export class AgentSession {
2453
1916
  const result = (await this._extensionRunner.emit({
2454
1917
  type: "session_before_tree",
2455
1918
  preparation,
2456
- signal: this._branchSummaryAbortController.signal,
1919
+ signal: this._compactionOrchestrator.branchSummaryAbortController.signal,
2457
1920
  }));
2458
1921
  if (result?.cancel) {
2459
1922
  return { cancelled: true };
@@ -2486,12 +1949,12 @@ export class AgentSession {
2486
1949
  const result = await generateBranchSummary(entriesToSummarize, {
2487
1950
  model,
2488
1951
  apiKey,
2489
- signal: this._branchSummaryAbortController.signal,
1952
+ signal: this._compactionOrchestrator.branchSummaryAbortController.signal,
2490
1953
  customInstructions,
2491
1954
  replaceInstructions,
2492
1955
  reserveTokens: branchSummarySettings.reserveTokens,
2493
1956
  });
2494
- this._branchSummaryAbortController = undefined;
1957
+ this._compactionOrchestrator.branchSummaryAbortController = undefined;
2495
1958
  if (result.aborted) {
2496
1959
  return { cancelled: true, aborted: true };
2497
1960
  }
@@ -2569,7 +2032,7 @@ export class AgentSession {
2569
2032
  });
2570
2033
  }
2571
2034
  // Emit to custom tools
2572
- this._branchSummaryAbortController = undefined;
2035
+ this._compactionOrchestrator.branchSummaryAbortController = undefined;
2573
2036
  return { editorText, cancelled: false, summaryEntry };
2574
2037
  }
2575
2038
  /**
@@ -2631,17 +2094,17 @@ export class AgentSession {
2631
2094
  sessionId: this.sessionId,
2632
2095
  userMessages,
2633
2096
  assistantMessages,
2634
- toolCalls,
2097
+ toolCalls: Math.max(toolCalls, this._cumulativeToolCalls),
2635
2098
  toolResults,
2636
2099
  totalMessages: state.messages.length,
2637
2100
  tokens: {
2638
- input: totalInput,
2639
- output: totalOutput,
2101
+ input: Math.max(totalInput, this._cumulativeInputTokens),
2102
+ output: Math.max(totalOutput, this._cumulativeOutputTokens),
2640
2103
  cacheRead: totalCacheRead,
2641
2104
  cacheWrite: totalCacheWrite,
2642
- total: totalInput + totalOutput + totalCacheRead + totalCacheWrite,
2105
+ total: Math.max(totalInput + totalOutput, this._cumulativeInputTokens + this._cumulativeOutputTokens) + totalCacheRead + totalCacheWrite,
2643
2106
  },
2644
- cost: totalCost,
2107
+ cost: Math.max(totalCost, this._cumulativeCost),
2645
2108
  };
2646
2109
  }
2647
2110
  getContextUsage() {