@gajae-code/coding-agent 0.11.1 → 0.11.3

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 (413) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/types/cli/config-cli.d.ts +11 -1
  3. package/dist/types/cli/launch-disposition.d.ts +23 -0
  4. package/dist/types/cli/notify-cli.d.ts +1 -0
  5. package/dist/types/cli/session-picker.d.ts +2 -1
  6. package/dist/types/cli/setup-cli.d.ts +1 -1
  7. package/dist/types/commands/mcp-serve.d.ts +33 -0
  8. package/dist/types/commands/mcp.d.ts +1 -1
  9. package/dist/types/commands/notify.d.ts +0 -2
  10. package/dist/types/commands/sdk.d.ts +1 -1
  11. package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
  12. package/dist/types/config/file-lock.d.ts +14 -4
  13. package/dist/types/config/keybindings.d.ts +42 -1
  14. package/dist/types/config/model-auth.d.ts +3 -0
  15. package/dist/types/config/model-bindings-applier.d.ts +13 -0
  16. package/dist/types/config/model-discovery-manager.d.ts +49 -0
  17. package/dist/types/config/model-equivalence.d.ts +20 -0
  18. package/dist/types/config/model-registry.d.ts +16 -15
  19. package/dist/types/config/model-resolver.d.ts +28 -18
  20. package/dist/types/config/models-config-schema.d.ts +11 -0
  21. package/dist/types/config/settings-schema.d.ts +141 -11
  22. package/dist/types/config/settings.d.ts +14 -11
  23. package/dist/types/coordinator-mcp/policy.d.ts +5 -0
  24. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
  25. package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
  26. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  27. package/dist/types/discovery/helpers.d.ts +0 -6
  28. package/dist/types/edit/index.d.ts +3 -0
  29. package/dist/types/eval/py/env.d.ts +9 -0
  30. package/dist/types/extensibility/extensions/loader.d.ts +2 -1
  31. package/dist/types/extensibility/extensions/runner.d.ts +2 -2
  32. package/dist/types/extensibility/extensions/types.d.ts +34 -3
  33. package/dist/types/extensibility/hooks/runner.d.ts +1 -1
  34. package/dist/types/extensibility/shared-events.d.ts +2 -0
  35. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  36. package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
  37. package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
  38. package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
  39. package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
  40. package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
  41. package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
  42. package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
  43. package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
  44. package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
  45. package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
  46. package/dist/types/gjc-runtime/team-store.d.ts +160 -0
  47. package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
  48. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
  49. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
  50. package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
  51. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
  52. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
  53. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
  54. package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
  55. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
  56. package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
  57. package/dist/types/goals/runtime.d.ts +1 -0
  58. package/dist/types/goals/state.d.ts +8 -0
  59. package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
  60. package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
  61. package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
  62. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  63. package/dist/types/hindsight/state.d.ts +11 -4
  64. package/dist/types/lsp/lspmux.d.ts +5 -3
  65. package/dist/types/lsp/path-trust.d.ts +1 -0
  66. package/dist/types/main.d.ts +4 -2
  67. package/dist/types/memories/storage.d.ts +1 -0
  68. package/dist/types/modes/action-registry.d.ts +29 -0
  69. package/dist/types/modes/components/chrome.d.ts +14 -0
  70. package/dist/types/modes/components/command-palette.d.ts +27 -0
  71. package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
  72. package/dist/types/modes/components/index.d.ts +2 -1
  73. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  74. package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
  75. package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
  76. package/dist/types/modes/components/queue-pane.d.ts +12 -0
  77. package/dist/types/modes/components/read-tool-group.d.ts +6 -0
  78. package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
  79. package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
  80. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  81. package/dist/types/modes/components/show-images-selector.d.ts +1 -1
  82. package/dist/types/modes/components/status-line/types.d.ts +1 -1
  83. package/dist/types/modes/components/status-line.d.ts +1 -94
  84. package/dist/types/modes/components/tasks-pane.d.ts +15 -0
  85. package/dist/types/modes/components/theme-selector.d.ts +1 -1
  86. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  87. package/dist/types/modes/components/tool-status-header.d.ts +111 -0
  88. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
  89. package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
  90. package/dist/types/modes/controllers/input-controller.d.ts +8 -1
  91. package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
  92. package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
  93. package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
  94. package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
  95. package/dist/types/modes/interactive-mode.d.ts +19 -17
  96. package/dist/types/modes/jobs-observer.d.ts +2 -0
  97. package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
  98. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
  99. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
  100. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
  101. package/dist/types/modes/tasks-aggregator.d.ts +39 -0
  102. package/dist/types/modes/transcript-item-registry.d.ts +60 -0
  103. package/dist/types/modes/types.d.ts +20 -13
  104. package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
  105. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  106. package/dist/types/sdk/broker/broker.d.ts +78 -12
  107. package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
  108. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
  109. package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
  110. package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
  111. package/dist/types/sdk/broker/session-index.d.ts +0 -1
  112. package/dist/types/sdk/broker/state-version.d.ts +2 -0
  113. package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
  114. package/dist/types/sdk/bus/config-commands.d.ts +1 -1
  115. package/dist/types/sdk/bus/config.d.ts +11 -0
  116. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  117. package/dist/types/sdk/bus/html-format.d.ts +3 -2
  118. package/dist/types/sdk/bus/index.d.ts +29 -0
  119. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  120. package/dist/types/sdk/bus/notification-service.d.ts +20 -0
  121. package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
  122. package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
  123. package/dist/types/sdk/bus/rich-document.d.ts +7 -0
  124. package/dist/types/sdk/bus/rich-render.d.ts +18 -41
  125. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
  126. package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
  127. package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
  128. package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
  129. package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
  130. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  131. package/dist/types/sdk/host/host.d.ts +2 -0
  132. package/dist/types/sdk/index.d.ts +1 -0
  133. package/dist/types/sdk/session-directory.d.ts +56 -0
  134. package/dist/types/sdk/session.d.ts +2 -0
  135. package/dist/types/session/agent-session.d.ts +82 -47
  136. package/dist/types/session/agent-storage.d.ts +7 -0
  137. package/dist/types/session/fallback-chain-controller.d.ts +10 -2
  138. package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
  139. package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
  140. package/dist/types/session/messages.d.ts +16 -0
  141. package/dist/types/session/session-manager-internal.d.ts +14 -0
  142. package/dist/types/session/session-manager.d.ts +82 -12
  143. package/dist/types/session/session-storage.d.ts +43 -3
  144. package/dist/types/session/volatile-context-pruning.d.ts +15 -0
  145. package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
  146. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
  147. package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
  148. package/dist/types/system-prompt.d.ts +2 -11
  149. package/dist/types/task/executor.d.ts +3 -1
  150. package/dist/types/thinking.d.ts +7 -0
  151. package/dist/types/tool-discovery/tool-index.d.ts +1 -50
  152. package/dist/types/tools/ask.d.ts +64 -2
  153. package/dist/types/tools/bash.d.ts +3 -0
  154. package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
  155. package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
  156. package/dist/types/tools/cron.d.ts +2 -0
  157. package/dist/types/tools/fetch.d.ts +1 -0
  158. package/dist/types/tools/index.d.ts +30 -15
  159. package/dist/types/tools/output-meta.d.ts +1 -0
  160. package/dist/types/tools/read.d.ts +5 -0
  161. package/dist/types/tools/search-tool-bm25.d.ts +3 -4
  162. package/dist/types/tools/subagent.d.ts +1 -0
  163. package/dist/types/utils/event-bus.d.ts +1 -1
  164. package/dist/types/utils/file-mentions.d.ts +3 -3
  165. package/dist/types/web/search/index.d.ts +3 -1
  166. package/package.json +21 -9
  167. package/scripts/build-sdk-package-smoke.ts +34 -1
  168. package/scripts/generate-hotkeys-docs.ts +74 -0
  169. package/scripts/generate-sdk-operation-inventory.ts +64 -20
  170. package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
  171. package/src/async/job-manager.ts +49 -6
  172. package/src/cli/config-cli.ts +75 -2
  173. package/src/cli/launch-disposition.ts +42 -0
  174. package/src/cli/notify-cli.ts +92 -26
  175. package/src/cli/session-picker.ts +20 -3
  176. package/src/cli/setup-cli.ts +1 -1
  177. package/src/cli.ts +1 -1
  178. package/src/commands/config.ts +1 -1
  179. package/src/commands/harness.ts +34 -106
  180. package/src/commands/launch.ts +6 -4
  181. package/src/commands/mcp-serve.ts +85 -8
  182. package/src/commands/mcp.ts +2 -2
  183. package/src/commands/notify.ts +8 -4
  184. package/src/commands/sdk.ts +61 -40
  185. package/src/commands/ultragoal.ts +4 -1
  186. package/src/config/atomic-yaml-patch.ts +80 -13
  187. package/src/config/file-lock.ts +105 -43
  188. package/src/config/keybindings.ts +64 -20
  189. package/src/config/model-auth.ts +9 -0
  190. package/src/config/model-bindings-applier.ts +139 -0
  191. package/src/config/model-discovery-manager.ts +224 -0
  192. package/src/config/model-equivalence.ts +66 -0
  193. package/src/config/model-registry.ts +169 -302
  194. package/src/config/model-resolver.ts +361 -369
  195. package/src/config/models-config-schema.ts +5 -4
  196. package/src/config/settings-schema.ts +214 -12
  197. package/src/config/settings.ts +458 -482
  198. package/src/coordinator-mcp/policy.ts +76 -11
  199. package/src/coordinator-mcp/question-gate-codec.ts +274 -0
  200. package/src/coordinator-mcp/question-state.ts +778 -0
  201. package/src/coordinator-mcp/server.ts +1702 -238
  202. package/src/debug/index.ts +1 -1
  203. package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
  204. package/src/defaults/gjc/skills/team/SKILL.md +16 -0
  205. package/src/discovery/helpers.ts +1 -50
  206. package/src/edit/index.ts +64 -0
  207. package/src/eval/py/env.ts +26 -0
  208. package/src/eval/py/kernel.ts +5 -3
  209. package/src/extensibility/extensions/loader.ts +9 -1
  210. package/src/extensibility/extensions/runner.ts +12 -3
  211. package/src/extensibility/extensions/types.ts +39 -1
  212. package/src/extensibility/gjc-plugins/installer.ts +16 -16
  213. package/src/extensibility/hooks/runner.ts +2 -2
  214. package/src/extensibility/runtime-skill-discovery.ts +33 -13
  215. package/src/extensibility/shared-events.ts +2 -0
  216. package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
  217. package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
  218. package/src/gjc-runtime/deep-interview-state.ts +317 -5
  219. package/src/gjc-runtime/goal-mode-request.ts +55 -8
  220. package/src/gjc-runtime/launch-tmux.ts +2 -5
  221. package/src/gjc-runtime/launch-worktree.ts +5 -5
  222. package/src/gjc-runtime/linux-proc.ts +71 -0
  223. package/src/gjc-runtime/ralplan-runtime.ts +74 -90
  224. package/src/gjc-runtime/session-resolution.ts +18 -3
  225. package/src/gjc-runtime/session-state-sidecar.ts +6 -107
  226. package/src/gjc-runtime/state-migrations.ts +1 -1
  227. package/src/gjc-runtime/state-runtime.ts +327 -249
  228. package/src/gjc-runtime/state-writer.ts +36 -40
  229. package/src/gjc-runtime/team-launch.ts +319 -0
  230. package/src/gjc-runtime/team-notify.ts +326 -0
  231. package/src/gjc-runtime/team-runtime.ts +1099 -1482
  232. package/src/gjc-runtime/team-store.ts +828 -0
  233. package/src/gjc-runtime/team-workers.ts +962 -0
  234. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
  235. package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
  236. package/src/gjc-runtime/tmux-sessions.ts +4 -21
  237. package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
  238. package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
  239. package/src/gjc-runtime/ultragoal-guard.ts +29 -5
  240. package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
  241. package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
  242. package/src/gjc-runtime/workflow-cli-common.ts +30 -0
  243. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  244. package/src/gjc-runtime/workflow-manifest.ts +18 -0
  245. package/src/goals/continuation-timeout-guard.ts +79 -0
  246. package/src/goals/runtime.ts +7 -5
  247. package/src/goals/state.ts +18 -0
  248. package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
  249. package/src/harness-control-plane/phase-rollup.ts +4 -7
  250. package/src/harness-control-plane/receipt-ingest.ts +5 -0
  251. package/src/harness-control-plane/receipt-spool.ts +51 -7
  252. package/src/harness-control-plane/session-lease.ts +12 -130
  253. package/src/hindsight/backend.ts +26 -27
  254. package/src/hindsight/state.ts +101 -32
  255. package/src/hooks/skill-state.ts +17 -11
  256. package/src/internal-urls/docs-index.generated.ts +21 -18
  257. package/src/lsp/client.ts +1 -1
  258. package/src/lsp/config.ts +145 -26
  259. package/src/lsp/index.ts +1 -1
  260. package/src/lsp/lspmux.ts +39 -10
  261. package/src/lsp/path-trust.ts +81 -0
  262. package/src/main.ts +127 -30
  263. package/src/memories/index.ts +1 -0
  264. package/src/memories/storage.ts +6 -2
  265. package/src/modes/action-registry.ts +165 -0
  266. package/src/modes/components/chrome.ts +40 -0
  267. package/src/modes/components/command-palette.ts +168 -0
  268. package/src/modes/components/custom-editor.ts +1 -1
  269. package/src/modes/components/custom-provider-wizard.ts +51 -14
  270. package/src/modes/components/index.ts +2 -1
  271. package/src/modes/components/pet-selector.ts +11 -17
  272. package/src/modes/components/plan-preview-overlay.ts +295 -0
  273. package/src/modes/components/queue-mode-selector.ts +10 -27
  274. package/src/modes/components/queue-pane.ts +79 -0
  275. package/src/modes/components/read-tool-group.ts +13 -0
  276. package/src/modes/components/session-observer-overlay.ts +207 -772
  277. package/src/modes/components/sessions-dashboard.ts +181 -0
  278. package/src/modes/components/settings-selector.ts +1 -1
  279. package/src/modes/components/show-images-selector.ts +10 -24
  280. package/src/modes/components/status-line/types.ts +1 -1
  281. package/src/modes/components/status-line.ts +1 -969
  282. package/src/modes/components/tasks-pane.ts +73 -0
  283. package/src/modes/components/theme-selector.ts +11 -31
  284. package/src/modes/components/tool-execution.ts +22 -0
  285. package/src/modes/components/tool-status-header.ts +1056 -0
  286. package/src/modes/components/transcript-viewer-overlay.ts +384 -0
  287. package/src/modes/controllers/btw-controller.ts +1 -0
  288. package/src/modes/controllers/event-controller.ts +3 -2
  289. package/src/modes/controllers/extension-ui-controller.ts +24 -1
  290. package/src/modes/controllers/goal-mode-controller.ts +474 -0
  291. package/src/modes/controllers/input-controller.ts +764 -229
  292. package/src/modes/controllers/mode-gate.ts +24 -0
  293. package/src/modes/controllers/plan-mode-controller.ts +517 -0
  294. package/src/modes/controllers/selector-controller.ts +225 -10
  295. package/src/modes/controllers/stt-controller.ts +125 -0
  296. package/src/modes/interactive-mode.ts +289 -1150
  297. package/src/modes/jobs-observer.ts +3 -0
  298. package/src/modes/prompt-action-autocomplete.ts +7 -0
  299. package/src/modes/runtime-init.ts +8 -0
  300. package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
  301. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
  302. package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
  303. package/src/modes/tasks-aggregator.ts +199 -0
  304. package/src/modes/transcript-item-registry.ts +229 -0
  305. package/src/modes/types.ts +45 -18
  306. package/src/modes/utils/ui-helpers.ts +17 -9
  307. package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
  308. package/src/prompts/agent-fragments/restricted-bash.md +1 -0
  309. package/src/prompts/agents/architect.md +2 -8
  310. package/src/prompts/agents/critic.md +2 -8
  311. package/src/prompts/agents/executor.md +3 -0
  312. package/src/prompts/agents/planner.md +4 -12
  313. package/src/prompts/system/custom-system-prompt.md +1 -23
  314. package/src/prompts/system/plan-mode-approved.md +8 -0
  315. package/src/prompts/system/system-prompt.md +17 -96
  316. package/src/prompts/tools/bash.md +4 -4
  317. package/src/prompts/tools/browser.md +15 -52
  318. package/src/prompts/tools/find.md +2 -2
  319. package/src/prompts/tools/hashline.md +13 -55
  320. package/src/prompts/tools/read.md +3 -6
  321. package/src/prompts/tools/search-tool-bm25.md +0 -2
  322. package/src/prompts/tools/search.md +2 -4
  323. package/src/prompts/tools/skill-discovery.md +1 -2
  324. package/src/prompts/tools/task.md +1 -1
  325. package/src/runtime-mcp/manager.ts +1 -1
  326. package/src/sdk/broker/broker.ts +206 -78
  327. package/src/sdk/broker/discovery.ts +1 -1
  328. package/src/sdk/broker/ensure.ts +3 -1
  329. package/src/sdk/broker/lifecycle-codec.ts +11 -0
  330. package/src/sdk/broker/lifecycle-ledger.ts +371 -74
  331. package/src/sdk/broker/lifecycle.ts +1399 -142
  332. package/src/sdk/broker/process-incarnation.ts +5 -13
  333. package/src/sdk/broker/session-index.ts +145 -56
  334. package/src/sdk/broker/state-version.ts +21 -0
  335. package/src/sdk/broker/transport.ts +1 -1
  336. package/src/sdk/bus/chat-daemon-cli.ts +2 -0
  337. package/src/sdk/bus/chat-daemon-control.ts +8 -28
  338. package/src/sdk/bus/chat-effect-journal.ts +10 -2
  339. package/src/sdk/bus/config-commands.ts +5 -4
  340. package/src/sdk/bus/config.ts +98 -0
  341. package/src/sdk/bus/conversation-store.ts +5 -29
  342. package/src/sdk/bus/daemon-paths.ts +2 -0
  343. package/src/sdk/bus/html-format.ts +20 -3
  344. package/src/sdk/bus/index.ts +782 -94
  345. package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
  346. package/src/sdk/bus/natives-augment.d.ts +26 -1
  347. package/src/sdk/bus/notification-service.ts +168 -20
  348. package/src/sdk/bus/rate-limit-pool.ts +58 -14
  349. package/src/sdk/bus/recent-activity.ts +188 -74
  350. package/src/sdk/bus/rich-document.ts +258 -0
  351. package/src/sdk/bus/rich-render.ts +62 -70
  352. package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
  353. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  354. package/src/sdk/bus/telegram-daemon.ts +1389 -237
  355. package/src/sdk/bus/threaded-inbound.ts +8 -3
  356. package/src/sdk/bus/threaded-render.ts +57 -1
  357. package/src/sdk/bus/topic-registry.ts +120 -13
  358. package/src/sdk/host/control/dispatch.ts +14 -2
  359. package/src/sdk/host/control/operations.ts +6 -1
  360. package/src/sdk/host/host.ts +44 -2
  361. package/src/sdk/host/query/handlers.ts +20 -22
  362. package/src/sdk/host/query/revision-store.ts +80 -57
  363. package/src/sdk/index.ts +1 -0
  364. package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
  365. package/src/sdk/session-directory.ts +141 -0
  366. package/src/sdk/session.ts +462 -480
  367. package/src/session/agent-session.ts +1700 -583
  368. package/src/session/agent-storage.ts +18 -0
  369. package/src/session/cache-economics.ts +25 -8
  370. package/src/session/fallback-chain-controller.ts +53 -3
  371. package/src/session/internal/managed-session-scope.ts +2226 -0
  372. package/src/session/internal/managed-session-storage.ts +453 -0
  373. package/src/session/messages.ts +91 -2
  374. package/src/session/session-manager-internal.ts +33 -0
  375. package/src/session/session-manager.ts +1112 -333
  376. package/src/session/session-storage.ts +444 -39
  377. package/src/session/volatile-context-pruning.ts +78 -0
  378. package/src/setup/credential-auto-import.ts +2 -1
  379. package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
  380. package/src/setup/provider-onboarding.ts +36 -61
  381. package/src/setup/provider-presets.json +5 -0
  382. package/src/skill-state/active-state.ts +3 -13
  383. package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
  384. package/src/skill-state/workflow-state-contract.ts +6 -41
  385. package/src/slash-commands/builtin-registry.ts +46 -11
  386. package/src/system-prompt.ts +37 -44
  387. package/src/task/agents.ts +19 -1
  388. package/src/task/executor.ts +90 -6
  389. package/src/task/index.ts +36 -21
  390. package/src/thinking.ts +21 -6
  391. package/src/tool-discovery/tool-index.ts +2 -134
  392. package/src/tools/ask.ts +157 -21
  393. package/src/tools/ast-edit.ts +1 -1
  394. package/src/tools/bash.ts +38 -0
  395. package/src/tools/browser/dead-tab-recovery.ts +78 -0
  396. package/src/tools/browser/tab-supervisor.ts +282 -36
  397. package/src/tools/computer.ts +10 -3
  398. package/src/tools/cron.ts +30 -16
  399. package/src/tools/eval.ts +1 -2
  400. package/src/tools/fetch.ts +11 -4
  401. package/src/tools/index.ts +76 -24
  402. package/src/tools/output-meta.ts +19 -7
  403. package/src/tools/read.ts +219 -64
  404. package/src/tools/resource-gc.ts +2 -2
  405. package/src/tools/search-tool-bm25.ts +11 -74
  406. package/src/tools/subagent.ts +43 -2
  407. package/src/utils/event-bus.ts +9 -4
  408. package/src/utils/file-mentions.ts +4 -4
  409. package/src/web/search/index.ts +3 -3
  410. package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
  411. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
  412. package/src/discovery/plugin-dir-roots.ts +0 -28
  413. package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
