gsd-pi 2.77.0 → 2.78.0-dev.aeeb2ca00

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 (878) hide show
  1. package/README.md +51 -33
  2. package/dist/claude-cli-check.js +46 -10
  3. package/dist/cli-web-branch.d.ts +1 -0
  4. package/dist/cli-web-branch.js +3 -0
  5. package/dist/cli.js +38 -2
  6. package/dist/extension-discovery.d.ts +6 -0
  7. package/dist/extension-discovery.js +37 -0
  8. package/dist/extension-registry.d.ts +3 -0
  9. package/dist/extension-sort.d.ts +18 -0
  10. package/dist/extension-sort.js +114 -0
  11. package/dist/extension-validator.d.ts +47 -0
  12. package/dist/extension-validator.js +127 -0
  13. package/dist/headless.js +49 -4
  14. package/dist/loader.js +35 -7
  15. package/dist/provider-migrations.d.ts +18 -0
  16. package/dist/provider-migrations.js +14 -0
  17. package/dist/resource-loader.d.ts +40 -0
  18. package/dist/resource-loader.js +32 -13
  19. package/dist/resources/extensions/browser-tools/capture.js +9 -0
  20. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  21. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  22. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  23. package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
  24. package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
  25. package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
  26. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +552 -67
  27. package/dist/resources/extensions/cmux/index.js +20 -0
  28. package/dist/resources/extensions/github-sync/templates.js +103 -0
  29. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  30. package/dist/resources/extensions/google-search/index.js +3 -375
  31. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  32. package/dist/resources/extensions/gsd/auto/loop.js +124 -2
  33. package/dist/resources/extensions/gsd/auto/phases.js +57 -39
  34. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  35. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
  36. package/dist/resources/extensions/gsd/auto/session.js +6 -2
  37. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  38. package/dist/resources/extensions/gsd/auto-dispatch.js +201 -38
  39. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  40. package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
  41. package/dist/resources/extensions/gsd/auto-post-unit.js +215 -64
  42. package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
  43. package/dist/resources/extensions/gsd/auto-recovery.js +210 -24
  44. package/dist/resources/extensions/gsd/auto-start.js +122 -30
  45. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  46. package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
  47. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  48. package/dist/resources/extensions/gsd/auto-worktree.js +180 -34
  49. package/dist/resources/extensions/gsd/auto.js +107 -35
  50. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
  51. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
  52. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +5 -6
  53. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
  54. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
  55. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
  56. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
  57. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  58. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  59. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  60. package/dist/resources/extensions/gsd/component-loader.js +447 -0
  61. package/dist/resources/extensions/gsd/component-types.js +69 -0
  62. package/dist/resources/extensions/gsd/context-store.js +23 -7
  63. package/dist/resources/extensions/gsd/detection.js +49 -1
  64. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  65. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  66. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  67. package/dist/resources/extensions/gsd/forensics.js +106 -0
  68. package/dist/resources/extensions/gsd/gate-registry.js +2 -2
  69. package/dist/resources/extensions/gsd/git-constants.js +28 -1
  70. package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
  71. package/dist/resources/extensions/gsd/git-service.js +127 -2
  72. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  73. package/dist/resources/extensions/gsd/gsd-db.js +6 -3
  74. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  75. package/dist/resources/extensions/gsd/guided-flow.js +39 -13
  76. package/dist/resources/extensions/gsd/journal.js +17 -2
  77. package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
  78. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  79. package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
  80. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  81. package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
  82. package/dist/resources/extensions/gsd/model-router.js +6 -0
  83. package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
  84. package/dist/resources/extensions/gsd/notifications.js +30 -16
  85. package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
  86. package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
  87. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  88. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  89. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  90. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  91. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  92. package/dist/resources/extensions/gsd/reports.js +5 -4
  93. package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
  94. package/dist/resources/extensions/gsd/service-tier.js +5 -2
  95. package/dist/resources/extensions/gsd/session-lock.js +19 -10
  96. package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
  97. package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
  98. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
  99. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  100. package/dist/resources/extensions/gsd/state.js +69 -58
  101. package/dist/resources/extensions/gsd/sync-lock.js +98 -42
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  103. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  104. package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
  105. package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
  106. package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
  107. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  108. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  109. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  110. package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
  111. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  112. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  113. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  114. package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
  115. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  116. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  117. package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
  118. package/dist/resources/extensions/gsd/worktree-manager.js +86 -8
  119. package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
  120. package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
  121. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  122. package/dist/resources/extensions/mcp-client/index.js +121 -10
  123. package/dist/resources/extensions/ollama/index.js +5 -1
  124. package/dist/resources/extensions/remote-questions/manager.js +11 -5
  125. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  126. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  127. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  128. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  129. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  130. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  131. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  132. package/dist/web/standalone/.next/BUILD_ID +1 -1
  133. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  134. package/dist/web/standalone/.next/build-manifest.json +4 -4
  135. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  136. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  137. package/dist/web/standalone/.next/required-server-files.json +3 -3
  138. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  139. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  141. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  149. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  151. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  152. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  153. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  155. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  156. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  168. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  184. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  213. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  214. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  217. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  219. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  222. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  225. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  227. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  230. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  232. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  233. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  235. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  236. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  238. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  239. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  240. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  242. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  243. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  244. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  245. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  246. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  247. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  249. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  250. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  251. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  252. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  253. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  254. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  255. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  256. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  257. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  259. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  260. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  262. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  263. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  265. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  267. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  268. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  269. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  270. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  271. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  272. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  273. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  274. package/dist/web/standalone/.next/server/app/index.html +1 -1
  275. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  276. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  277. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  278. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  279. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  280. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  281. package/dist/web/standalone/.next/server/app/page.js +2 -2
  282. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  283. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  284. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  285. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  286. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  287. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  288. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  289. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  290. package/dist/web/standalone/.next/server/middleware.js +2 -2
  291. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  292. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  293. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  294. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  295. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  296. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  297. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  298. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  299. package/dist/web/standalone/.next/static/chunks/app/page-5b113fd32bc2a1c3.js +1 -0
  300. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  301. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  302. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  303. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  304. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  305. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  306. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  307. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  308. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  309. package/dist/web/standalone/server.js +1 -1
  310. package/package.json +17 -16
  311. package/packages/daemon/package.json +2 -2
  312. package/packages/daemon/src/logger.ts +4 -3
  313. package/packages/mcp-server/README.md +3 -3
  314. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  315. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  316. package/packages/mcp-server/dist/env-writer.js +74 -6
  317. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  318. package/packages/mcp-server/dist/server.d.ts +24 -0
  319. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  320. package/packages/mcp-server/dist/server.js +111 -87
  321. package/packages/mcp-server/dist/server.js.map +1 -1
  322. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  323. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  324. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  325. package/packages/mcp-server/package.json +7 -2
  326. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  327. package/packages/mcp-server/src/env-writer.ts +76 -6
  328. package/packages/mcp-server/src/mcp-server.test.ts +25 -3
  329. package/packages/mcp-server/src/readers/graph.test.ts +87 -15
  330. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  331. package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
  332. package/packages/mcp-server/src/server.ts +158 -105
  333. package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
  334. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  335. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  336. package/packages/native/package.json +7 -2
  337. package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
  338. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  339. package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
  340. package/packages/native/src/__tests__/ps.test.mjs +14 -8
  341. package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
  342. package/packages/native/src/__tests__/truncate.test.mjs +17 -2
  343. package/packages/native/tsconfig.tsbuildinfo +1 -1
  344. package/packages/pi-agent-core/package.json +6 -1
  345. package/packages/pi-agent-core/src/agent-loop.test.ts +226 -31
  346. package/packages/pi-agent-core/src/agent.test.ts +96 -102
  347. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  348. package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
  349. package/packages/pi-ai/dist/models/capability-patches.js +9 -2
  350. package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
  351. package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
  352. package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
  353. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
  354. package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
  355. package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
  356. package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
  357. package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
  358. package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
  359. package/packages/pi-ai/dist/models/generated/openai.js +17 -0
  360. package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
  361. package/packages/pi-ai/dist/models.generated.test.js +43 -70
  362. package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
  363. package/packages/pi-ai/dist/models.test.js +36 -11
  364. package/packages/pi-ai/dist/models.test.js.map +1 -1
  365. package/packages/pi-ai/package.json +6 -1
  366. package/packages/pi-ai/scripts/generate-models.ts +44 -0
  367. package/packages/pi-ai/src/models/capability-patches.ts +10 -2
  368. package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
  369. package/packages/pi-ai/src/models/generated/openai.ts +17 -0
  370. package/packages/pi-ai/src/models.generated.test.ts +46 -73
  371. package/packages/pi-ai/src/models.test.ts +48 -11
  372. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  373. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
  374. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
  376. package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
  377. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
  378. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  379. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  380. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  381. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  382. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  383. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  384. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  385. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  386. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  387. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  388. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  389. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  390. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  391. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  392. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  393. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  394. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  395. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  396. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  397. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  398. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  399. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  400. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  401. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  402. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  403. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  404. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  405. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  406. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  407. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  408. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  409. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +8 -2
  410. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  411. package/packages/pi-coding-agent/dist/core/extensions/loader.js +85 -8
  412. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  413. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  414. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  415. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  416. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +41 -4
  417. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  418. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  419. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  420. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
  421. package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
  422. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  423. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  424. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  425. package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
  426. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  427. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
  428. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  429. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
  430. package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
  431. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
  432. package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
  433. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  434. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  435. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  436. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  437. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  438. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  439. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
  440. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  441. package/packages/pi-coding-agent/dist/core/system-prompt.js +19 -5
  442. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  443. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  444. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  445. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  446. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  447. package/packages/pi-coding-agent/dist/index.js +1 -0
  448. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  449. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  450. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  451. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
  452. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  453. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
  454. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
  455. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  456. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  457. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  458. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  459. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  460. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  461. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  462. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  463. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
  464. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  465. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  466. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
  467. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  468. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +139 -0
  469. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  470. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
  471. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  472. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  473. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
  474. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  475. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
  476. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  477. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
  478. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
  479. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
  480. package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
  481. package/packages/pi-coding-agent/package.json +6 -1
  482. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
  483. package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
  484. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
  485. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  486. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  487. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  488. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  489. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  490. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  491. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  492. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  493. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  494. package/packages/pi-coding-agent/src/core/extensions/loader.ts +82 -11
  495. package/packages/pi-coding-agent/src/core/extensions/types.ts +8 -0
  496. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +48 -4
  497. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +22 -2
  498. package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
  499. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  500. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
  501. package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
  502. package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
  503. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  504. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  505. package/packages/pi-coding-agent/src/core/system-prompt.ts +38 -4
  506. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  507. package/packages/pi-coding-agent/src/index.ts +1 -0
  508. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  509. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
  510. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
  511. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  512. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  513. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
  514. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +160 -1
  515. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
  516. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
  517. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
  518. package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
  519. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  520. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +31 -14
  521. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  522. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
  523. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  524. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +51 -6
  525. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  526. package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
  527. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  528. package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
  529. package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
  530. package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
  531. package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
  532. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
  533. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
  534. package/packages/pi-tui/dist/components/editor.d.ts +14 -0
  535. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  536. package/packages/pi-tui/dist/components/editor.js +19 -0
  537. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  538. package/packages/pi-tui/dist/components/image.test.js +6 -5
  539. package/packages/pi-tui/dist/components/image.test.js.map +1 -1
  540. package/packages/pi-tui/dist/editor-component.d.ts +2 -0
  541. package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
  542. package/packages/pi-tui/dist/editor-component.js.map +1 -1
  543. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  544. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  545. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  546. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  547. package/packages/pi-tui/package.json +6 -1
  548. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +46 -15
  549. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
  550. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +62 -6
  551. package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
  552. package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
  553. package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
  554. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
  555. package/packages/pi-tui/src/components/editor.ts +22 -0
  556. package/packages/pi-tui/src/components/image.test.ts +10 -5
  557. package/packages/pi-tui/src/editor-component.ts +3 -0
  558. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  559. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  560. package/packages/rpc-client/dist/rpc-client.test.js +101 -51
  561. package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
  562. package/packages/rpc-client/package.json +6 -1
  563. package/packages/rpc-client/src/rpc-client.test.ts +109 -52
  564. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  565. package/pkg/package.json +1 -1
  566. package/scripts/install.js +526 -0
  567. package/scripts/lib/workspace-manifest.cjs +86 -0
  568. package/scripts/link-workspace-packages.cjs +5 -17
  569. package/scripts/postinstall.js +9 -178
  570. package/src/resources/extensions/browser-tools/capture.ts +12 -0
  571. package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
  572. package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
  573. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
  574. package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
  575. package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
  576. package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
  577. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +602 -73
  578. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +1028 -91
  579. package/src/resources/extensions/cmux/index.ts +35 -10
  580. package/src/resources/extensions/github-sync/templates.ts +151 -0
  581. package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
  582. package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
  583. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  584. package/src/resources/extensions/google-search/index.ts +9 -470
  585. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  586. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  587. package/src/resources/extensions/gsd/auto/loop.ts +142 -2
  588. package/src/resources/extensions/gsd/auto/phases.ts +62 -38
  589. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  590. package/src/resources/extensions/gsd/auto/run-unit.ts +16 -2
  591. package/src/resources/extensions/gsd/auto/session.ts +7 -2
  592. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  593. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  594. package/src/resources/extensions/gsd/auto-dispatch.ts +214 -37
  595. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  596. package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
  597. package/src/resources/extensions/gsd/auto-post-unit.ts +226 -73
  598. package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
  599. package/src/resources/extensions/gsd/auto-recovery.ts +240 -25
  600. package/src/resources/extensions/gsd/auto-start.ts +146 -14
  601. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  602. package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
  603. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  604. package/src/resources/extensions/gsd/auto-worktree.ts +190 -31
  605. package/src/resources/extensions/gsd/auto.ts +127 -41
  606. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
  607. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
  608. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -6
  609. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
  610. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
  611. package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
  612. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
  613. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  614. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  615. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  616. package/src/resources/extensions/gsd/component-loader.ts +598 -0
  617. package/src/resources/extensions/gsd/component-types.ts +362 -0
  618. package/src/resources/extensions/gsd/context-store.ts +25 -8
  619. package/src/resources/extensions/gsd/detection.ts +58 -1
  620. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  621. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  622. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  623. package/src/resources/extensions/gsd/forensics.ts +118 -1
  624. package/src/resources/extensions/gsd/gate-registry.ts +2 -2
  625. package/src/resources/extensions/gsd/git-constants.ts +30 -1
  626. package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
  627. package/src/resources/extensions/gsd/git-service.ts +150 -2
  628. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  629. package/src/resources/extensions/gsd/gsd-db.ts +6 -3
  630. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  631. package/src/resources/extensions/gsd/guided-flow.ts +57 -14
  632. package/src/resources/extensions/gsd/journal.ts +38 -3
  633. package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
  634. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  635. package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
  636. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  637. package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
  638. package/src/resources/extensions/gsd/model-router.ts +6 -0
  639. package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
  640. package/src/resources/extensions/gsd/notifications.ts +27 -15
  641. package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
  642. package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
  643. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
  644. package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
  645. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  646. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
  647. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  648. package/src/resources/extensions/gsd/reports.ts +5 -4
  649. package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
  650. package/src/resources/extensions/gsd/service-tier.ts +5 -2
  651. package/src/resources/extensions/gsd/session-lock.ts +20 -10
  652. package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
  653. package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
  654. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
  655. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  656. package/src/resources/extensions/gsd/state.ts +76 -66
  657. package/src/resources/extensions/gsd/sync-lock.ts +97 -39
  658. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
  659. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
  660. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
  661. package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
  662. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +135 -285
  663. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  664. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
  665. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
  666. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
  667. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +166 -0
  668. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
  669. package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
  670. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +64 -0
  671. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
  672. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
  673. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
  674. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
  675. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
  676. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
  677. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
  678. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
  679. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  680. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
  681. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
  682. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
  683. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
  684. package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
  685. package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
  686. package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
  687. package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
  688. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
  689. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
  690. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
  691. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  692. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
  693. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
  694. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
  695. package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
  696. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
  697. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
  698. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  699. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  700. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  701. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  702. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
  703. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
  704. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
  705. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  706. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
  707. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  708. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
  709. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
  710. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
  711. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  712. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  713. package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
  714. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
  715. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
  716. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  717. package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
  718. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  719. package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
  720. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
  721. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
  722. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
  723. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  724. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
  725. package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
  726. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
  727. package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
  728. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +47 -0
  729. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
  730. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
  731. package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
  732. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  733. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  734. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  735. package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
  736. package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
  737. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
  738. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
  739. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
  740. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  741. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
  742. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  743. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
  744. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
  745. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
  746. package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
  747. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
  748. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +54 -41
  749. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +213 -0
  750. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
  751. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
  752. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  753. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
  754. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
  755. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
  756. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
  757. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  758. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
  759. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
  760. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  761. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
  762. package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
  763. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
  764. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
  765. package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
  766. package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
  767. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
  768. package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
  769. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
  770. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
  771. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
  772. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
  773. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  774. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
  775. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  776. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
  777. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
  778. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  779. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
  780. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
  781. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
  782. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
  783. package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
  784. package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
  785. package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
  786. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
  787. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
  788. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  789. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  790. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
  791. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
  792. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  793. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  794. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
  795. package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
  796. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  797. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  798. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
  799. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  800. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  801. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +139 -5
  802. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
  803. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
  804. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
  805. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
  806. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  807. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
  808. package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
  809. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
  810. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
  811. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
  812. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
  813. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
  814. package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
  815. package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
  816. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
  817. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  818. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  819. package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
  820. package/src/resources/extensions/gsd/types.ts +3 -3
  821. package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
  822. package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
  823. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  824. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  825. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  826. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  827. package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
  828. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  829. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  830. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  831. package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
  832. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  833. package/src/resources/extensions/gsd/workflow-logger.ts +22 -3
  834. package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
  835. package/src/resources/extensions/gsd/worktree-manager.ts +109 -7
  836. package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
  837. package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
  838. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  839. package/src/resources/extensions/mcp-client/index.ts +132 -11
  840. package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
  841. package/src/resources/extensions/ollama/index.ts +5 -1
  842. package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
  843. package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
  844. package/src/resources/extensions/remote-questions/manager.ts +36 -4
  845. package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
  846. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  847. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  848. package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
  849. package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
  850. package/src/resources/skills/create-skill/SKILL.md +2 -2
  851. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  852. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  853. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  854. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  855. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  856. package/dist/web/standalone/.next/static/chunks/app/page-151349214571e2b6.js +0 -1
  857. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  858. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  859. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
  860. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
  861. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
  862. package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
  863. package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
  864. package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
  865. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -142
  866. package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
  867. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
  868. package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
  869. package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
  870. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
  871. package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
  872. package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
  873. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
  874. package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
  875. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
  876. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
  877. /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
  878. /package/dist/web/standalone/.next/static/{pV-mPo7rYGb5JBC09C8GG → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
@@ -4,7 +4,8 @@
4
4
  */
5
5
  import assert from "node:assert/strict";
6
6
  import { describe, it, mock } from "node:test";
7
- import { generateSummary, estimateTokens, chunkMessages } from "./compaction.js";
7
+ import { generateSummary, estimateTokens, chunkMessages, isDegenerateSummary, CompactionProducedNoSummaryError } from "./compaction.js";
8
+ import { estimateSerializedTokens } from "./utils.js";
8
9
  // ---------------------------------------------------------------------------
9
10
  // Helpers
10
11
  // ---------------------------------------------------------------------------
@@ -13,6 +14,37 @@ function makeUserMessage(tokenCount) {
13
14
  const text = "x".repeat(tokenCount * 4);
14
15
  return { role: "user", content: text };
15
16
  }
17
+ /**
18
+ * Create a tool-result message of approximately `rawTokenCount` uncapped tokens.
19
+ * Post-truncation, this estimates to ~500 tokens (TOOL_RESULT_MAX_CHARS / 4).
20
+ *
21
+ * Used to exercise the #4665 regression: before the fix, chunkMessages used
22
+ * estimateTokens (pre-truncation), so a 100K-token tool result forced its own
23
+ * chunk even though it serialized to ~500 tokens. After the fix, many tool
24
+ * results coalesce into a single chunk.
25
+ */
26
+ function makeToolResultMessage(rawTokenCount) {
27
+ const text = "y".repeat(rawTokenCount * 4);
28
+ return {
29
+ role: "toolResult",
30
+ toolCallId: `call_${rawTokenCount}`,
31
+ content: [{ type: "text", text }],
32
+ };
33
+ }
34
+ /**
35
+ * Create a branch-summary message with a specific summary length. Summary
36
+ * messages are intentionally NOT truncated by the serializer (they're already
37
+ * concise), so this is the right tool to force chunking post-fix.
38
+ */
39
+ function makeBranchSummaryMessage(approxTokens) {
40
+ const summary = "z".repeat(approxTokens * 4);
41
+ return {
42
+ role: "branchSummary",
43
+ summary,
44
+ fromId: "test",
45
+ timestamp: 0,
46
+ };
47
+ }
16
48
  /** Create a mock model with a given context window. */
17
49
  function makeModel(contextWindow) {
18
50
  return {
@@ -48,61 +80,97 @@ describe("chunkMessages", () => {
48
80
  assert.equal(chunks[0].length, 2);
49
81
  });
50
82
  it("splits messages into multiple chunks when they exceed budget", () => {
83
+ // Use branchSummary messages — they aren't capped by the serializer, so
84
+ // their post-serialization size matches their raw size. Each 50k-token
85
+ // summary must get its own chunk under an 80k budget.
51
86
  const messages = [
52
- makeUserMessage(50_000),
53
- makeUserMessage(50_000),
54
- makeUserMessage(50_000),
87
+ makeBranchSummaryMessage(50_000),
88
+ makeBranchSummaryMessage(50_000),
89
+ makeBranchSummaryMessage(50_000),
55
90
  ];
56
- // Budget of 80k tokens means each 50k message gets its own chunk
57
- // (or two fit together if budget allows)
58
91
  const chunks = chunkMessages(messages, 80_000);
59
92
  assert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);
60
- // All messages should be present across chunks
61
93
  const totalMessages = chunks.reduce((sum, c) => sum + c.length, 0);
62
94
  assert.equal(totalMessages, 3);
63
95
  });
64
96
  it("puts a single oversized message in its own chunk", () => {
65
- const messages = [
66
- makeUserMessage(200_000), // Way over any reasonable budget
67
- ];
97
+ // Use branchSummary — not truncated by the serializer — to force the
98
+ // oversized-single-message path. A user message with the same raw size
99
+ // would cap to ~500 tokens and fit in any reasonable budget.
100
+ const messages = [makeBranchSummaryMessage(200_000)];
68
101
  const chunks = chunkMessages(messages, 80_000);
69
102
  assert.equal(chunks.length, 1);
70
103
  assert.equal(chunks[0].length, 1);
71
104
  });
72
105
  it("preserves message order across chunks", () => {
73
- // Create messages with identifiable sizes
74
106
  const messages = [
75
- makeUserMessage(30_000), // ~30k tokens
76
- makeUserMessage(30_000),
77
- makeUserMessage(30_000),
78
- makeUserMessage(30_000),
107
+ makeBranchSummaryMessage(30_000),
108
+ makeBranchSummaryMessage(30_000),
109
+ makeBranchSummaryMessage(30_000),
110
+ makeBranchSummaryMessage(30_000),
79
111
  ];
80
112
  const chunks = chunkMessages(messages, 50_000);
81
- // Reconstruct original order
82
113
  const flat = chunks.flat();
83
114
  assert.equal(flat.length, 4);
84
115
  for (let i = 0; i < flat.length; i++) {
85
116
  assert.strictEqual(flat[i], messages[i], `Message ${i} should be in order`);
86
117
  }
87
118
  });
119
+ // ---------------------------------------------------------------------------
120
+ // #4665 regression: token estimation must reflect serializer truncation
121
+ // ---------------------------------------------------------------------------
122
+ it("(#4665) does not over-split when tool results dominate — they serialize to ~500 tokens", () => {
123
+ // Ten 100K-token tool results. Under the old pre-truncation estimator
124
+ // this would estimate to ~1M tokens and force 10+ tiny chunks. Under
125
+ // the new estimator each caps to ~500 tokens (TOOL_RESULT_MAX_CHARS/4),
126
+ // so 10 of them total ~5K tokens and fit in a single generous budget.
127
+ const messages = Array.from({ length: 10 }, () => makeToolResultMessage(100_000));
128
+ const chunks = chunkMessages(messages, 50_000);
129
+ assert.equal(chunks.length, 1, "ten 100K-token tool results should coalesce into one chunk (cap=2000 chars → ~500 tokens each)");
130
+ assert.equal(chunks[0].length, 10);
131
+ });
132
+ it("(#4665) estimateSerializedTokens caps toolResult at TOOL_RESULT_MAX_CHARS/4", () => {
133
+ const huge = makeToolResultMessage(100_000);
134
+ const serialized = estimateSerializedTokens(huge);
135
+ const raw = estimateTokens(huge);
136
+ assert.ok(raw > 50_000, `raw estimator should report the real size, got ${raw}`);
137
+ assert.ok(serialized < 1_000, `serialized estimator should cap at ~500 tokens, got ${serialized}`);
138
+ });
139
+ it("(#4665) estimateSerializedTokens also caps large user content and assistant thinking", () => {
140
+ const hugeUser = makeUserMessage(50_000);
141
+ assert.ok(estimateSerializedTokens(hugeUser) < 1_000, "user content > cap must be truncated in the estimator");
142
+ // Assistant with a huge thinking block + huge text block
143
+ const hugeAssistant = {
144
+ role: "assistant",
145
+ content: [
146
+ { type: "thinking", thinking: "t".repeat(100_000) },
147
+ { type: "text", text: "r".repeat(100_000) },
148
+ ],
149
+ };
150
+ assert.ok(estimateSerializedTokens(hugeAssistant) < 2_000, "assistant thinking + text must each cap; total under 2x TOOL_RESULT_MAX_CHARS/4");
151
+ });
88
152
  });
