@vellumai/assistant 0.6.5 → 0.6.6

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 (443) hide show
  1. package/AGENTS.md +9 -1
  2. package/ARCHITECTURE.md +15 -17
  3. package/Dockerfile +6 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
  5. package/docs/architecture/integrations.md +32 -39
  6. package/docs/architecture/memory.md +25 -30
  7. package/docs/architecture/security.md +7 -6
  8. package/docs/browser-use-architecture-phase2.md +63 -20
  9. package/docs/plugins.md +761 -0
  10. package/examples/plugins/echo/README.md +132 -0
  11. package/examples/plugins/echo/package.json +17 -0
  12. package/examples/plugins/echo/register.ts +187 -0
  13. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  14. package/openapi.yaml +212 -68
  15. package/package.json +1 -1
  16. package/src/__tests__/app-compiler.test.ts +57 -0
  17. package/src/__tests__/approval-cascade.test.ts +7 -2
  18. package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
  19. package/src/__tests__/avatar-generator.test.ts +4 -2
  20. package/src/__tests__/bundled-asset.test.ts +6 -6
  21. package/src/__tests__/catalog-cache.test.ts +69 -0
  22. package/src/__tests__/checker.test.ts +459 -171
  23. package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
  24. package/src/__tests__/compaction-events.test.ts +501 -0
  25. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  26. package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
  27. package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
  28. package/src/__tests__/config-model-image-provider.test.ts +110 -0
  29. package/src/__tests__/config-schema.test.ts +22 -9
  30. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
  31. package/src/__tests__/contacts-tools.test.ts +26 -0
  32. package/src/__tests__/context-overflow-policy.test.ts +7 -7
  33. package/src/__tests__/context-window-manager.test.ts +355 -4
  34. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
  36. package/src/__tests__/conversation-agent-loop.test.ts +30 -141
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
  38. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
  40. package/src/__tests__/conversation-pairing.test.ts +174 -10
  41. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
  42. package/src/__tests__/conversation-process-callsite.test.ts +3 -0
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
  44. package/src/__tests__/conversation-queue.test.ts +29 -14
  45. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
  47. package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
  48. package/src/__tests__/conversation-seed-composer.test.ts +2 -2
  49. package/src/__tests__/conversation-slash-queue.test.ts +7 -2
  50. package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
  51. package/src/__tests__/conversation-speed-override.test.ts +6 -1
  52. package/src/__tests__/conversation-title-service.test.ts +116 -0
  53. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
  54. package/src/__tests__/conversation-usage.test.ts +1 -1
  55. package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
  56. package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
  57. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
  58. package/src/__tests__/credential-health-service.test.ts +78 -9
  59. package/src/__tests__/credential-security-invariants.test.ts +2 -2
  60. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  61. package/src/__tests__/empty-response-pipeline.test.ts +305 -0
  62. package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
  63. package/src/__tests__/first-greeting.test.ts +247 -5
  64. package/src/__tests__/headless-browser-mode.test.ts +57 -0
  65. package/src/__tests__/history-repair-pipeline.test.ts +399 -0
  66. package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
  67. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
  68. package/src/__tests__/host-proxy-interface.test.ts +36 -2
  69. package/src/__tests__/image-credentials.test.ts +137 -0
  70. package/src/__tests__/image-service-dispatcher.test.ts +186 -0
  71. package/src/__tests__/injector-chain.test.ts +526 -0
  72. package/src/__tests__/intent-routing.test.ts +0 -26
  73. package/src/__tests__/llm-call-pipeline.test.ts +285 -0
  74. package/src/__tests__/llm-schema.test.ts +1 -1
  75. package/src/__tests__/media-generate-image.test.ts +119 -13
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
  77. package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
  78. package/src/__tests__/migration-import-from-url.test.ts +5 -68
  79. package/src/__tests__/model-intents.test.ts +4 -2
  80. package/src/__tests__/notification-broadcaster.test.ts +3 -3
  81. package/src/__tests__/notification-decision-strategy.test.ts +0 -11
  82. package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
  83. package/src/__tests__/oauth-apps-routes.test.ts +1 -1
  84. package/src/__tests__/oauth-cli.test.ts +14 -12
  85. package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
  86. package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
  87. package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
  88. package/src/__tests__/oauth-providers-routes.test.ts +3 -2
  89. package/src/__tests__/oauth-store.test.ts +41 -76
  90. package/src/__tests__/onboarding-template-contract.test.ts +16 -64
  91. package/src/__tests__/openai-image-service.test.ts +368 -0
  92. package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
  93. package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
  94. package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
  95. package/src/__tests__/persistence-pipeline.test.ts +377 -0
  96. package/src/__tests__/pipeline-runner.test.ts +565 -0
  97. package/src/__tests__/platform.test.ts +5 -2
  98. package/src/__tests__/plugin-bootstrap.test.ts +483 -0
  99. package/src/__tests__/plugin-registry.test.ts +273 -0
  100. package/src/__tests__/plugin-route-contribution.test.ts +288 -0
  101. package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
  102. package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
  103. package/src/__tests__/plugin-types.test.ts +320 -0
  104. package/src/__tests__/pricing.test.ts +44 -12
  105. package/src/__tests__/proxy-approval-callback.test.ts +69 -8
  106. package/src/__tests__/reaction-persistence.test.ts +1 -0
  107. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  108. package/src/__tests__/registry.test.ts +0 -2
  109. package/src/__tests__/schedule-routes.test.ts +131 -1
  110. package/src/__tests__/scheduler-recurrence.test.ts +14 -70
  111. package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
  112. package/src/__tests__/secret-detection-handler.test.ts +0 -10
  113. package/src/__tests__/shell-identity.test.ts +0 -134
  114. package/src/__tests__/suggestion-routes.test.ts +103 -4
  115. package/src/__tests__/task-memory-cleanup.test.ts +1 -0
  116. package/src/__tests__/task-scheduler.test.ts +3 -15
  117. package/src/__tests__/test-preload.ts +11 -0
  118. package/src/__tests__/title-generate-pipeline.test.ts +224 -0
  119. package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
  120. package/src/__tests__/tool-error-pipeline.test.ts +244 -0
  121. package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
  122. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
  123. package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
  124. package/src/__tests__/tool-executor.test.ts +141 -0
  125. package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
  126. package/src/__tests__/tool-result-truncation.test.ts +0 -110
  127. package/src/__tests__/user-plugin-loader.test.ts +191 -0
  128. package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
  129. package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
  130. package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
  131. package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
  132. package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
  133. package/src/__tests__/workspace-policy.test.ts +21 -3
  134. package/src/agent/loop.ts +340 -102
  135. package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
  136. package/src/approvals/guardian-request-resolvers.ts +80 -0
  137. package/src/backup/__tests__/backup-worker.test.ts +2 -13
  138. package/src/backup/backup-worker.ts +3 -15
  139. package/src/bundler/app-compiler.ts +84 -1
  140. package/src/calls/call-state.ts +2 -2
  141. package/src/channels/__tests__/types.test.ts +3 -3
  142. package/src/channels/types.ts +6 -4
  143. package/src/cli/__tests__/notifications.test.ts +87 -211
  144. package/src/cli/commands/__tests__/backup.test.ts +1 -1
  145. package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
  146. package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
  147. package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
  148. package/src/cli/commands/backup.ts +2 -2
  149. package/src/cli/commands/clients.ts +138 -0
  150. package/src/cli/commands/completions.ts +2 -9
  151. package/src/cli/commands/conversations.ts +55 -7
  152. package/src/cli/commands/image-generation.ts +33 -34
  153. package/src/cli/commands/notifications.ts +68 -103
  154. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
  155. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  156. package/src/cli/commands/oauth/connect.ts +2 -2
  157. package/src/cli/commands/oauth/providers.ts +176 -8
  158. package/src/cli/commands/oauth/status.ts +46 -36
  159. package/src/cli/commands/skills.ts +3 -4
  160. package/src/cli/program.ts +25 -29
  161. package/src/config/__tests__/backup-schema.test.ts +7 -2
  162. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  163. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
  164. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
  165. package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
  166. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
  170. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  171. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
  172. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
  174. package/src/config/bundled-skills/schedule/SKILL.md +8 -3
  175. package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
  176. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
  177. package/src/config/bundled-tool-registry.ts +0 -15
  178. package/src/config/feature-flag-registry.json +17 -1
  179. package/src/config/schema.ts +19 -0
  180. package/src/config/schemas/backup.ts +1 -1
  181. package/src/config/schemas/conversations.ts +16 -0
  182. package/src/config/schemas/llm.ts +2 -3
  183. package/src/config/schemas/security.ts +6 -6
  184. package/src/config/schemas/tts.ts +11 -0
  185. package/src/config/skill-state.ts +6 -2
  186. package/src/config/skills.ts +94 -5
  187. package/src/context/__tests__/compact-prompt.test.ts +27 -9
  188. package/src/context/prompts/compact.md +26 -12
  189. package/src/context/tool-result-truncation.ts +3 -63
  190. package/src/context/window-manager.ts +190 -16
  191. package/src/credential-health/credential-health-service.ts +19 -6
  192. package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
  193. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
  194. package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
  195. package/src/daemon/config-watcher.ts +0 -2
  196. package/src/daemon/context-overflow-policy.ts +4 -13
  197. package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
  198. package/src/daemon/conversation-agent-loop.ts +984 -683
  199. package/src/daemon/conversation-history.ts +10 -19
  200. package/src/daemon/conversation-lifecycle.ts +37 -19
  201. package/src/daemon/conversation-notifiers.ts +2 -110
  202. package/src/daemon/conversation-process.ts +14 -7
  203. package/src/daemon/conversation-runtime-assembly.ts +532 -411
  204. package/src/daemon/conversation-tool-setup.ts +41 -4
  205. package/src/daemon/conversation.ts +80 -35
  206. package/src/daemon/external-plugins-bootstrap.ts +478 -0
  207. package/src/daemon/first-greeting.ts +191 -14
  208. package/src/daemon/handlers/config-model.ts +11 -0
  209. package/src/daemon/handlers/skills.ts +5 -1
  210. package/src/daemon/lifecycle.ts +33 -68
  211. package/src/daemon/message-types/computer-use.ts +2 -34
  212. package/src/daemon/message-types/conversations.ts +49 -0
  213. package/src/daemon/message-types/messages.ts +12 -0
  214. package/src/daemon/server.ts +5 -3
  215. package/src/daemon/shutdown-handlers.ts +2 -12
  216. package/src/daemon/tool-side-effects.ts +14 -56
  217. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
  218. package/src/heartbeat/heartbeat-service.ts +24 -1
  219. package/src/home/__tests__/feed-population-integration.test.ts +312 -0
  220. package/src/home/emit-feed-event.ts +7 -0
  221. package/src/home/feed-types.ts +41 -2
  222. package/src/home/rewrite-command-preview.ts +66 -0
  223. package/src/ipc/__tests__/socket-path.test.ts +11 -50
  224. package/src/ipc/cli-client.ts +1 -1
  225. package/src/ipc/cli-server.ts +3 -3
  226. package/src/ipc/gateway-client.ts +4 -1
  227. package/src/ipc/routes/browser-context.ts +2 -0
  228. package/src/ipc/routes/browser.ts +1 -0
  229. package/src/ipc/routes/get-contact.ts +16 -0
  230. package/src/ipc/routes/index.ts +14 -0
  231. package/src/ipc/routes/list-clients.ts +31 -0
  232. package/src/ipc/routes/merge-contacts.ts +17 -0
  233. package/src/ipc/routes/notification.ts +133 -0
  234. package/src/ipc/routes/rename-conversation.ts +59 -0
  235. package/src/ipc/routes/search-contacts.ts +19 -0
  236. package/src/ipc/routes/upsert-contact.ts +25 -0
  237. package/src/ipc/socket-path.ts +14 -38
  238. package/src/media/app-icon-generator.ts +23 -46
  239. package/src/media/avatar-router.ts +26 -41
  240. package/src/media/gemini-image-service.ts +8 -41
  241. package/src/media/image-credentials.ts +73 -0
  242. package/src/media/image-service.ts +85 -0
  243. package/src/media/openai-image-service.ts +131 -0
  244. package/src/media/types.ts +46 -0
  245. package/src/memory/conversation-crud.ts +48 -18
  246. package/src/memory/conversation-queries.ts +57 -4
  247. package/src/memory/conversation-title-service.ts +25 -0
  248. package/src/memory/db-init.ts +8 -0
  249. package/src/memory/embedding-gemini.test.ts +41 -2
  250. package/src/memory/embedding-gemini.ts +6 -1
  251. package/src/memory/graph/bootstrap.test.ts +282 -0
  252. package/src/memory/graph/bootstrap.ts +8 -5
  253. package/src/memory/graph/extraction.ts +10 -2
  254. package/src/memory/graph/graph-search.test.ts +1 -0
  255. package/src/memory/graph/inspect.ts +2 -2
  256. package/src/memory/graph/retriever.ts +10 -3
  257. package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
  258. package/src/memory/migrations/149-oauth-tables.ts +1 -0
  259. package/src/memory/migrations/223-schedule-script-column.ts +11 -0
  260. package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
  261. package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
  262. package/src/memory/migrations/index.ts +4 -0
  263. package/src/memory/pkb/pkb-index.test.ts +1 -0
  264. package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
  265. package/src/memory/pkb/pkb-search.test.ts +65 -4
  266. package/src/memory/pkb/pkb-search.ts +40 -18
  267. package/src/memory/qdrant-client.test.ts +60 -0
  268. package/src/memory/qdrant-client.ts +25 -0
  269. package/src/memory/schema/infrastructure.ts +1 -0
  270. package/src/memory/schema/oauth.ts +4 -1
  271. package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
  272. package/src/messaging/providers/slack/render-transcript.ts +58 -0
  273. package/src/notifications/conversation-pairing.ts +78 -19
  274. package/src/notifications/copy-composer.ts +0 -5
  275. package/src/notifications/emit-signal.ts +1 -1
  276. package/src/notifications/signal.ts +1 -2
  277. package/src/oauth/AGENTS.md +1 -1
  278. package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
  279. package/src/oauth/connect-orchestrator.ts +8 -34
  280. package/src/oauth/connect-types.ts +6 -10
  281. package/src/oauth/manual-token-connection.ts +23 -0
  282. package/src/oauth/oauth-store.ts +30 -14
  283. package/src/oauth/provider-serializer.ts +6 -1
  284. package/src/oauth/seed-providers.ts +56 -108
  285. package/src/outbound-proxy/http-forwarder.ts +9 -0
  286. package/src/permissions/approval-policy.test.ts +293 -18
  287. package/src/permissions/approval-policy.ts +110 -58
  288. package/src/permissions/arg-parser.test.ts +161 -0
  289. package/src/permissions/arg-parser.ts +141 -0
  290. package/src/permissions/bash-risk-classifier.test.ts +414 -2
  291. package/src/permissions/bash-risk-classifier.ts +303 -60
  292. package/src/permissions/checker.ts +157 -29
  293. package/src/permissions/command-registry.test.ts +239 -0
  294. package/src/permissions/command-registry.ts +234 -54
  295. package/src/permissions/defaults.ts +5 -4
  296. package/src/permissions/gateway-threshold-reader.ts +196 -0
  297. package/src/permissions/prompter.ts +4 -0
  298. package/src/permissions/risk-types.ts +61 -4
  299. package/src/permissions/schedule-risk-classifier.test.ts +129 -0
  300. package/src/permissions/schedule-risk-classifier.ts +85 -0
  301. package/src/permissions/shell-identity.ts +2 -42
  302. package/src/permissions/types.ts +2 -0
  303. package/src/permissions/workspace-policy.ts +8 -3
  304. package/src/plugins/defaults/circuit-breaker.ts +146 -0
  305. package/src/plugins/defaults/compaction.ts +145 -0
  306. package/src/plugins/defaults/empty-response.ts +126 -0
  307. package/src/plugins/defaults/history-repair.ts +85 -0
  308. package/src/plugins/defaults/index.ts +116 -0
  309. package/src/plugins/defaults/injectors.ts +491 -0
  310. package/src/plugins/defaults/llm-call.ts +82 -0
  311. package/src/plugins/defaults/memory-retrieval.ts +226 -0
  312. package/src/plugins/defaults/overflow-reduce.ts +181 -0
  313. package/src/plugins/defaults/persistence.ts +129 -0
  314. package/src/plugins/defaults/title-generate.ts +95 -0
  315. package/src/plugins/defaults/token-estimate.ts +104 -0
  316. package/src/plugins/defaults/tool-error.ts +126 -0
  317. package/src/plugins/defaults/tool-execute.ts +89 -0
  318. package/src/plugins/defaults/tool-result-truncate.ts +88 -0
  319. package/src/plugins/pipeline.ts +316 -0
  320. package/src/plugins/plugin-skill-contributions.ts +292 -0
  321. package/src/plugins/registry.ts +241 -0
  322. package/src/plugins/types.ts +1134 -0
  323. package/src/plugins/user-loader.ts +177 -0
  324. package/src/prompts/templates/BOOTSTRAP.md +27 -77
  325. package/src/providers/model-catalog.ts +52 -29
  326. package/src/providers/model-intents.ts +1 -1
  327. package/src/providers/openrouter/client.ts +5 -1
  328. package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
  329. package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
  330. package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
  331. package/src/providers/speech-to-text/xai-realtime.ts +39 -14
  332. package/src/runtime/AGENTS.md +25 -16
  333. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
  334. package/src/runtime/__tests__/client-registry.test.ts +293 -0
  335. package/src/runtime/client-registry.ts +261 -0
  336. package/src/runtime/http-server.ts +77 -8
  337. package/src/runtime/http-types.ts +0 -2
  338. package/src/runtime/migrations/vbundle-builder.ts +1 -22
  339. package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
  340. package/src/runtime/routes/approval-routes.ts +17 -0
  341. package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
  342. package/src/runtime/routes/conversation-routes.ts +223 -116
  343. package/src/runtime/routes/inbound-message-handler.ts +88 -13
  344. package/src/runtime/routes/memory-item-routes.test.ts +1 -0
  345. package/src/runtime/routes/migration-routes.ts +0 -3
  346. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
  347. package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
  348. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
  349. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
  350. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
  351. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
  352. package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
  353. package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
  354. package/src/runtime/routes/playground/deps.ts +56 -0
  355. package/src/runtime/routes/playground/force-compact.ts +73 -0
  356. package/src/runtime/routes/playground/guard.ts +37 -0
  357. package/src/runtime/routes/playground/index.ts +28 -0
  358. package/src/runtime/routes/playground/inject-failures.ts +159 -0
  359. package/src/runtime/routes/playground/reset-circuit.ts +115 -0
  360. package/src/runtime/routes/playground/seed-conversation.ts +139 -0
  361. package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
  362. package/src/runtime/routes/playground/state.ts +78 -0
  363. package/src/runtime/routes/schedule-routes.ts +89 -8
  364. package/src/runtime/skill-route-registry.ts +75 -15
  365. package/src/schedule/run-script.ts +68 -0
  366. package/src/schedule/schedule-store.ts +7 -1
  367. package/src/schedule/scheduler.ts +48 -8
  368. package/src/skills/catalog-cache.ts +12 -5
  369. package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
  370. package/src/tools/browser/browser-execution.ts +88 -19
  371. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
  372. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
  373. package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
  374. package/src/tools/browser/cdp-client/factory.ts +15 -4
  375. package/src/tools/executor.ts +126 -74
  376. package/src/tools/network/script-proxy/session-manager.ts +37 -1
  377. package/src/tools/permission-checker.ts +98 -49
  378. package/src/tools/policy-context.ts +4 -0
  379. package/src/tools/registry.ts +140 -3
  380. package/src/tools/schedule/create.ts +23 -8
  381. package/src/tools/schedule/update.ts +3 -1
  382. package/src/tools/secret-detection-handler.ts +0 -51
  383. package/src/tools/system/avatar-generator.ts +6 -2
  384. package/src/tools/types.ts +28 -2
  385. package/src/util/platform.ts +7 -2
  386. package/src/util/pricing.ts +26 -3
  387. package/src/workspace/migrations/006-services-config.ts +2 -4
  388. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
  389. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
  390. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
  391. package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
  392. package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
  393. package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
  394. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
  395. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
  396. package/src/workspace/migrations/registry.ts +12 -0
  397. package/tsconfig.json +1 -1
  398. package/hook-templates/debug-prompt-logger/hook.json +0 -7
  399. package/hook-templates/debug-prompt-logger/run.sh +0 -66
  400. package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
  401. package/src/__tests__/context-overflow-approval.test.ts +0 -156
  402. package/src/__tests__/hooks-blocking.test.ts +0 -178
  403. package/src/__tests__/hooks-cli.test.ts +0 -182
  404. package/src/__tests__/hooks-config.test.ts +0 -108
  405. package/src/__tests__/hooks-discovery.test.ts +0 -211
  406. package/src/__tests__/hooks-integration.test.ts +0 -196
  407. package/src/__tests__/hooks-manager.test.ts +0 -226
  408. package/src/__tests__/hooks-runner.test.ts +0 -175
  409. package/src/__tests__/hooks-settings.test.ts +0 -160
  410. package/src/__tests__/hooks-templates.test.ts +0 -169
  411. package/src/__tests__/hooks-ts-runner.test.ts +0 -170
  412. package/src/__tests__/hooks-watch.test.ts +0 -112
  413. package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
  414. package/src/__tests__/oauth-scope-policy.test.ts +0 -180
  415. package/src/__tests__/send-notification-tool.test.ts +0 -83
  416. package/src/cli/commands/shotgun.ts +0 -266
  417. package/src/config/bundled-skills/conversations/SKILL.md +0 -20
  418. package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
  419. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
  420. package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
  421. package/src/config/bundled-skills/notifications/SKILL.md +0 -40
  422. package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
  423. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
  424. package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
  425. package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
  426. package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
  427. package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
  428. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
  429. package/src/daemon/context-overflow-approval.ts +0 -52
  430. package/src/daemon/watch-handler.ts +0 -399
  431. package/src/hooks/cli.ts +0 -253
  432. package/src/hooks/config.ts +0 -100
  433. package/src/hooks/discovery.ts +0 -135
  434. package/src/hooks/manager.ts +0 -179
  435. package/src/hooks/runner.ts +0 -117
  436. package/src/hooks/templates.ts +0 -77
  437. package/src/hooks/types.ts +0 -75
  438. package/src/oauth/scope-policy.ts +0 -89
  439. package/src/runtime/gateway-internal-client.ts +0 -94
  440. package/src/runtime/routes/watch-routes.ts +0 -156
  441. package/src/signals/shotgun.ts +0 -203
  442. package/src/tools/watch/screen-watch.ts +0 -144
  443. package/src/tools/watch/watch-state.ts +0 -142
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Default `tokenEstimate` plugin.
3
+ *
4
+ * The plugin's middleware is a passthrough — it calls `next(args)` and returns
5
+ * the result unchanged. The actual estimate lives in
6
+ * {@link defaultTokenEstimateTerminal}, which is wired in as the pipeline's
7
+ * `terminal` argument by `runPipeline` call sites in
8
+ * `daemon/conversation-agent-loop.ts`. This separation matters: the default
9
+ * plugin is registered before any user plugin (defaults load first in
10
+ * `bootstrapPlugins()`), which puts it at the OUTERMOST position of the onion
11
+ * chain. If the default middleware were to invoke the terminal directly
12
+ * without calling `next`, it would shadow every later-registered plugin. The
13
+ * passthrough lets user middleware that wraps the default (e.g. a doubler, a
14
+ * provider-native `countTokens` override) participate normally.
15
+ *
16
+ * The terminal delegates to
17
+ * {@link import("../../context/token-estimator.js").estimatePromptTokens estimatePromptTokens},
18
+ * which applies the EWMA calibration correction recorded from past provider
19
+ * responses. Preflight + mid-loop checks must use the calibrated estimate —
20
+ * before this pipeline existed, both call sites invoked `estimatePromptTokens`
21
+ * directly, and the calibrated estimate is what keeps the overflow gate
22
+ * consistent with the convergence path in the reducer. The pre-send
23
+ * calibration capture in `agent/loop.ts` still uses `estimatePromptTokensRaw`
24
+ * on purpose — the calibrator must learn against the raw estimate so the EWMA
25
+ * converges against provider ground truth rather than chasing its own
26
+ * corrected output. Pipelines produce user-facing estimates; calibration
27
+ * capture stays outside the pipeline.
28
+ */
29
+
30
+ import {
31
+ estimatePromptTokens,
32
+ estimateToolsTokens,
33
+ } from "../../context/token-estimator.js";
34
+ import { registerPlugin } from "../registry.js";
35
+ import {
36
+ type EstimateArgs,
37
+ type EstimateResult,
38
+ type Middleware,
39
+ type Plugin,
40
+ PluginExecutionError,
41
+ } from "../types.js";
42
+
43
+ /**
44
+ * Terminal handler for the `tokenEstimate` pipeline. Computes the tool token
45
+ * budget from `args.tools` and delegates to {@link estimatePromptTokens} with
46
+ * the canonical provider key, applying the EWMA calibration correction.
47
+ * Exported so tests can verify default behavior directly without going through
48
+ * `runPipeline`, and so `daemon/conversation-agent-loop.ts` can pass it as the
49
+ * `terminal` argument to `runPipeline`.
50
+ */
51
+ export const defaultTokenEstimateTerminal = async (
52
+ args: EstimateArgs,
53
+ ): Promise<EstimateResult> => {
54
+ const toolTokenBudget =
55
+ args.tools.length > 0 ? estimateToolsTokens(args.tools) : 0;
56
+ return estimatePromptTokens(args.history, args.systemPrompt, {
57
+ providerName: args.providerName,
58
+ toolTokenBudget,
59
+ });
60
+ };
61
+
62
+ const passthrough: Middleware<EstimateArgs, EstimateResult> = async (
63
+ args,
64
+ next,
65
+ ) => next(args);
66
+
67
+ /**
68
+ * Default `tokenEstimate` plugin. Registered by
69
+ * {@link bootstrapPlugins} on daemon startup so the pipeline always has a
70
+ * terminal handler even when no other plugin contributes one.
71
+ */
72
+ export const defaultTokenEstimatePlugin: Plugin = {
73
+ manifest: {
74
+ name: "default-token-estimate",
75
+ version: "1.0.0",
76
+ provides: { tokenEstimate: "v1" },
77
+ requires: { pluginRuntime: "v1", tokenEstimateApi: "v1" },
78
+ },
79
+ middleware: {
80
+ tokenEstimate: passthrough,
81
+ },
82
+ };
83
+
84
+ // Module-load side effect: register this default at import time so
85
+ // downstream consumers (including tests that skip `bootstrapPlugins()`)
86
+ // observe a populated registry by default. Idempotent via the swallowed
87
+ // duplicate-name check. Kept local to this module (rather than iterating
88
+ // an array in `defaults/index.ts`) so the registration only references
89
+ // the already-initialized `defaultTokenEstimatePlugin` identifier —
90
+ // avoiding a TDZ crash when tests `mock.module(...)` a dependency of any
91
+ // other default plugin and directly import this file.
92
+ try {
93
+ registerPlugin(defaultTokenEstimatePlugin);
94
+ } catch (err) {
95
+ if (
96
+ err instanceof PluginExecutionError &&
97
+ err.message.includes("already registered")
98
+ ) {
99
+ // already registered — expected when both index.ts and the direct
100
+ // file are imported in the same process
101
+ } else {
102
+ throw err;
103
+ }
104
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Default `toolError` plugin.
3
+ *
4
+ * The plugin's middleware is a passthrough — it calls `next(args)` and returns
5
+ * the result unchanged. The actual nudge-decision logic lives in
6
+ * {@link defaultToolErrorTerminal}, which is wired in as the pipeline's
7
+ * `terminal` argument by the `runPipeline` call site in `agent/loop.ts`. This
8
+ * separation matters: the default plugin is registered before any user plugin
9
+ * (defaults load first via module-side-effect imports / `registerDefaultPlugins`),
10
+ * which puts it at the OUTERMOST position of the onion chain. If the default
11
+ * middleware invoked the decision logic directly without calling `next`, it
12
+ * would shadow every later-registered plugin. Routing through `next(args)`
13
+ * lets user middleware participate normally.
14
+ *
15
+ * The canonical nudge decision: when the current turn produced at least one
16
+ * failed tool result, append a system-notice block to the tool results that
17
+ * coaches the LLM to either retry with corrected parameters (for recoverable
18
+ * errors) or report the failure to the user (for unrecoverable ones). Once
19
+ * the consecutive-error-turn counter exceeds the caller-supplied cap, the
20
+ * nudge is skipped — the error is likely not something the LLM can fix on
21
+ * its own and continuing to nudge only burns tokens.
22
+ *
23
+ * Design doc: `.private/plans/agent-plugin-system.md` (PR 19).
24
+ */
25
+
26
+ import { registerPlugin } from "../registry.js";
27
+ import {
28
+ type Middleware,
29
+ type Plugin,
30
+ PluginExecutionError,
31
+ type ToolErrorArgs,
32
+ type ToolErrorDecision,
33
+ } from "../types.js";
34
+
35
+ /**
36
+ * Canonical nudge text. Kept as a module-level constant so tests and future
37
+ * plugins can match it without duplicating the string.
38
+ */
39
+ export const DEFAULT_TOOL_ERROR_NUDGE_TEXT =
40
+ "<system_notice>One or more tool calls returned an error. If the error looks recoverable (e.g. missing or invalid parameters), fix the parameters and retry. If the error is clearly unrecoverable (e.g. a service is down, a resource does not exist, or a permission is permanently denied), report it to the user.</system_notice>";
41
+
42
+ /**
43
+ * Terminal handler for the `toolError` pipeline. Nudge iff the current turn
44
+ * had an error AND the consecutive-error counter is within the cap. Once the
45
+ * cap is breached the caller should stop appending the nudge (the error is
46
+ * likely unrecoverable and the LLM already had multiple attempts to correct
47
+ * it).
48
+ *
49
+ * Exported so `agent/loop.ts` can pass it as the `terminal` argument to
50
+ * `runPipeline` (ensuring the nudge decision fires even when no plugin is
51
+ * registered — e.g. direct AgentLoop callers that skip `bootstrapPlugins()`)
52
+ * and so tests can verify the decision logic directly without going through
53
+ * the pipeline runner.
54
+ */
55
+ export const defaultToolErrorTerminal = async (
56
+ args: ToolErrorArgs,
57
+ ): Promise<ToolErrorDecision> => {
58
+ if (
59
+ args.hasToolError &&
60
+ args.consecutiveErrorTurns <= args.maxConsecutiveErrorNudges
61
+ ) {
62
+ return {
63
+ action: "nudge",
64
+ nudgeText: DEFAULT_TOOL_ERROR_NUDGE_TEXT,
65
+ };
66
+ }
67
+ return { action: "skip" };
68
+ };
69
+
70
+ /**
71
+ * Default middleware for the `toolError` slot. Passthrough — calls `next(args)`
72
+ * so later-registered user plugins still participate in the onion chain. The
73
+ * actual decision logic lives in {@link defaultToolErrorTerminal}, wired in
74
+ * at the `runPipeline` call site in `agent/loop.ts`.
75
+ *
76
+ * Named explicitly so the pipeline's structured log record carries
77
+ * `"defaultToolErrorMiddleware"` in `chain` instead of an anonymous entry.
78
+ */
79
+ const defaultToolErrorMiddleware: Middleware<ToolErrorArgs, ToolErrorDecision> =
80
+ async function defaultToolErrorMiddleware(args, next) {
81
+ return next(args);
82
+ };
83
+
84
+ /**
85
+ * Plugin registration for the default `toolError` behavior. Registered by
86
+ * `daemon/external-plugins-bootstrap.ts` via a side-effect import so the
87
+ * middleware is available to the pipeline runner from daemon startup.
88
+ */
89
+ export const defaultToolErrorPlugin: Plugin = {
90
+ manifest: {
91
+ name: "default-tool-error",
92
+ version: "1.0.0",
93
+ requires: {
94
+ pluginRuntime: "v1",
95
+ toolErrorApi: "v1",
96
+ },
97
+ provides: {
98
+ toolError: "v1",
99
+ },
100
+ },
101
+ middleware: {
102
+ toolError: defaultToolErrorMiddleware,
103
+ },
104
+ };
105
+
106
+ // Module-load side effect: register this default at import time so
107
+ // downstream consumers (including tests that skip `bootstrapPlugins()`)
108
+ // observe a populated registry by default. Idempotent via the swallowed
109
+ // duplicate-name check. Kept local to this module (rather than iterating
110
+ // an array in `defaults/index.ts`) so the registration only references
111
+ // the already-initialized `defaultToolErrorPlugin` identifier —
112
+ // avoiding a TDZ crash when tests `mock.module(...)` a dependency of any
113
+ // other default plugin and directly import this file.
114
+ try {
115
+ registerPlugin(defaultToolErrorPlugin);
116
+ } catch (err) {
117
+ if (
118
+ err instanceof PluginExecutionError &&
119
+ err.message.includes("already registered")
120
+ ) {
121
+ // already registered — expected when both index.ts and the direct
122
+ // file are imported in the same process
123
+ } else {
124
+ throw err;
125
+ }
126
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Default `toolExecute` plugin — a no-argument passthrough that preserves
3
+ * the behavior `ToolExecutor.execute` had before the pipeline wrapper was
4
+ * introduced.
5
+ *
6
+ * Design
7
+ * ------
8
+ * The public {@link ToolExecutor.execute} method invokes
9
+ * {@link runPipeline} with the terminal bound to an internal
10
+ * `executeInternal` method (the original execute body, refactored to avoid
11
+ * recursion). Because the terminal IS the original behavior, the default
12
+ * plugin's `middleware.toolExecute` is a thin passthrough: it forwards to
13
+ * `next(args)` and returns the downstream result unchanged.
14
+ *
15
+ * This matches the convention set by PR 15 (`default-llm-call.ts`) for
16
+ * `llmCall` — the default plugin makes the pipeline shape explicit without
17
+ * introducing any behavior of its own. When no third-party plugins are
18
+ * registered the chain is `[defaultMiddleware] → terminal`, which composes
19
+ * identically to `[] → terminal`, so the shell-integration tests (which
20
+ * never register the default) stay unchanged-green.
21
+ *
22
+ * Why a dedicated plugin at all?
23
+ * ------------------------------
24
+ * - It signals publicly that `toolExecute` is a supported pipeline slot with
25
+ * a concrete contract.
26
+ * - Registration order determines onion order. If a third-party plugin
27
+ * wraps `toolExecute`, the runtime should boot with the default present
28
+ * (as the innermost passthrough) so the chain visibly contains a
29
+ * canonical terminator regardless of which third parties load.
30
+ */
31
+
32
+ import { registerPlugin } from "../registry.js";
33
+ import {
34
+ type Middleware,
35
+ type Plugin,
36
+ PluginExecutionError,
37
+ type ToolExecuteArgs,
38
+ type ToolExecuteResult,
39
+ } from "../types.js";
40
+
41
+ /**
42
+ * Passthrough middleware — forwards the call to `next`. Named so the
43
+ * pipeline runner's `chain` log entry reads `defaultToolExecute` instead of
44
+ * `anonymous`.
45
+ */
46
+ const defaultToolExecute: Middleware<ToolExecuteArgs, ToolExecuteResult> =
47
+ async function defaultToolExecute(args, next) {
48
+ return next(args);
49
+ };
50
+
51
+ /**
52
+ * The default `toolExecute` plugin. Exported as a module constant so the
53
+ * daemon bootstrap can register it via a side-effect import. Tests may
54
+ * import and register it explicitly via `registerPlugin()` to cover the
55
+ * on-by-default execution path.
56
+ */
57
+ export const defaultToolExecutePlugin: Plugin = {
58
+ manifest: {
59
+ name: "default-tool-execute",
60
+ version: "1.0.0",
61
+ provides: { toolExecuteApi: "v1" },
62
+ requires: { pluginRuntime: "v1", toolExecuteApi: "v1" },
63
+ },
64
+ middleware: {
65
+ toolExecute: defaultToolExecute,
66
+ },
67
+ };
68
+
69
+ // Module-load side effect: register this default at import time so
70
+ // downstream consumers (including tests that skip `bootstrapPlugins()`)
71
+ // observe a populated registry by default. Idempotent via the swallowed
72
+ // duplicate-name check. Kept local to this module (rather than iterating
73
+ // an array in `defaults/index.ts`) so the registration only references
74
+ // the already-initialized `defaultToolExecutePlugin` identifier —
75
+ // avoiding a TDZ crash when tests `mock.module(...)` a dependency of any
76
+ // other default plugin and directly import this file.
77
+ try {
78
+ registerPlugin(defaultToolExecutePlugin);
79
+ } catch (err) {
80
+ if (
81
+ err instanceof PluginExecutionError &&
82
+ err.message.includes("already registered")
83
+ ) {
84
+ // already registered — expected when both index.ts and the direct
85
+ // file are imported in the same process
86
+ } else {
87
+ throw err;
88
+ }
89
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Default `toolResultTruncate` plugin.
3
+ *
4
+ * The plugin's middleware is a passthrough — it calls `next(args)` and returns
5
+ * the result unchanged. The actual truncation lives in
6
+ * {@link defaultToolResultTruncateTerminal}, which is wired in as the
7
+ * pipeline's `terminal` argument by the `runPipeline` call site in
8
+ * `agent/loop.ts`. This separation matters: the default plugin is registered
9
+ * before any user plugin (defaults load first in `bootstrapPlugins()`), which
10
+ * puts it at the OUTERMOST position of the onion chain. If the default
11
+ * middleware were to invoke the terminal directly without calling `next`, it
12
+ * would shadow every later-registered plugin (including hot-reloaded ones).
13
+ * Routing through `next(args)` lets user middleware participate normally.
14
+ *
15
+ * Design doc: `.private/plans/agent-plugin-system.md` (PR 17).
16
+ */
17
+
18
+ import { truncateToolResultText } from "../../context/tool-result-truncation.js";
19
+ import { registerPlugin } from "../registry.js";
20
+ import {
21
+ type Middleware,
22
+ type Plugin,
23
+ PluginExecutionError,
24
+ type ToolResultTruncateArgs,
25
+ type ToolResultTruncateResult,
26
+ } from "../types.js";
27
+
28
+ /**
29
+ * Terminal handler for the `toolResultTruncate` pipeline. Exported so tests
30
+ * can verify default behavior directly without going through `runPipeline`,
31
+ * and so `agent/loop.ts` can pass it as the `terminal` argument to
32
+ * `runPipeline`.
33
+ */
34
+ export function defaultToolResultTruncateTerminal(
35
+ args: ToolResultTruncateArgs,
36
+ ): ToolResultTruncateResult {
37
+ const truncated = truncateToolResultText(args.content, args.maxChars);
38
+ return {
39
+ content: truncated,
40
+ truncated: truncated !== args.content,
41
+ };
42
+ }
43
+
44
+ const passthrough: Middleware<
45
+ ToolResultTruncateArgs,
46
+ ToolResultTruncateResult
47
+ > = async (args, next) => next(args);
48
+
49
+ /**
50
+ * Plugin descriptor for the default tool-result truncation middleware.
51
+ * Registered by `plugins/defaults/index.ts` so the registry always has at
52
+ * least one middleware for the `toolResultTruncate` pipeline.
53
+ */
54
+ export const defaultToolResultTruncatePlugin: Plugin = {
55
+ manifest: {
56
+ name: "default-tool-result-truncate",
57
+ version: "1.0.0",
58
+ requires: {
59
+ pluginRuntime: "v1",
60
+ toolResultTruncateApi: "v1",
61
+ },
62
+ },
63
+ middleware: {
64
+ toolResultTruncate: passthrough,
65
+ },
66
+ };
67
+
68
+ // Module-load side effect: register this default at import time so
69
+ // downstream consumers (including tests that skip `bootstrapPlugins()`)
70
+ // observe a populated registry by default. Idempotent via the swallowed
71
+ // duplicate-name check. Kept local to this module (rather than iterating
72
+ // an array in `defaults/index.ts`) so the registration only references
73
+ // the already-initialized `defaultToolResultTruncatePlugin` identifier —
74
+ // avoiding a TDZ crash when tests `mock.module(...)` a dependency of any
75
+ // other default plugin and directly import this file.
76
+ try {
77
+ registerPlugin(defaultToolResultTruncatePlugin);
78
+ } catch (err) {
79
+ if (
80
+ err instanceof PluginExecutionError &&
81
+ err.message.includes("already registered")
82
+ ) {
83
+ // already registered — expected when both index.ts and the direct
84
+ // file are imported in the same process
85
+ } else {
86
+ throw err;
87
+ }
88
+ }