package/src/tools/read.ts CHANGED
@@ -53,6 +53,7 @@ import {
53
53
  type ReadUrlToolDetails,
54
54
  renderReadUrlCall,
55
55
  renderReadUrlResult,
56
+ wrapUntrustedContent,
56
57
  } from "./fetch";
57
58
  import { applyListLimit } from "./list-limit";
58
59
  import {
@@ -94,6 +95,8 @@ const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx"
94
95
 
95
96
  const MAX_SUMMARY_BYTES = 2 * 1024 * 1024;
96
97
  const MAX_SUMMARY_LINES = 20_000;
98
+ const RAW_COLLECTOR_MAX_BYTES = MAX_SUMMARY_BYTES;
99
+
97
100
  /**
98
101
  * Per-line column cap for file reads. Lines wider than the value of
99
102
  * `tools.outputMaxColumns` are ellipsis-truncated at display time; the file
@@ -192,6 +195,14 @@ function formatSummaryElisionFooter(readPath: string, elidedSpans: number, elide
192
195
  const linePart = elidedLines > 0 ? `${elidedLines} ${lineWord} across ` : "";
193
196
  return `[${linePart}${elidedSpans} elided ${spanWord}; read ${readPath}:raw or a line range like ${readPath}:1-9999 for verbatim content]`;
194
197
  }
198
+
199
+ function formatReceiptFooter(readPath: string, shownLines: number, totalLines: number, shownBytes: number): string {
200
+ return `[Showing first ${shownLines} of ${totalLines} lines (~${Math.ceil(shownBytes / 1024)} KiB); re-read ${readPath}:1-${totalLines} or ${readPath}:raw for the full file]`;
201
+ }
202
+
203
+ function formatSummaryCapFooter(readPath: string, maxBytes: number, totalLines: number): string {
204
+ return `[Summary truncated at ${Math.ceil(maxBytes / 1024)} KiB; re-read ${readPath}:raw or ${readPath}:1-${totalLines} for the full source]`;
205
+ }
195
206
  const READ_CHUNK_SIZE = 8 * 1024;
196
207
 
197
208
  /**
@@ -487,6 +498,38 @@ const readSchema = z
487
498
 
488
499
  export type ReadToolInput = z.infer<typeof readSchema>;
489
500
 
501
+ const UNSAFE_SUMMARY_PATH =
502
+ /(?:\b(?:https?|wss?):\/\/|\b(?:api[-_ ]?key|access[-_ ]?token|bearer|secret|password)\b|\b(?:sk|pk|rk)-[A-Za-z0-9_-]{12,})/i;
503
+
504
+ /** Project paths and output sizes without exposing read content or remote URLs. */
505
+ export function summarizeReadToolActivity(kind: "args" | "result", value: unknown): string | undefined {
506
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
507
+ const record = value as Record<string, unknown>;
508
+ if (kind === "args") {
509
+ const readPath = record.path;
510
+ if (
511
+ typeof readPath !== "string" ||
512
+ readPath.length === 0 ||
513
+ readPath.length > 100 ||
514
+ UNSAFE_SUMMARY_PATH.test(readPath)
515
+ ) {
516
+ return undefined;
517
+ }
518
+ return readPath;
519
+ }
520
+ if (!Array.isArray(record.content)) return undefined;
521
+ const text = record.content
522
+ .filter(
523
+ (block): block is { type: unknown; text: unknown } =>
524
+ typeof block === "object" && block !== null && "type" in block && "text" in block,
525
+ )
526
+ .filter(block => block.type === "text" && typeof block.text === "string")
527
+ .map(block => block.text as string)
528
+ .join("\n");
529
+ const lines = text.length === 0 ? 0 : text.split("\n").length;
530
+ return `${lines} lines, ${Buffer.byteLength(text, "utf-8")} bytes`;
531
+ }
532
+
490
533
  export interface ReadToolDetails {
491
534
  kind?: "file" | "url";
492
535
  truncation?: TruncationResult;
@@ -499,6 +542,9 @@ export interface ReadToolDetails {
499
542
  method?: string;
500
543
  notes?: string[];
501
544
  meta?: OutputMeta;
545
+ /** Whether this explicit content read may be spilled by output metadata. */
546
+ spillEligible?: boolean;
547
+
502
548
  /** Raw text + start line for user-visible TUI rendering, set when content is text-like.
503
549
  * Mirrors the same lines the model receives but without hashline/line-number prefixes,
504
550
  * so the TUI can render the file content with its own gutter without re-parsing the formatted text. */
@@ -667,6 +713,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
667
713
  readonly parameters = readSchema;
668
714
  readonly nonAbortable = true;
669
715
  readonly strict = true;
716
+ readonly safeSummary = summarizeReadToolActivity;
670
717
 
671
718
  readonly #autoResizeImages: boolean;
672
719
  readonly #defaultLimit: number;
@@ -782,12 +829,16 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
782
829
  options: {
783
830
  details?: ReadToolDetails;
784
831
  sourcePath?: string;
832
+ spillEligible?: boolean;
833
+ receiptPath?: string;
785
834
  sourceUrl?: string;
786
835
  sourceInternal?: string;
787
836
  entityLabel: string;
788
837
  ignoreResultLimits?: boolean;
838
+ resultByteCeiling?: number;
789
839
  raw?: boolean;
790
840
  immutable?: boolean;
841
+ wrapUntrusted?: boolean;
791
842
  },
792
843
  ): AgentToolResult<ReadToolDetails> {
793
844
  const displayMode = resolveFileDisplayMode(this.session, { raw: options.raw, immutable: options.immutable });
@@ -836,9 +887,30 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
836
887
  }
837
888
 
838
889
  const endLine = endLineExpanded;
839
- const selectedContent = allLines.slice(startLine, endLine).join("\n");
890
+ let selectedContent = allLines.slice(startLine, endLine).join("\n");
891
+
892
+ if (options.receiptPath) {
893
+ const budgetLines = this.session.settings.get("read.receiptBudgetLines");
894
+ const budgetBytes = this.session.settings.get("read.receiptBudgetBytes") * 1024;
895
+ const receiptLines: string[] = [];
896
+ let bytes = 0;
897
+ for (const line of allLines) {
898
+ const lineBytes = Buffer.byteLength(line, "utf-8") + (receiptLines.length > 0 ? 1 : 0);
899
+ if (receiptLines.length >= budgetLines || bytes + lineBytes > budgetBytes) break;
900
+ receiptLines.push(line);
901
+ bytes += lineBytes;
902
+ }
903
+ selectedContent = receiptLines.join("\n");
904
+ }
840
905
  const userLimitedLines = limit !== undefined ? endLine - startLine : undefined;
841
- const truncation = ignoreResultLimits ? noTruncResult(selectedContent) : truncateHead(selectedContent);
906
+ const truncation = ignoreResultLimits
907
+ ? noTruncResult(selectedContent)
908
+ : truncateHead(
909
+ selectedContent,
910
+ options.resultByteCeiling === undefined
911
+ ? undefined
912
+ : { maxBytes: options.resultByteCeiling, maxLines: Number.MAX_SAFE_INTEGER },
913
+ );
842
914
 
843
915
  const shouldAddHashLines = displayMode.hashLines;
844
916
  const shouldAddLineNumbers = shouldAddHashLines ? false : displayMode.lineNumbers;
@@ -892,8 +964,12 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
892
964
  } else {
893
965
  outputText = formatText(truncation.content, startLineDisplay);
894
966
  }
967
+ if (options.receiptPath && (truncation.truncated || countTextLines(selectedContent) < totalLines)) {
968
+ outputText += `\n\n${formatReceiptFooter(options.receiptPath, countTextLines(selectedContent), totalLines, Buffer.byteLength(selectedContent, "utf-8"))}`;
969
+ }
895
970
 
896
- resultBuilder.text(outputText);
971
+ details.spillEligible = options.spillEligible === true && selectedContent.length > 0;
972
+ resultBuilder.text(options.wrapUntrusted ? wrapUntrustedContent(outputText) : outputText);
897
973
  if (truncationInfo) {
898
974
  resultBuilder.truncation(truncationInfo.result, truncationInfo.options);
899
975
  }
@@ -952,6 +1028,8 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
952
1028
  }