89
153
  // ---------------------------------------------------------------------------
90
154
  // generateSummary chunked fallback tests
91
155
  // ---------------------------------------------------------------------------
92
156
  describe("generateSummary — chunked fallback (#2932)", () => {
93
157
  it("calls _completeFn multiple times when messages exceed model context window", async () => {
94
- // Arrange: 3 messages of ~80k tokens each = ~240k total, model has 200k window
158
+ // Use branchSummary messages not capped by the serializer so the
159
+ // chunker's post-truncation view matches the raw view. 3 × 80k summaries
160
+ // totalling 240k tokens must exceed a 200k context window.
95
161
  const messages = [
96
- makeUserMessage(80_000),
97
- makeUserMessage(80_000),
98
- makeUserMessage(80_000),
162
+ makeBranchSummaryMessage(80_000),
163
+ makeBranchSummaryMessage(80_000),
164
+ makeBranchSummaryMessage(80_000),
99
165
  ];
100
166
  const model = makeModel(200_000);
101
167
  const reserveTokens = 16_384;
102
- // Verify our test setup: messages really do exceed the model window
168
+ // Verify our test setup: messages really do exceed the model window.
169
+ // Use estimateSerializedTokens because that's what generateSummary uses
170
+ // for its "does this fit?" decision post-#4665.
103
171
  let totalTokens = 0;
104
172
  for (const m of messages)
105
- totalTokens += estimateTokens(m);
173
+ totalTokens += estimateSerializedTokens(m);
106
174
  assert.ok(totalTokens > model.contextWindow, `Test setup: ${totalTokens} tokens should exceed ${model.contextWindow} context window`);
107
175
  // Track calls
108
176
  const calls = [];
@@ -117,7 +185,10 @@ describe("generateSummary — chunked fallback (#2932)", () => {
117
185
  else {
118
186
  calls.push("initial");
119
187
  }
120
- return makeFakeResponse("Summary of chunk");
188
+ // Return a non-degenerate summary (>100 chars). Short responses like
189
+ // "Summary of chunk" would trip the #4665 degenerate-output guard,
190
+ // which is exactly what we don't want to test here.
191
+ return makeFakeResponse("## Goal\nDetailed summary of this chunk describing the work completed, files touched, and decisions made. At least 100 characters so the degenerate guard does not trip.");
121
192
  });
122
193
  const summary = await generateSummary(messages, model, reserveTokens, undefined, // apiKey
123
194
  undefined, // signal
@@ -152,13 +223,13 @@ describe("generateSummary — chunked fallback (#2932)", () => {
152
223
  });
153
224
  it("passes previousSummary through chunked summarization", async () => {
154
225
  const messages = [
155
- makeUserMessage(80_000),
156
- makeUserMessage(80_000),
157
- makeUserMessage(80_000),
226
+ makeBranchSummaryMessage(80_000),
227
+ makeBranchSummaryMessage(80_000),
228
+ makeBranchSummaryMessage(80_000),
158
229
  ];
159
230
  const model = makeModel(200_000);
160
231
  const reserveTokens = 16_384;
161
- const previousSummary = "Previous session summary content";
232
+ const previousSummary = "Previous session summary content — intentionally verbose enough to clear the degenerate-summary threshold so this test exercises the actual propagation path.";
162
233
  const prompts = [];
163
234
  const mockComplete = mock.fn(async (_model, context) => {
164
235
  const userMsg = context.messages?.[0];
@@ -166,11 +237,142 @@ describe("generateSummary — chunked fallback (#2932)", () => {
166
237
  ? userMsg.content
167
238
  : userMsg?.content?.[0]?.text ?? "";
168
239
  prompts.push(text);
169
- return makeFakeResponse("Chunk summary");
240
+ return makeFakeResponse("Chunk summary with sufficient length to clear the #4665 degenerate-output guard threshold of 100 characters — this must be longer.");
170
241
  });
171
242
  await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, previousSummary, mockComplete);
172
243
  // First chunk should include the previousSummary
173
244
  assert.ok(prompts[0].includes(previousSummary), "First chunk should incorporate the previousSummary");
174
245
  });
175
246
  });
247
+ // ---------------------------------------------------------------------------
248
+ // #4665 regression — iterative chain must not propagate degenerate summaries
249
+ // ---------------------------------------------------------------------------
250
+ describe("(#4665) degenerate summary guard", () => {
251
+ it("isDegenerateSummary detects the known failure patterns", () => {
252
+ assert.equal(isDegenerateSummary(undefined), false);
253
+ assert.equal(isDegenerateSummary(""), true, "empty string is degenerate");
254
+ assert.equal(isDegenerateSummary("too short"), true, "short output is degenerate");
255
+ assert.equal(isDegenerateSummary("The user asked me to summarize an empty conversation"), true, "known failure phrase 'empty conversation' is degenerate");
256
+ assert.equal(isDegenerateSummary("No conversation to summarize"), true, "'no conversation to summarize' is degenerate");
257
+ assert.equal(isDegenerateSummary("## Goal\nRefactor the compaction pipeline.\n## Done\n- Updated utils.ts\n- Added tests for #4665 regression path"), false, "a real multi-section summary over 100 chars is not degenerate");
258
+ });
259
+ it("does not propagate a degenerate first-chunk summary forward (no 'preserve nothing' chain)", async () => {
260
+ // Force the chunked path with uncapped summary messages.
261
+ const messages = [
262
+ makeBranchSummaryMessage(80_000),
263
+ makeBranchSummaryMessage(80_000),
264
+ makeBranchSummaryMessage(80_000),
265
+ ];
266
+ const model = makeModel(200_000);
267
+ const reserveTokens = 16_384;
268
+ // Responses: chunk 0 returns degenerate ("empty conversation"). Chunks
269
+ // 1 and 2 return real summaries. Pre-fix behavior: the chunk-0 output
270
+ // is fed into UPDATE_SUMMARIZATION_PROMPT for chunks 1+, which says
271
+ // "PRESERVE all existing information" — so emptiness is preserved.
272
+ // Post-fix: the degenerate chunk-0 output must not become runningSummary.
273
+ let callIndex = 0;
274
+ const responses = [
275
+ "The user asked me to summarize an empty conversation.",
276
+ "## Done\n- Refactored the serializer to head+tail truncation.\n- Updated chunker to use post-serialization token estimate.",
277
+ "## Done\n- Added regression tests for #4665 including this propagation guard.\n- Verified isDegenerateSummary handles known failure patterns.",
278
+ ];
279
+ const seenPrompts = [];
280
+ const mockComplete = mock.fn(async (_model, context) => {
281
+ const userMsg = context.messages?.[0];
282
+ const text = typeof userMsg?.content === "string"
283
+ ? userMsg.content
284
+ : userMsg?.content?.[0]?.text ?? "";
285
+ seenPrompts.push(text);
286
+ const response = responses[Math.min(callIndex, responses.length - 1)];
287
+ callIndex++;
288
+ return makeFakeResponse(response);
289
+ });
290
+ const summary = await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);
291
+ // The returned summary must be one of the real chunk summaries — not
292
+ // the degenerate "empty conversation" output, and not an empty string.
293
+ assert.ok(!isDegenerateSummary(summary), `final summary should not be degenerate. got: ${JSON.stringify(summary)}`);
294
+ assert.ok(summary.includes("Refactored") || summary.includes("regression tests"), "final summary should carry real information from chunks 1 or 2");
295
+ });
296
+ it("retries the first chunk once with the initial prompt if the first pass is degenerate", async () => {
297
+ // Force chunked path with a single large chunk. Mock returns degenerate
298
+ // on the first call and a real summary on the retry.
299
+ const messages = [
300
+ makeBranchSummaryMessage(80_000),
301
+ makeBranchSummaryMessage(80_000),
302
+ ];
303
+ const model = makeModel(100_000); // small window forces chunking
304
+ const reserveTokens = 16_384;
305
+ const responses = [
306
+ "", // first attempt: empty string → degenerate
307
+ "## Goal\nReal summary produced on the retry pass after the initial pass came back empty — this should land as the running summary.",
308
+ "## Done\n- Added retry-on-degenerate-first-chunk behavior to the iterative summarizer so empty outputs don't poison the chain.",
309
+ ];
310
+ let callIndex = 0;
311
+ const mockComplete = mock.fn(async () => {
312
+ const response = responses[Math.min(callIndex, responses.length - 1)];
313
+ callIndex++;
314
+ return makeFakeResponse(response);
315
+ });
316
+ const summary = await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);
317
+ assert.ok(!isDegenerateSummary(summary), "final summary must not be degenerate after the retry took effect");
318
+ assert.ok(mockComplete.mock.callCount() >= 3, `expected at least 3 calls (first attempt, retry, second chunk), got ${mockComplete.mock.callCount()}`);
319
+ });
320
+ // -------------------------------------------------------------------------
321
+ // R1 — retry non-first chunks too + observable log when both attempts fail
322
+ // -------------------------------------------------------------------------
323
+ it("(R1) retries a degenerate NON-FIRST chunk before silently dropping it", async () => {
324
+ // Use a small model window to force exactly 2 chunks from 2 messages.
325
+ // Chunk 0 ok, chunk 1 degenerate on first try then real on retry.
326
+ // Chunk 1's recovered content must reach the final summary.
327
+ const messages = [
328
+ makeBranchSummaryMessage(80_000),
329
+ makeBranchSummaryMessage(80_000),
330
+ ];
331
+ const model = makeModel(100_000);
332
+ const reserveTokens = 16_384;
333
+ const CHUNK0_SUMMARY = "## Done\n- Chunk 0 real summary with enough length to clear the degenerate threshold of 100 characters — easily.";
334
+ const CHUNK1_RETRY_SUMMARY = "## Done\n- Chunk 1 recovered on retry — its content must appear in the final summary or the R1 fix regressed for non-first chunks.";
335
+ let callIndex = 0;
336
+ const responses = [
337
+ CHUNK0_SUMMARY, // chunk 0
338
+ "empty conversation", // chunk 1 first try → degenerate
339
+ CHUNK1_RETRY_SUMMARY, // chunk 1 retry → real
340
+ ];
341
+ const mockComplete = mock.fn(async () => {
342
+ const r = responses[Math.min(callIndex, responses.length - 1)];
343
+ callIndex++;
344
+ return makeFakeResponse(r);
345
+ });
346
+ const summary = await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);
347
+ assert.equal(mockComplete.mock.callCount(), 3, "expected 3 calls: chunk 0 + chunk 1 initial + chunk 1 retry");
348
+ assert.ok(summary.includes("recovered on retry"), `final summary must include chunk 1's retry content (R1: non-first chunks must also retry), got: ${JSON.stringify(summary)}`);
349
+ });
350
+ // -------------------------------------------------------------------------
351
+ // R6 — empty output must not be silently written as a compaction entry
352
+ // -------------------------------------------------------------------------
353
+ it("(R6) throws CompactionProducedNoSummaryError when every chunk is degenerate AND no previousSummary", async () => {
354
+ const messages = [
355
+ makeBranchSummaryMessage(80_000),
356
+ makeBranchSummaryMessage(80_000),
357
+ ];
358
+ const model = makeModel(100_000);
359
+ const reserveTokens = 16_384;
360
+ // Every response is degenerate, both initial and retry attempts.
361
+ const mockComplete = mock.fn(async () => makeFakeResponse("empty conversation"));
362
+ await assert.rejects(() => generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, // no previousSummary
363
+ mockComplete), (err) => err instanceof CompactionProducedNoSummaryError, "expected CompactionProducedNoSummaryError when all chunks degenerate and no previousSummary");
364
+ });
365
+ it("(R6) falls back to previousSummary when every chunk is degenerate", async () => {
366
+ const messages = [
367
+ makeBranchSummaryMessage(80_000),
368
+ makeBranchSummaryMessage(80_000),
369
+ ];
370
+ const model = makeModel(100_000);
371
+ const reserveTokens = 16_384;
372
+ const previousSummary = "Previously-computed summary from the last compaction — deliberately long enough to clear the degenerate-output threshold.";
373
+ const mockComplete = mock.fn(async () => makeFakeResponse("empty conversation"));
374
+ const result = await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, previousSummary, mockComplete);
375
+ assert.equal(result, previousSummary, "when all chunks degenerate, must fall back to previousSummary rather than return empty string");
376
+ });
377
+ });
176
378
  //# sourceMappingURL=compaction.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.test.js","sourceRoot":"","sources":["../../../src/core/compaction/compaction.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for chunked compaction fallback when messages exceed model context window.\n * Regression test for #2932.\n */\n\nimport assert from \"node:assert/strict\";\nimport { describe, it, mock } from \"node:test\";\n\nimport type { AgentMessage } from \"@gsd/pi-agent-core\";\nimport type { Model, AssistantMessage } from \"@gsd/pi-ai\";\n\nimport { generateSummary, estimateTokens, chunkMessages } from \"./compaction.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Create a user message with approximately `tokenCount` tokens (chars = tokens * 4). */\nfunction makeUserMessage(tokenCount: number): AgentMessage {\n\tconst text = \"x\".repeat(tokenCount * 4);\n\treturn { role: \"user\", content: text } as unknown as AgentMessage;\n}\n\n/** Create a mock model with a given context window. */\nfunction makeModel(contextWindow: number): Model<any> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"anthropic-messages\",\n\t\tprovider: \"anthropic\",\n\t\tbaseUrl: \"https://api.test\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow,\n\t\tmaxTokens: 4096,\n\t} as Model<any>;\n}\n\nfunction makeFakeResponse(text: string): AssistantMessage {\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tstopReason: \"end_turn\",\n\t} as unknown as AssistantMessage;\n}\n\n// ---------------------------------------------------------------------------\n// chunkMessages tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"chunkMessages\", () => {\n\tit(\"returns a single chunk when messages fit in budget\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(1_000),\n\t\t\tmakeUserMessage(1_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 100_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 2);\n\t});\n\n\tit(\"splits messages into multiple chunks when they exceed budget\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(50_000),\n\t\t\tmakeUserMessage(50_000),\n\t\t\tmakeUserMessage(50_000),\n\t\t];\n\t\t// Budget of 80k tokens means each 50k message gets its own chunk\n\t\t// (or two fit together if budget allows)\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);\n\t\t// All messages should be present across chunks\n\t\tconst totalMessages = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\tassert.equal(totalMessages, 3);\n\t});\n\n\tit(\"puts a single oversized message in its own chunk\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(200_000), // Way over any reasonable budget\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 1);\n\t});\n\n\tit(\"preserves message order across chunks\", () => {\n\t\t// Create messages with identifiable sizes\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(30_000), // ~30k tokens\n\t\t\tmakeUserMessage(30_000),\n\t\t\tmakeUserMessage(30_000),\n\t\t\tmakeUserMessage(30_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 50_000);\n\t\t// Reconstruct original order\n\t\tconst flat = chunks.flat();\n\t\tassert.equal(flat.length, 4);\n\t\tfor (let i = 0; i < flat.length; i++) {\n\t\t\tassert.strictEqual(flat[i], messages[i], `Message ${i} should be in order`);\n\t\t}\n\t});\n});\n\n// ---------------------------------------------------------------------------\n// generateSummary chunked fallback tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"generateSummary — chunked fallback (#2932)\", () => {\n\tit(\"calls _completeFn multiple times when messages exceed model context window\", async () => {\n\t\t// Arrange: 3 messages of ~80k tokens each = ~240k total, model has 200k window\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify our test setup: messages really do exceed the model window\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens > model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should exceed ${model.contextWindow} context window`,\n\t\t);\n\n\t\t// Track calls\n\t\tconst calls: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any, _options: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\n\t\t\tif (text.includes(\"<previous-summary>\")) {\n\t\t\t\tcalls.push(\"update\");\n\t\t\t} else {\n\t\t\t\tcalls.push(\"initial\");\n\t\t\t}\n\t\t\treturn makeFakeResponse(\"Summary of chunk\");\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined, // apiKey\n\t\t\tundefined, // signal\n\t\t\tundefined, // customInstructions\n\t\t\tundefined, // previousSummary\n\t\t\tmockComplete, // _completeFn override for testing\n\t\t);\n\n\t\t// Assert: should have called completeSimple more than once (chunked)\n\t\tassert.ok(\n\t\t\tmockComplete.mock.callCount() > 1,\n\t\t\t`Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount()}`,\n\t\t);\n\n\t\t// First call should be an initial summary, subsequent should be updates\n\t\tassert.equal(calls[0], \"initial\", \"First chunk should use initial summarization prompt\");\n\t\tfor (let i = 1; i < calls.length; i++) {\n\t\t\tassert.equal(calls[i], \"update\", `Chunk ${i + 1} should use update summarization prompt`);\n\t\t}\n\n\t\t// Should return a non-empty summary\n\t\tassert.ok(summary.length > 0, \"Summary should not be empty\");\n\t});\n\n\tit(\"uses single-pass when messages fit within model context window\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(10_000),\n\t\t\tmakeUserMessage(10_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify test setup\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens < model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should fit in ${model.contextWindow} context window`,\n\t\t);\n\n\t\tconst mockComplete = mock.fn(async () => makeFakeResponse(\"Single pass summary\"));\n\n\t\tawait generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);\n\n\t\tassert.equal(\n\t\t\tmockComplete.mock.callCount(),\n\t\t\t1,\n\t\t\t\"Should use single-pass summarization when messages fit in context window\",\n\t\t);\n\t});\n\n\tit(\"passes previousSummary through chunked summarization\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t\tmakeUserMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\t\tconst previousSummary = \"Previous session summary content\";\n\n\t\tconst prompts: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\t\t\tprompts.push(text);\n\t\t\treturn makeFakeResponse(\"Chunk summary\");\n\t\t});\n\n\t\tawait generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tpreviousSummary,\n\t\t\tmockComplete,\n\t\t);\n\n\t\t// First chunk should include the previousSummary\n\t\tassert.ok(\n\t\t\tprompts[0].includes(previousSummary),\n\t\t\t\"First chunk should incorporate the previousSummary\",\n\t\t);\n\t});\n});\n"]}