953
1029
  const finalText =
954
1030
  notices.length > 0 ? (outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n")) : outputText;
1031
+ details.spillEligible = parts.length > 0;
1032
+
955
1033
  resultBuilder.text(finalText);
956
1034
  return resultBuilder.done();
957
1035
  }
@@ -971,6 +1049,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
971
1049
  signal: AbortSignal | undefined,
972
1050
  ): Promise<{
973
1051
  outputText: string;
1052
+ contentLineCount: number;
974
1053
  columnTruncated: number;
975
1054
  bridgeResult?: AgentToolResult<ReadToolDetails>;
976
1055
  }> {
@@ -992,7 +1071,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
992
1071
  const firstText = bridgeResult.content.find((c): c is TextContent => c.type === "text");
993
1072
  if (firstText) firstText.text = `${notice}\n${firstText.text}`;
994
1073
  }
995
- return { outputText: "", columnTruncated: 0, bridgeResult };
1074
+ return { outputText: "", contentLineCount: 0, columnTruncated: 0, bridgeResult };
996
1075
  } catch (error) {
997
1076
  logger.warn("ACP fs readTextFile failed; falling back to disk", { path: absolutePath, error });
998
1077
  }
@@ -1005,6 +1084,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1005
1084
  const blocks: string[] = [];