1
+ {"version":3,"file":"compaction.test.js","sourceRoot":"","sources":["../../../src/core/compaction/compaction.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for chunked compaction fallback when messages exceed model context window.\n * Regression test for #2932.\n */\n\nimport assert from \"node:assert/strict\";\nimport { describe, it, mock } from \"node:test\";\n\nimport type { AgentMessage } from \"@gsd/pi-agent-core\";\nimport type { Model, AssistantMessage } from \"@gsd/pi-ai\";\n\nimport { generateSummary, estimateTokens, chunkMessages, isDegenerateSummary, CompactionProducedNoSummaryError } from \"./compaction.js\";\nimport { estimateSerializedTokens } from \"./utils.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Create a user message with approximately `tokenCount` tokens (chars = tokens * 4). */\nfunction makeUserMessage(tokenCount: number): AgentMessage {\n\tconst text = \"x\".repeat(tokenCount * 4);\n\treturn { role: \"user\", content: text } as unknown as AgentMessage;\n}\n\n/**\n * Create a tool-result message of approximately `rawTokenCount` uncapped tokens.\n * Post-truncation, this estimates to ~500 tokens (TOOL_RESULT_MAX_CHARS / 4).\n *\n * Used to exercise the #4665 regression: before the fix, chunkMessages used\n * estimateTokens (pre-truncation), so a 100K-token tool result forced its own\n * chunk even though it serialized to ~500 tokens. After the fix, many tool\n * results coalesce into a single chunk.\n */\nfunction makeToolResultMessage(rawTokenCount: number): AgentMessage {\n\tconst text = \"y\".repeat(rawTokenCount * 4);\n\treturn {\n\t\trole: \"toolResult\",\n\t\ttoolCallId: `call_${rawTokenCount}`,\n\t\tcontent: [{ type: \"text\", text }],\n\t} as unknown as AgentMessage;\n}\n\n/**\n * Create a branch-summary message with a specific summary length. Summary\n * messages are intentionally NOT truncated by the serializer (they're already\n * concise), so this is the right tool to force chunking post-fix.\n */\nfunction makeBranchSummaryMessage(approxTokens: number): AgentMessage {\n\tconst summary = \"z\".repeat(approxTokens * 4);\n\treturn {\n\t\trole: \"branchSummary\",\n\t\tsummary,\n\t\tfromId: \"test\",\n\t\ttimestamp: 0,\n\t} as unknown as AgentMessage;\n}\n\n/** Create a mock model with a given context window. */\nfunction makeModel(contextWindow: number): Model<any> {\n\treturn {\n\t\tid: \"test-model\",\n\t\tname: \"Test Model\",\n\t\tapi: \"anthropic-messages\",\n\t\tprovider: \"anthropic\",\n\t\tbaseUrl: \"https://api.test\",\n\t\treasoning: false,\n\t\tinput: [\"text\"],\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },\n\t\tcontextWindow,\n\t\tmaxTokens: 4096,\n\t} as Model<any>;\n}\n\nfunction makeFakeResponse(text: string): AssistantMessage {\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tstopReason: \"end_turn\",\n\t} as unknown as AssistantMessage;\n}\n\n// ---------------------------------------------------------------------------\n// chunkMessages tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"chunkMessages\", () => {\n\tit(\"returns a single chunk when messages fit in budget\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(1_000),\n\t\t\tmakeUserMessage(1_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 100_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 2);\n\t});\n\n\tit(\"splits messages into multiple chunks when they exceed budget\", () => {\n\t\t// Use branchSummary messages — they aren't capped by the serializer, so\n\t\t// their post-serialization size matches their raw size. Each 50k-token\n\t\t// summary must get its own chunk under an 80k budget.\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(50_000),\n\t\t\tmakeBranchSummaryMessage(50_000),\n\t\t\tmakeBranchSummaryMessage(50_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.ok(chunks.length > 1, `Expected multiple chunks, got ${chunks.length}`);\n\t\tconst totalMessages = chunks.reduce((sum, c) => sum + c.length, 0);\n\t\tassert.equal(totalMessages, 3);\n\t});\n\n\tit(\"puts a single oversized message in its own chunk\", () => {\n\t\t// Use branchSummary — not truncated by the serializer — to force the\n\t\t// oversized-single-message path. A user message with the same raw size\n\t\t// would cap to ~500 tokens and fit in any reasonable budget.\n\t\tconst messages: AgentMessage[] = [makeBranchSummaryMessage(200_000)];\n\t\tconst chunks = chunkMessages(messages, 80_000);\n\t\tassert.equal(chunks.length, 1);\n\t\tassert.equal(chunks[0].length, 1);\n\t});\n\n\tit(\"preserves message order across chunks\", () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(30_000),\n\t\t\tmakeBranchSummaryMessage(30_000),\n\t\t\tmakeBranchSummaryMessage(30_000),\n\t\t\tmakeBranchSummaryMessage(30_000),\n\t\t];\n\t\tconst chunks = chunkMessages(messages, 50_000);\n\t\tconst flat = chunks.flat();\n\t\tassert.equal(flat.length, 4);\n\t\tfor (let i = 0; i < flat.length; i++) {\n\t\t\tassert.strictEqual(flat[i], messages[i], `Message ${i} should be in order`);\n\t\t}\n\t});\n\n\t// ---------------------------------------------------------------------------\n\t// #4665 regression: token estimation must reflect serializer truncation\n\t// ---------------------------------------------------------------------------\n\n\tit(\"(#4665) does not over-split when tool results dominate — they serialize to ~500 tokens\", () => {\n\t\t// Ten 100K-token tool results. Under the old pre-truncation estimator\n\t\t// this would estimate to ~1M tokens and force 10+ tiny chunks. Under\n\t\t// the new estimator each caps to ~500 tokens (TOOL_RESULT_MAX_CHARS/4),\n\t\t// so 10 of them total ~5K tokens and fit in a single generous budget.\n\t\tconst messages: AgentMessage[] = Array.from({ length: 10 }, () =>\n\t\t\tmakeToolResultMessage(100_000),\n\t\t);\n\t\tconst chunks = chunkMessages(messages, 50_000);\n\t\tassert.equal(\n\t\t\tchunks.length,\n\t\t\t1,\n\t\t\t\"ten 100K-token tool results should coalesce into one chunk (cap=2000 chars → ~500 tokens each)\",\n\t\t);\n\t\tassert.equal(chunks[0].length, 10);\n\t});\n\n\tit(\"(#4665) estimateSerializedTokens caps toolResult at TOOL_RESULT_MAX_CHARS/4\", () => {\n\t\tconst huge = makeToolResultMessage(100_000);\n\t\tconst serialized = estimateSerializedTokens(huge);\n\t\tconst raw = estimateTokens(huge);\n\t\tassert.ok(raw > 50_000, `raw estimator should report the real size, got ${raw}`);\n\t\tassert.ok(\n\t\t\tserialized < 1_000,\n\t\t\t`serialized estimator should cap at ~500 tokens, got ${serialized}`,\n\t\t);\n\t});\n\n\tit(\"(#4665) estimateSerializedTokens also caps large user content and assistant thinking\", () => {\n\t\tconst hugeUser = makeUserMessage(50_000);\n\t\tassert.ok(\n\t\t\testimateSerializedTokens(hugeUser) < 1_000,\n\t\t\t\"user content > cap must be truncated in the estimator\",\n\t\t);\n\n\t\t// Assistant with a huge thinking block + huge text block\n\t\tconst hugeAssistant: AgentMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [\n\t\t\t\t{ type: \"thinking\", thinking: \"t\".repeat(100_000) },\n\t\t\t\t{ type: \"text\", text: \"r\".repeat(100_000) },\n\t\t\t],\n\t\t} as unknown as AgentMessage;\n\t\tassert.ok(\n\t\t\testimateSerializedTokens(hugeAssistant) < 2_000,\n\t\t\t\"assistant thinking + text must each cap; total under 2x TOOL_RESULT_MAX_CHARS/4\",\n\t\t);\n\t});\n});\n\n// ---------------------------------------------------------------------------\n// generateSummary chunked fallback tests\n// ---------------------------------------------------------------------------\n\ndescribe(\"generateSummary — chunked fallback (#2932)\", () => {\n\tit(\"calls _completeFn multiple times when messages exceed model context window\", async () => {\n\t\t// Use branchSummary messages — not capped by the serializer — so the\n\t\t// chunker's post-truncation view matches the raw view. 3 × 80k summaries\n\t\t// totalling 240k tokens must exceed a 200k context window.\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify our test setup: messages really do exceed the model window.\n\t\t// Use estimateSerializedTokens because that's what generateSummary uses\n\t\t// for its \"does this fit?\" decision post-#4665.\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateSerializedTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens > model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should exceed ${model.contextWindow} context window`,\n\t\t);\n\n\t\t// Track calls\n\t\tconst calls: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any, _options: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\n\t\t\tif (text.includes(\"<previous-summary>\")) {\n\t\t\t\tcalls.push(\"update\");\n\t\t\t} else {\n\t\t\t\tcalls.push(\"initial\");\n\t\t\t}\n\t\t\t// Return a non-degenerate summary (>100 chars). Short responses like\n\t\t\t// \"Summary of chunk\" would trip the #4665 degenerate-output guard,\n\t\t\t// which is exactly what we don't want to test here.\n\t\t\treturn makeFakeResponse(\n\t\t\t\t\"## Goal\\nDetailed summary of this chunk describing the work completed, files touched, and decisions made. At least 100 characters so the degenerate guard does not trip.\",\n\t\t\t);\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined, // apiKey\n\t\t\tundefined, // signal\n\t\t\tundefined, // customInstructions\n\t\t\tundefined, // previousSummary\n\t\t\tmockComplete, // _completeFn override for testing\n\t\t);\n\n\t\t// Assert: should have called completeSimple more than once (chunked)\n\t\tassert.ok(\n\t\t\tmockComplete.mock.callCount() > 1,\n\t\t\t`Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount()}`,\n\t\t);\n\n\t\t// First call should be an initial summary, subsequent should be updates\n\t\tassert.equal(calls[0], \"initial\", \"First chunk should use initial summarization prompt\");\n\t\tfor (let i = 1; i < calls.length; i++) {\n\t\t\tassert.equal(calls[i], \"update\", `Chunk ${i + 1} should use update summarization prompt`);\n\t\t}\n\n\t\t// Should return a non-empty summary\n\t\tassert.ok(summary.length > 0, \"Summary should not be empty\");\n\t});\n\n\tit(\"uses single-pass when messages fit within model context window\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeUserMessage(10_000),\n\t\t\tmakeUserMessage(10_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Verify test setup\n\t\tlet totalTokens = 0;\n\t\tfor (const m of messages) totalTokens += estimateTokens(m);\n\t\tassert.ok(\n\t\t\ttotalTokens < model.contextWindow,\n\t\t\t`Test setup: ${totalTokens} tokens should fit in ${model.contextWindow} context window`,\n\t\t);\n\n\t\tconst mockComplete = mock.fn(async () => makeFakeResponse(\"Single pass summary\"));\n\n\t\tawait generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete);\n\n\t\tassert.equal(\n\t\t\tmockComplete.mock.callCount(),\n\t\t\t1,\n\t\t\t\"Should use single-pass summarization when messages fit in context window\",\n\t\t);\n\t});\n\n\tit(\"passes previousSummary through chunked summarization\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\t\tconst previousSummary =\n\t\t\t\"Previous session summary content — intentionally verbose enough to clear the degenerate-summary threshold so this test exercises the actual propagation path.\";\n\n\t\tconst prompts: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\t\t\tprompts.push(text);\n\t\t\treturn makeFakeResponse(\n\t\t\t\t\"Chunk summary with sufficient length to clear the #4665 degenerate-output guard threshold of 100 characters — this must be longer.\",\n\t\t\t);\n\t\t});\n\n\t\tawait generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tpreviousSummary,\n\t\t\tmockComplete,\n\t\t);\n\n\t\t// First chunk should include the previousSummary\n\t\tassert.ok(\n\t\t\tprompts[0].includes(previousSummary),\n\t\t\t\"First chunk should incorporate the previousSummary\",\n\t\t);\n\t});\n});\n\n// ---------------------------------------------------------------------------\n// #4665 regression — iterative chain must not propagate degenerate summaries\n// ---------------------------------------------------------------------------\n\ndescribe(\"(#4665) degenerate summary guard\", () => {\n\tit(\"isDegenerateSummary detects the known failure patterns\", () => {\n\t\tassert.equal(isDegenerateSummary(undefined), false);\n\t\tassert.equal(isDegenerateSummary(\"\"), true, \"empty string is degenerate\");\n\t\tassert.equal(isDegenerateSummary(\"too short\"), true, \"short output is degenerate\");\n\t\tassert.equal(\n\t\t\tisDegenerateSummary(\"The user asked me to summarize an empty conversation\"),\n\t\t\ttrue,\n\t\t\t\"known failure phrase 'empty conversation' is degenerate\",\n\t\t);\n\t\tassert.equal(\n\t\t\tisDegenerateSummary(\"No conversation to summarize\"),\n\t\t\ttrue,\n\t\t\t\"'no conversation to summarize' is degenerate\",\n\t\t);\n\t\tassert.equal(\n\t\t\tisDegenerateSummary(\n\t\t\t\t\"## Goal\\nRefactor the compaction pipeline.\\n## Done\\n- Updated utils.ts\\n- Added tests for #4665 regression path\",\n\t\t\t),\n\t\t\tfalse,\n\t\t\t\"a real multi-section summary over 100 chars is not degenerate\",\n\t\t);\n\t});\n\n\tit(\"does not propagate a degenerate first-chunk summary forward (no 'preserve nothing' chain)\", async () => {\n\t\t// Force the chunked path with uncapped summary messages.\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(200_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Responses: chunk 0 returns degenerate (\"empty conversation\"). Chunks\n\t\t// 1 and 2 return real summaries. Pre-fix behavior: the chunk-0 output\n\t\t// is fed into UPDATE_SUMMARIZATION_PROMPT for chunks 1+, which says\n\t\t// \"PRESERVE all existing information\" — so emptiness is preserved.\n\t\t// Post-fix: the degenerate chunk-0 output must not become runningSummary.\n\t\tlet callIndex = 0;\n\t\tconst responses = [\n\t\t\t\"The user asked me to summarize an empty conversation.\",\n\t\t\t\"## Done\\n- Refactored the serializer to head+tail truncation.\\n- Updated chunker to use post-serialization token estimate.\",\n\t\t\t\"## Done\\n- Added regression tests for #4665 including this propagation guard.\\n- Verified isDegenerateSummary handles known failure patterns.\",\n\t\t];\n\t\tconst seenPrompts: string[] = [];\n\t\tconst mockComplete = mock.fn(async (_model: any, context: any) => {\n\t\t\tconst userMsg = context.messages?.[0];\n\t\t\tconst text =\n\t\t\t\ttypeof userMsg?.content === \"string\"\n\t\t\t\t\t? userMsg.content\n\t\t\t\t\t: userMsg?.content?.[0]?.text ?? \"\";\n\t\t\tseenPrompts.push(text);\n\t\t\tconst response = responses[Math.min(callIndex, responses.length - 1)];\n\t\t\tcallIndex++;\n\t\t\treturn makeFakeResponse(response);\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tmockComplete,\n\t\t);\n\n\t\t// The returned summary must be one of the real chunk summaries — not\n\t\t// the degenerate \"empty conversation\" output, and not an empty string.\n\t\tassert.ok(\n\t\t\t!isDegenerateSummary(summary),\n\t\t\t`final summary should not be degenerate. got: ${JSON.stringify(summary)}`,\n\t\t);\n\t\tassert.ok(\n\t\t\tsummary.includes(\"Refactored\") || summary.includes(\"regression tests\"),\n\t\t\t\"final summary should carry real information from chunks 1 or 2\",\n\t\t);\n\t});\n\n\tit(\"retries the first chunk once with the initial prompt if the first pass is degenerate\", async () => {\n\t\t// Force chunked path with a single large chunk. Mock returns degenerate\n\t\t// on the first call and a real summary on the retry.\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(100_000); // small window forces chunking\n\t\tconst reserveTokens = 16_384;\n\n\t\tconst responses = [\n\t\t\t\"\", // first attempt: empty string → degenerate\n\t\t\t\"## Goal\\nReal summary produced on the retry pass after the initial pass came back empty — this should land as the running summary.\",\n\t\t\t\"## Done\\n- Added retry-on-degenerate-first-chunk behavior to the iterative summarizer so empty outputs don't poison the chain.\",\n\t\t];\n\t\tlet callIndex = 0;\n\t\tconst mockComplete = mock.fn(async () => {\n\t\t\tconst response = responses[Math.min(callIndex, responses.length - 1)];\n\t\t\tcallIndex++;\n\t\t\treturn makeFakeResponse(response);\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tmockComplete,\n\t\t);\n\n\t\tassert.ok(\n\t\t\t!isDegenerateSummary(summary),\n\t\t\t\"final summary must not be degenerate after the retry took effect\",\n\t\t);\n\t\tassert.ok(\n\t\t\tmockComplete.mock.callCount() >= 3,\n\t\t\t`expected at least 3 calls (first attempt, retry, second chunk), got ${mockComplete.mock.callCount()}`,\n\t\t);\n\t});\n\n\t// -------------------------------------------------------------------------\n\t// R1 — retry non-first chunks too + observable log when both attempts fail\n\t// -------------------------------------------------------------------------\n\n\tit(\"(R1) retries a degenerate NON-FIRST chunk before silently dropping it\", async () => {\n\t\t// Use a small model window to force exactly 2 chunks from 2 messages.\n\t\t// Chunk 0 ok, chunk 1 degenerate on first try then real on retry.\n\t\t// Chunk 1's recovered content must reach the final summary.\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(100_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\tconst CHUNK0_SUMMARY = \"## Done\\n- Chunk 0 real summary with enough length to clear the degenerate threshold of 100 characters — easily.\";\n\t\tconst CHUNK1_RETRY_SUMMARY = \"## Done\\n- Chunk 1 recovered on retry — its content must appear in the final summary or the R1 fix regressed for non-first chunks.\";\n\n\t\tlet callIndex = 0;\n\t\tconst responses = [\n\t\t\tCHUNK0_SUMMARY, // chunk 0\n\t\t\t\"empty conversation\", // chunk 1 first try → degenerate\n\t\t\tCHUNK1_RETRY_SUMMARY, // chunk 1 retry → real\n\t\t];\n\t\tconst mockComplete = mock.fn(async () => {\n\t\t\tconst r = responses[Math.min(callIndex, responses.length - 1)];\n\t\t\tcallIndex++;\n\t\t\treturn makeFakeResponse(r);\n\t\t});\n\n\t\tconst summary = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tmockComplete,\n\t\t);\n\n\t\tassert.equal(\n\t\t\tmockComplete.mock.callCount(),\n\t\t\t3,\n\t\t\t\"expected 3 calls: chunk 0 + chunk 1 initial + chunk 1 retry\",\n\t\t);\n\t\tassert.ok(\n\t\t\tsummary.includes(\"recovered on retry\"),\n\t\t\t`final summary must include chunk 1's retry content (R1: non-first chunks must also retry), got: ${JSON.stringify(summary)}`,\n\t\t);\n\t});\n\n\t// -------------------------------------------------------------------------\n\t// R6 — empty output must not be silently written as a compaction entry\n\t// -------------------------------------------------------------------------\n\n\tit(\"(R6) throws CompactionProducedNoSummaryError when every chunk is degenerate AND no previousSummary\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(100_000);\n\t\tconst reserveTokens = 16_384;\n\n\t\t// Every response is degenerate, both initial and retry attempts.\n\t\tconst mockComplete = mock.fn(async () => makeFakeResponse(\"empty conversation\"));\n\n\t\tawait assert.rejects(\n\t\t\t() => generateSummary(\n\t\t\t\tmessages,\n\t\t\t\tmodel,\n\t\t\t\treserveTokens,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tundefined, // no previousSummary\n\t\t\t\tmockComplete,\n\t\t\t),\n\t\t\t(err: unknown) => err instanceof CompactionProducedNoSummaryError,\n\t\t\t\"expected CompactionProducedNoSummaryError when all chunks degenerate and no previousSummary\",\n\t\t);\n\t});\n\n\tit(\"(R6) falls back to previousSummary when every chunk is degenerate\", async () => {\n\t\tconst messages: AgentMessage[] = [\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t\tmakeBranchSummaryMessage(80_000),\n\t\t];\n\t\tconst model = makeModel(100_000);\n\t\tconst reserveTokens = 16_384;\n\t\tconst previousSummary =\n\t\t\t\"Previously-computed summary from the last compaction — deliberately long enough to clear the degenerate-output threshold.\";\n\n\t\tconst mockComplete = mock.fn(async () => makeFakeResponse(\"empty conversation\"));\n\n\t\tconst result = await generateSummary(\n\t\t\tmessages,\n\t\t\tmodel,\n\t\t\treserveTokens,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tpreviousSummary,\n\t\t\tmockComplete,\n\t\t);\n\n\t\tassert.equal(\n\t\t\tresult,\n\t\t\tpreviousSummary,\n\t\t\t\"when all chunks degenerate, must fall back to previousSummary rather than return empty string\",\n\t\t);\n\t});\n});\n"]}
@@ -65,14 +65,42 @@ export declare function createSummarizationMessage(promptText: string): [{
65
65
  }];