1006
1085
  const notices: string[] = [];
1007
1086
  let columnTruncated = 0;
1087
+ let contentLineCount = 0;
1008
1088
 
1009
1089
  for (const range of ranges) {
1010
1090
  const rangeStart = range.startLine - 1; // 0-indexed
@@ -1039,6 +1119,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1039
1119
  }
1040
1120
  }
1041
1121
 
1122
+ contentLineCount += collectedLines.length;
1042
1123
  if (collectedLines.length > 0) {
1043
1124
  getFileReadCache(this.session).recordContiguous(absolutePath, range.startLine, collectedLines);
1044
1125
  }
@@ -1051,7 +1132,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1051
1132
  if (notices.length > 0) {
1052
1133
  outputText = outputText ? `${outputText}\n${notices.join("\n")}` : notices.join("\n");
1053
1134
  }
1054
- return { outputText, columnTruncated };
1135
+ return { outputText, contentLineCount, columnTruncated };
1055
1136
  }
1056
1137
 
1057
1138
  async #readArchiveDirectory(
@@ -1334,6 +1415,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1334
1415
  displayText: string;
1335
1416
  elidedSpans: number;
1336
1417
  elidedLines: number;
1418
+ capped: boolean;
1337
1419
  } {
1338
1420
  const displayMode = resolveFileDisplayMode(this.session);
1339
1421
  const shouldAddHashLines = displayMode.hashLines;
@@ -1393,17 +1475,19 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1393
1475
 
1394
1476
  const modelParts: string[] = [];
1395
1477
  const displayParts: string[] = [];
1478
+ const capBytes = this.session.settings.get("read.summaryMaxBytes") * 1024;
1479
+ let usedBytes = 0;
1396
1480
  let elidedSpans = 0;
1397
1481
  let elidedLines = 0;
1482
+ let capDropped = false;
1398
1483
  for (const unit of units) {
1484
+ let model: string;
1485
+ let display: string;
1486
+ let implicitElidedLines = 0;
1399
1487
  if (unit.kind === "elided") {
1400
- modelParts.push("...");
1401
- displayParts.push("...");
1402
- elidedSpans++;
1403
- elidedLines += unit.endLine - unit.startLine + 1;
1404
- continue;
1405
- }
1406
- if (unit.kind === "merged") {
1488
+ model = display = "...";
1489
+ implicitElidedLines = unit.endLine - unit.startLine + 1;
1490
+ } else if (unit.kind === "merged") {
1407
1491
  const formatted = formatMergedBraceLine(
1408
1492
  unit.startLine,
1409
1493
  unit.endLine,
@@ -1412,18 +1496,39 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1412
1496
  shouldAddHashLines,
1413
1497
  shouldAddLineNumbers,
1414
1498
  );
1415
- modelParts.push(formatted.model);
1416
- displayParts.push(formatted.display);
1499
+ model = formatted.model;
1500
+ display = formatted.display;
1501
+ implicitElidedLines = Math.max(0, unit.endLine - unit.startLine - 1);
1502
+ } else {
1503
+ model = formatSingleLine(unit.line, unit.text, shouldAddHashLines, shouldAddLineNumbers);
1504
+ display = unit.text;
1505
+ }
1506
+ const separatorBytes = modelParts.length > 0 ? 1 : 0;
1507
+ if (usedBytes + separatorBytes + Buffer.byteLength(model, "utf-8") > capBytes) {
1508
+ capDropped = true;
1417
1509
  elidedSpans++;
1418
- // Merged brace pair encloses (start+1)..(end-1) as elided.
1419
- elidedLines += Math.max(0, unit.endLine - unit.startLine - 1);
1510
+ elidedLines += unit.kind === "line" ? 1 : unit.endLine - unit.startLine + 1;
1420
1511
  continue;
1421
1512
  }
1422
- modelParts.push(formatSingleLine(unit.line, unit.text, shouldAddHashLines, shouldAddLineNumbers));
1423
- displayParts.push(unit.text);
1513
+ usedBytes += separatorBytes + Buffer.byteLength(model, "utf-8");
1514
+ modelParts.push(model);
1515
+ displayParts.push(display);
1516
+ if (unit.kind === "elided" || unit.kind === "merged") {
1517
+ elidedSpans++;
1518
+ elidedLines += implicitElidedLines;
1519
+ }
1424
1520
  }
1425
-
1426
- return { text: modelParts.join("\n"), displayText: displayParts.join("\n"), elidedSpans, elidedLines };
1521
+ if (capDropped) {
1522
+ modelParts.push("…");
1523
+ displayParts.push("…");
1524
+ }
1525
+ return {
1526
+ text: modelParts.join("\n"),
1527
+ displayText: displayParts.join("\n"),
1528
+ elidedSpans,
1529
+ elidedLines,
1530
+ capped: capDropped,
1531
+ };
1427
1532
  }
1428
1533
 
1429
1534
  async execute(
@@ -1469,6 +1574,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1469
1574
  sourceUrl: cached.details.finalUrl,
1470
1575
  entityLabel: "URL output",
1471
1576
  immutable: true,
1577
+ wrapUntrusted: true,
1472
1578
  });
1473
1579
  }
1474
1580
  return executeReadUrl(this.session, { path: parsedUrlTarget.path, raw: parsedUrlTarget.raw }, signal);
@@ -1613,25 +1719,38 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1613
1719
  details: { resolvedPath: absolutePath },
1614
1720
  sourcePath: absolutePath,
1615
1721
  entityLabel: "notebook",
1722
+ spillEligible: parsed.kind !== "none",
1723
+ resultByteCeiling:
1724
+ parsed.kind !== "none"
1725
+ ? Math.max(
1726
+ RAW_COLLECTOR_MAX_BYTES,
1727
+ this.session.settings.get("tools.readArtifactSpillThreshold") * 1024,
1728
+ )
1729
+ : undefined,
1730
+ receiptPath: parsed.kind === "none" ? localReadPath : undefined,
1616
1731
  });
1617
1732
  } else if (shouldConvertWithMarkit) {
1618
- // Convert document via markit.
1619
1733
  const result = await convertFileWithMarkit(absolutePath, signal);
1620
1734
  if (result.ok) {
1621
- // Apply truncation to converted content
1622
- const truncation = truncateHead(result.content);
1623
- const outputText = truncation.content;
1624
-
1625
- details = { truncation };
1626
- sourcePath = absolutePath;
1627
- truncationInfo = { result: truncation, options: { direction: "head", startLine: 1 } };
1628
-
1629
- content = [{ type: "text", text: outputText }];
1630
- } else if (result.error) {
1631
- content = [{ type: "text", text: `[Cannot read ${ext} file: ${result.error || "conversion failed"}]` }];
1632
- } else {
1633
- content = [{ type: "text", text: `[Cannot read ${ext} file: conversion failed]` }];
1735
+ const { offset, limit } = selToOffsetLimit(parsed);
1736
+ return this.#buildInMemoryTextResult(result.content, offset, limit, {
1737
+ details: { resolvedPath: absolutePath },
1738
+ sourcePath: absolutePath,
1739
+ entityLabel: "converted document",
1740
+ raw: isRawSelector(parsed),
1741
+ spillEligible: parsed.kind !== "none",
1742
+ resultByteCeiling:
1743
+ parsed.kind !== "none"
1744
+ ? Math.max(
1745
+ RAW_COLLECTOR_MAX_BYTES,
1746
+ this.session.settings.get("tools.readArtifactSpillThreshold") * 1024,
1747
+ )
1748
+ : undefined,
1749
+ receiptPath: parsed.kind === "none" ? localReadPath : undefined,
1750
+ });
1634
1751
  }