66
66
  timestamp: number;
67
67
  }];
68
+ /**
69
+ * Truncate text to a maximum character length for summarization, keeping both
70
+ * the head AND the tail. The tail is where information density lives for tool
71
+ * output (exit codes, verdicts, pass/fail counts, commit hashes), so pure
72
+ * head-slicing produced degenerate summaries (see issue #4665).
73
+ *
74
+ * Exported for test access only.
75
+ */
76
+ export declare function truncateForSummary(text: string, maxChars: number): string;
68
77
  /**
69
78
  * Serialize LLM messages to text for summarization.
70
79
  * This prevents the model from treating it as a conversation to continue.
71
80
  * Call convertToLlm() first to handle custom message types.
72
81
  *
73
- * Tool results are truncated to keep the summarization request within
74
- * reasonable token budgets. Full content is not needed for summarization.
82
+ * Every content block with a character count above TOOL_RESULT_MAX_CHARS is
83
+ * head+tail truncated. The issue #4665 fix broadened this from tool-results-
84
+ * only to every block type — large user pastes, assistant thinking, tool-call
85
+ * args, and bashExecution-derived blocks also bloat summarization input if
86
+ * uncapped.
75
87
  */
76
88
  export declare function serializeConversation(messages: Message[]): string;
89
+ /**
90
+ * Estimate tokens for a message AFTER the summarization serializer will have
91
+ * capped its large content blocks. Use this when deciding chunk sizes for
92
+ * summarization — NOT when deciding whether to compact in the first place
93
+ * (that needs the real in-memory content size via `estimateTokens`).
94
+ *
95
+ * See issue #4665: the old chunker used real content size but the serializer
96
+ * truncated tool results to 2000 chars, so a single 400K-char tool result
97
+ * looked like 100K tokens (triggering tens of unnecessary chunks) but actually
98
+ * serialized to ~600 tokens.
99
+ *
100
+ * Colocated with `truncateForSummary` / `serializeConversation` so the two
101
+ * stay in sync — if the serialization cap changes, both functions pick it up
102
+ * from `TOOL_RESULT_MAX_CHARS`.
103
+ */
104
+ export declare function estimateSerializedTokens(message: AgentMessage): number;
77
105
  export declare const SUMMARIZATION_SYSTEM_PROMPT = "You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.";
78
106
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAO1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CA2B9F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAK1G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,eAAe,UAAQ,GAAG,YAAY,GAAG,SAAS,CAqB1G;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,eAAe,UAAQ,GACrB,YAAY,EAAE,CAOhB;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,SAAS,SAAO,GACd,MAAM,CAKR;AAMD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ/I;AAkBD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAqDjE;AAMD,eAAO,MAAM,2BAA2B,oUAEmF,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/core/compaction/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAoB,OAAO,EAAE,MAAM,YAAY,CAAC;AAa5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAM1D,MAAM,WAAW,cAAc;IAC9B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,wBAAgB,aAAa,IAAI,cAAc,CAM9C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CA2B9F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAK1G;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,MAAM,CAUzF;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,eAAe,UAAQ,GAAG,YAAY,GAAG,SAAS,CAqB1G;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,eAAe,UAAQ,GACrB,YAAY,EAAE,CAOhB;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,SAAS,SAAO,GACd,MAAM,CAKR;AAMD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ/I;AAQD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAsDjE;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA4DtE;AAMD,eAAO,MAAM,2BAA2B,oUAEmF,CAAC"}