1752
+ content = [{ type: "text", text: `[Cannot read ${ext} file: ${result.error || "conversion failed"}]` }];
1753
+ details = { spillEligible: false };
1635
1754
  } else {
1636
1755
  if (
1637
1756
  parsed.kind === "none" &&
@@ -1646,8 +1765,22 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1646
1765
  renderedSummary.elidedSpans,
1647
1766
  renderedSummary.elidedLines,
1648
1767
  );
1649
- const modelText = footer ? `${renderedSummary.text}\n\n${footer}` : renderedSummary.text;
1768
+ const summaryTotalLines = Math.max(...summary.segments.map(segment => segment.endLine));
1769
+ const modelText = [
1770
+ renderedSummary.text,
1771
+ footer,
1772
+ renderedSummary.capped
1773
+ ? formatSummaryCapFooter(
1774
+ localReadPath,
1775
+ this.session.settings.get("read.summaryMaxBytes") * 1024,
1776
+ summaryTotalLines,
1777
+ )
1778
+ : "",
1779
+ ]
1780
+ .filter(Boolean)
1781
+ .join("\n\n");
1650
1782
  details = {
1783
+ spillEligible: false,
1651
1784
  displayContent: { text: renderedSummary.displayText, startLine: 1 },
1652
1785
  summary: {
1653
1786
  lines: countTextLines(renderedSummary.text),
@@ -1674,7 +1807,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1674
1807
  if (multiResult.bridgeResult) return multiResult.bridgeResult;
1675
1808
  content = [{ type: "text", text: multiResult.outputText }];
1676
1809
  sourcePath = absolutePath;
1677
- details = {};
1810
+ details = { spillEligible: multiResult.contentLineCount > 0 };
1678
1811
  if (multiResult.columnTruncated > 0) {
1679
1812
  columnTruncated = multiResult.columnTruncated;
1680
1813
  }
@@ -1714,13 +1847,25 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1714
1847
  const startLine = requestedStart - leadingContext;
1715
1848
  const startLineDisplay = startLine + 1;
1716
1849
 
1850
+ const isBareReceipt = parsed.kind === "none" && !content;
1851
+ const rawSelector = isRawSelector(parsed);
1717
1852
  const DEFAULT_LIMIT = this.#defaultLimit;
1718
- const effectiveLimit = limit ?? DEFAULT_LIMIT;
1719
- const maxLinesToCollect = Math.min(effectiveLimit + leadingContext + trailingContext, DEFAULT_MAX_LINES);
1720
- const selectedLineLimit = effectiveLimit + leadingContext + trailingContext;
1721
- // Scale byte budget with line limit so the configured line count actually fits.
1722
- // Assume ~512 bytes/line average; never go below the shared default.
1723
- const maxBytesForRead = Math.max(DEFAULT_MAX_BYTES, maxLinesToCollect * 512);
1853
+ const effectiveLimit = rawSelector ? Number.MAX_SAFE_INTEGER : (limit ?? DEFAULT_LIMIT);
1854
+ const receiptBudgetBytes = this.session.settings.get("read.receiptBudgetBytes") * 1024;
1855
+ const maxLinesToCollect = rawSelector
1856
+ ? Number.MAX_SAFE_INTEGER
1857
+ : isBareReceipt
1858
+ ? this.session.settings.get("read.receiptBudgetLines")
1859
+ : Math.min(effectiveLimit + leadingContext + trailingContext, DEFAULT_MAX_LINES);
1860
+ const selectedLineLimit = rawSelector ? null : effectiveLimit + leadingContext + trailingContext;
1861
+ const maxBytesForRead = rawSelector
1862
+ ? Math.max(
1863
+ RAW_COLLECTOR_MAX_BYTES,
1864
+ this.session.settings.get("tools.readArtifactSpillThreshold") * 1024,
1865
+ )
1866
+ : isBareReceipt
1867
+ ? receiptBudgetBytes
1868
+ : Math.max(DEFAULT_MAX_BYTES, maxLinesToCollect * 512);
1724
1869
 
1725
1870
  const streamResult = await streamLinesFromFile(
1726
1871
  absolutePath,
@@ -1757,7 +1902,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1757
1902
  // verbatim bytes for paste-back-into-tool workflows. Total byte/line
1758
1903
  // counts in `truncation` keep reflecting the source, not the trimmed
1759
1904
  // view — column truncation surfaces separately via `.limits()`.
1760
- const rawSelector = isRawSelector(parsed);
1905
+
1761
1906
  const shouldAddHashLines = !rawSelector && displayMode.hashLines;
1762
1907
  const maxColumns = resolveOutputMaxColumns(this.session.settings);
1763
1908
  if (!rawSelector && !shouldAddHashLines && maxColumns > 0) {
@@ -1819,7 +1964,8 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1819
1964
  firstLineBytes,
1820
1965
  )}, exceeds ${formatBytes(maxBytesForRead)} limit. Unable to display a valid UTF-8 snippet.]`;
1821
1966
  }
1822
- details = { truncation };
1967
+ details = { truncation, spillEligible: !isBareReceipt && collectedLines.length > 0 };
1968
+
1823
1969
  sourcePath = absolutePath;
1824
1970
  truncationInfo = {
1825
1971
  result: truncation,
@@ -1827,7 +1973,8 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1827
1973
  };
1828
1974
  } else if (truncation.truncated) {
1829
1975
  outputText = formatText(truncation.content, startLineDisplay);
1830
- details = { truncation };
1976
+ details = { truncation, spillEligible: !isBareReceipt && collectedLines.length > 0 };
1977
+
1831
1978
  sourcePath = absolutePath;
1832
1979
  truncationInfo = {
1833
1980
  result: truncation,
@@ -1839,14 +1986,22 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
1839
1986
 
1840
1987
  outputText = formatText(truncation.content, startLineDisplay);
1841
1988
  outputText += `\n\n[${remaining} more lines in file. Use :${nextOffset} to continue]`;
1842
- details = {};
1989
+ details = { spillEligible: !isBareReceipt && collectedLines.length > 0 };
1990
+
1843
1991
  sourcePath = absolutePath;
1844
1992
  } else {
1845
1993
  // No truncation, no user limit exceeded
1846
1994
  outputText = formatText(truncation.content, startLineDisplay);
1847
- details = {};
1995
+ details = { spillEligible: !isBareReceipt && collectedLines.length > 0 };
1996
+
1848
1997
  sourcePath = absolutePath;
1849
1998
  }
1999
+ if (isBareReceipt && (truncation.truncated || collectedLines.length < totalFileLines)) {
2000
+ outputText += `\n\n${formatReceiptFooter(localReadPath, collectedLines.length, totalFileLines, collectedBytes)}`;
2001
+ }
2002
+ if (rawSelector && truncation.truncated) {
2003
+ outputText += `\n\n[Raw read capped at ${formatBytes(maxBytesForRead)} of ${formatBytes(fileSize)}; re-read a line range to narrow the view]`;
2004
+ }
1850
2005
 
1851
2006
  if (capturedDisplayContent) {
1852
2007
  details.displayContent = capturedDisplayContent;
@@ -2073,23 +2228,23 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
2073
2228
  }
2074
2229
  throwIfAborted(signal);
2075
2230
 
2076
- const output = tree.totalLines <= 1 ? "(empty directory)" : tree.rendered;
2077
- const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
2078
- const details: ReadToolDetails = {
2079
- isDirectory: true,
2080
- resolvedPath: tree.rootPath,
2081
- };
2082
-
2083
- const resultBuilder = toolResult(details).text(truncation.content).sourcePath(tree.rootPath);
2084
- if (tree.truncated) {
2085
- resultBuilder.limits({ resultLimit: 1 });
2086
- }
2087
- if (truncation.truncated) {
2088
- resultBuilder.truncation(truncation, { direction: "head" });
2089
- details.truncation = truncation;
2090
- }
2091
-
2092
- return resultBuilder.done();
2231
+ const receiptLines = this.session.settings.get("read.receiptBudgetLines");
2232
+ const receiptBytes = this.session.settings.get("read.receiptBudgetBytes") * 1024;
2233
+ const sourceLines = tree.totalLines <= 1 ? ["(empty directory)"] : tree.rendered.split("\n");
2234
+ const bodyLines: string[] = [];
2235
+ let bodyBytes = 0;
2236
+ for (const line of sourceLines) {
2237
+ const bytes = Buffer.byteLength(line, "utf-8") + (bodyLines.length > 0 ? 1 : 0);
2238
+ if (bodyLines.length >= receiptLines || bodyBytes + bytes > receiptBytes) break;
2239
+ bodyLines.push(line);
2240
+ bodyBytes += bytes;
2241
+ }
2242
+ let output = bodyLines.join("\n");
2243
+ if (bodyLines.length < sourceLines.length || tree.truncated) {
2244
+ output += `\n\n[Listing truncated at ${bodyLines.length} lines / ${Math.ceil(bodyBytes / 1024)} KiB; read a deeper subpath (e.g. ${absolutePath}/<subdir>) to narrow the view]`;
2245
+ }
2246
+ const details: ReadToolDetails = { isDirectory: true, spillEligible: false, resolvedPath: tree.rootPath };
2247
+ return toolResult(details).text(output).sourcePath(tree.rootPath).done();
2093
2248
  }
2094
2249
  }
2095
2250
 
@@ -177,7 +177,7 @@ function ownerBrowserPolicy(snapshot: TabGcSnapshot): BrowserGcPolicy | null {
177
177
  /** Coarse, ordering-only eligibility; the live recheck in releaseTabIfGcEligible is authoritative. */
178
178
  function isCoarselyEligible(snapshot: TabGcSnapshot): boolean {
179
179
  return (
180
- snapshot.state === "alive" &&
180
+ (snapshot.state === "alive" || snapshot.state === "dead") &&
181
181
  snapshot.pendingCount === 0 &&
182
182
  (snapshot.kindTag === "headless" || snapshot.kindTag === "spawned")
183
183
  );
@@ -230,7 +230,7 @@ function evaluateRssPressureWarning(d: ResourceGcDeps): void {
230
230
  return;
231
231
  }
232
232
  const reclaimableRemains = collectIdleCandidates(d).some(
233
- c => c.snapshot.ownerId !== undefined && pressured.has(c.snapshot.ownerId),
233
+ c => c.snapshot.state === "alive" && c.snapshot.ownerId !== undefined && pressured.has(c.snapshot.ownerId),
234
234
  );
235
235
  if (reclaimableRemains) {
236
236
  rssWarningActive = false;
@@ -10,21 +10,13 @@ import {
10
10
  buildDiscoverableToolSearchIndex,
11
11
  type DiscoverableTool,
12
12
  type DiscoverableToolSearchIndex,
13
- formatDiscoverableToolServerSummary,
14
13
  searchDiscoverableTools,
15
- summarizeDiscoverableTools,
16
14
  } from "../tool-discovery/tool-index";
17
15
  import { renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
18
16
  import type { ToolSession } from ".";
19
17
  import { formatCount, replaceTabs, TRUNCATE_LENGTHS } from "./render-utils";
20
18
  import { ToolError } from "./tool-errors";
21
19
 
22
- // Re-export legacy MCP types for back-compat (tests and external callers may reference them)
23
- export type {
24
- DiscoverableMCPSearchIndex,
25
- DiscoverableMCPTool,
26
- } from "../runtime-mcp/discoverable-tool-metadata";
27
-
28
20
  const DEFAULT_LIMIT = 8;
29
21
  const TOOL_DISCOVERY_TITLE = "Tool Discovery";
30
22
  const COLLAPSED_MATCH_LIMIT = 5;
@@ -78,24 +70,9 @@ function buildSearchToolBm25Content(details: SearchToolBm25Details): string {
78
70
  });
79
71
  }
80
72
 
81
- /** Get discoverable tools for description rendering. Falls back to empty array on error. */
82
73
  function getDiscoverableToolsForDescription(session: ToolSession): DiscoverableTool[] {
83
74
  try {
84
- // Prefer generic method; fall back to legacy MCP-only
85
- if (session.getDiscoverableTools) {
86
- return session.getDiscoverableTools();
87
- }
88
- // Legacy MCP path — adapt DiscoverableMCPTool (with `description`) → DiscoverableTool.
89
- const legacy = session.getDiscoverableMCPTools?.() ?? [];
90
- return legacy.map(t => ({
91
- name: t.name,
92
- label: t.label,
93
- summary: t.description,
94
- source: "mcp" as const,
95
- serverName: t.serverName,
96
- mcpToolName: t.mcpToolName,
97
- schemaKeys: t.schemaKeys,
98
- }));
75
+ return session.getDiscoverableTools?.() ?? [];
99
76
  } catch {
100
77
  return [];
101
78
  }
@@ -103,36 +80,18 @@ function getDiscoverableToolsForDescription(session: ToolSession): DiscoverableT
103
80
 
104
81
  function getDiscoverableToolSearchIndexForExecution(session: ToolSession): DiscoverableToolSearchIndex {
105
82
  try {
106
- // Prefer generic cached index
107
- if (session.getDiscoverableToolSearchIndex) {
108
- const cached = session.getDiscoverableToolSearchIndex();
109
- if (cached) return cached;
110
- }
111
- // Legacy MCP: use cached MCP index. Its documents expose `tool.description` as well as
112
- // `tool.summary`, so it is structurally compatible with DiscoverableToolSearchIndex.
113
- const mcpCached = session.getDiscoverableMCPSearchIndex?.();
114
- if (mcpCached) return mcpCached as unknown as DiscoverableToolSearchIndex;
83
+ const cached = session.getDiscoverableToolSearchIndex?.();
84
+ if (cached) return cached;
115
85
  } catch {}
116
86
  return buildDiscoverableToolSearchIndex(getDiscoverableToolsForDescription(session));
117
87
  }
118
88
 
119
- /** Resolve the effective selected tool names (generic or legacy MCP). */
120
89
  function getSelectedToolNames(session: ToolSession): string[] {
121
- if (session.getSelectedDiscoveredToolNames) {
122
- return session.getSelectedDiscoveredToolNames();
123
- }
124
- return session.getSelectedMCPToolNames?.() ?? [];
90
+ return session.getSelectedDiscoveredToolNames?.() ?? [];
125
91
  }
126
92
 
127
- /** Activate tools (generic or legacy MCP fallback). */
128
93
  async function activateTools(session: ToolSession, toolNames: string[]): Promise<string[]> {
129
- if (session.activateDiscoveredTools) {
130
- return session.activateDiscoveredTools(toolNames);
131
- }
132
- if (session.activateDiscoveredMCPTools) {
133
- return session.activateDiscoveredMCPTools(toolNames);
134
- }
135
- return [];
94
+ return (await session.activateDiscoveredTools?.(toolNames)) ?? [];
136
95
  }
137
96
 
138
97
  type DiscoveryExecutionSession = ToolSession & {
@@ -140,39 +99,19 @@ type DiscoveryExecutionSession = ToolSession & {
140
99
  };
141
100
 
142
101
  function supportsToolDiscoveryExecution(session: ToolSession): session is DiscoveryExecutionSession {
143
- // Supports generic discovery
144
- if (
102
+ return (
145
103
  typeof session.isToolDiscoveryEnabled === "function" &&
146
104
  typeof session.getSelectedDiscoveredToolNames === "function" &&
147
105
  typeof session.activateDiscoveredTools === "function"
148
- ) {
149
- return true;
150
- }
151
- // Supports legacy MCP discovery
152
- if (
153
- typeof session.isMCPDiscoveryEnabled === "function" &&
154
- typeof session.getSelectedMCPToolNames === "function" &&
155
- typeof session.activateDiscoveredMCPTools === "function"
156
- ) {
157
- return true;
158
- }
159
- return false;
106
+ );
160
107
  }
161
108
 
162
109
  function isDiscoveryEnabled(session: ToolSession): boolean {
163
- if (typeof session.isToolDiscoveryEnabled === "function") {
164
- return session.isToolDiscoveryEnabled();
165
- }
166
- return session.isMCPDiscoveryEnabled?.() ?? false;
110
+ return session.isToolDiscoveryEnabled?.() ?? false;
167
111
  }
168
112
 
169
- export function renderSearchToolBm25Description(discoverableTools: DiscoverableTool[] = []): string {
170
- const summary = summarizeDiscoverableTools(discoverableTools);
171
- return prompt.render(searchToolBm25Description, {
172
- discoverableMCPToolCount: summary.toolCount,
173
- discoverableMCPServerSummaries: summary.servers.map(formatDiscoverableToolServerSummary),
174
- hasDiscoverableMCPServers: summary.servers.length > 0,
175
- });
113
+ export function renderSearchToolBm25Description(): string {
114
+ return prompt.render(searchToolBm25Description, {});
176
115
  }
177
116
 
178
117
  function renderMatchLines(match: SearchToolBm25Match, theme: Theme): string[] {
@@ -209,9 +148,7 @@ export class SearchToolBm25Tool implements AgentTool<typeof searchToolBm25Schema
209
148
  readonly name = "search_tool_bm25";
210
149
  readonly label = "SearchTools";
211
150
  readonly loadMode = "essential";
212
- get description(): string {
213
- return renderSearchToolBm25Description(getDiscoverableToolsForDescription(this.session));
214
- }
151
+ readonly description = renderSearchToolBm25Description();
215
152
  readonly parameters = searchToolBm25Schema;
216
153
  readonly strict = true;
217
154