@vellumai/assistant 0.7.3 → 0.8.1

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 (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -41,6 +41,49 @@ mock.module("../util/logger.js", () => ({
41
41
  }),
42
42
  }));
43
43
 
44
+ // ── Mock oauth-store so handleOAuthConnectStart can run without a seeded DB ──
45
+ type MockProviderRow = {
46
+ authorizeUrl?: string;
47
+ requiresClientSecret?: boolean;
48
+ [key: string]: unknown;
49
+ };
50
+
51
+ const DEFAULT_PROVIDER: MockProviderRow = {
52
+ authorizeUrl: "https://accounts.google.com/o/oauth2/auth",
53
+ requiresClientSecret: false,
54
+ };
55
+
56
+ let mockGetProvider: (service: string) => MockProviderRow | undefined = () =>
57
+ DEFAULT_PROVIDER;
58
+ let mockGetAppByProviderAndClientId: (
59
+ service: string,
60
+ clientId: string,
61
+ ) => Record<string, unknown> | undefined = (_service, clientId) => ({
62
+ id: "test-app-id",
63
+ provider: "google",
64
+ clientId,
65
+ });
66
+ let mockGetMostRecentAppByProvider: (
67
+ service: string,
68
+ ) => Record<string, unknown> | undefined = () => ({
69
+ id: "test-app-id",
70
+ provider: "google",
71
+ clientId: "default-client-id",
72
+ });
73
+ let mockGetAppClientSecret: (
74
+ row: Record<string, unknown>,
75
+ ) => Promise<string | undefined> = async () => undefined;
76
+
77
+ mock.module("../oauth/oauth-store.js", () => ({
78
+ getProvider: (service: string) => mockGetProvider(service),
79
+ getAppByProviderAndClientId: (service: string, clientId: string) =>
80
+ mockGetAppByProviderAndClientId(service, clientId),
81
+ getMostRecentAppByProvider: (service: string) =>
82
+ mockGetMostRecentAppByProvider(service),
83
+ getAppClientSecret: (row: Record<string, unknown>) =>
84
+ mockGetAppClientSecret(row),
85
+ }));
86
+
44
87
  // NOTE: Do NOT mock oauth-connect-state — use the real module so we can
45
88
  // verify state transitions via getOAuthConnectState.
46
89
 
@@ -65,6 +108,23 @@ function findRoute(operationId: string) {
65
108
  // ── Tests ──────────────────────────────────────────────────────────────────────
66
109
 
67
110
  describe("oauth-connect-routes", () => {
111
+ beforeEach(() => {
112
+ // Reset oauth-store mocks to permissive defaults so every test starts
113
+ // from a clean baseline regardless of what the previous test set.
114
+ mockGetProvider = () => DEFAULT_PROVIDER;
115
+ mockGetAppByProviderAndClientId = (_service, clientId) => ({
116
+ id: "test-app-id",
117
+ provider: "google",
118
+ clientId,
119
+ });
120
+ mockGetMostRecentAppByProvider = () => ({
121
+ id: "test-app-id",
122
+ provider: "google",
123
+ clientId: "default-client-id",
124
+ });
125
+ mockGetAppClientSecret = async () => undefined;
126
+ });
127
+
68
128
  describe("POST internal/oauth/connect/start", () => {
69
129
  beforeEach(() => {
70
130
  capturedOnDeferredComplete = undefined;
@@ -109,17 +169,6 @@ describe("oauth-connect-routes", () => {
109
169
  ).rejects.toBeInstanceOf(BadRequestError);
110
170
  });
111
171
 
112
- test("missing clientId throws BadRequestError", async () => {
113
- await expect(
114
- findRoute("internal_oauth_connect_start").handler({
115
- body: {
116
- service: "google",
117
- callbackTransport: "gateway",
118
- },
119
- }),
120
- ).rejects.toBeInstanceOf(BadRequestError);
121
- });
122
-
123
172
  test("missing service throws BadRequestError", async () => {
124
173
  await expect(
125
174
  findRoute("internal_oauth_connect_start").handler({
@@ -183,6 +232,120 @@ describe("oauth-connect-routes", () => {
183
232
  }),
184
233
  ).rejects.toBeInstanceOf(InternalError);
185
234
  });
235
+
236
+ test("unknown provider throws NotFoundError", async () => {
237
+ mockGetProvider = () => undefined;
238
+ await expect(
239
+ findRoute("internal_oauth_connect_start").handler({
240
+ body: {
241
+ service: "made-up-service",
242
+ clientId: "my-client-id",
243
+ callbackTransport: "gateway",
244
+ },
245
+ }),
246
+ ).rejects.toBeInstanceOf(NotFoundError);
247
+ });
248
+
249
+ test("manual-token provider rejected even when clientId is explicitly supplied", async () => {
250
+ // Codex/Devin finding on PR #30251: the manual-token check used to live
251
+ // inside `if (!clientId)`, so callers passing `--client-id` for a
252
+ // manual-token provider (e.g. slack_channel, telegram) bypassed it.
253
+ mockGetProvider = () => ({
254
+ authorizeUrl: "urn:manual-token",
255
+ requiresClientSecret: false,
256
+ });
257
+ await expect(
258
+ findRoute("internal_oauth_connect_start").handler({
259
+ body: {
260
+ service: "slack_channel",
261
+ clientId: "any-client-id",
262
+ callbackTransport: "gateway",
263
+ },
264
+ }),
265
+ ).rejects.toBeInstanceOf(BadRequestError);
266
+ });
267
+
268
+ test("manual-token provider rejected when no clientId is supplied", async () => {
269
+ mockGetProvider = () => ({
270
+ authorizeUrl: "urn:manual-token",
271
+ requiresClientSecret: false,
272
+ });
273
+ await expect(
274
+ findRoute("internal_oauth_connect_start").handler({
275
+ body: {
276
+ service: "slack_channel",
277
+ callbackTransport: "gateway",
278
+ },
279
+ }),
280
+ ).rejects.toBeInstanceOf(BadRequestError);
281
+ });
282
+
283
+ test("explicit clientId with no registered app throws NotFoundError", async () => {
284
+ // Devin finding on PR #30251: the explicit-clientId branch used to
285
+ // silently continue when getAppByProviderAndClientId returned null,
286
+ // letting orchestrateOAuthConnect fail later with a less helpful error.
287
+ mockGetAppByProviderAndClientId = () => undefined;
288
+ await expect(
289
+ findRoute("internal_oauth_connect_start").handler({
290
+ body: {
291
+ service: "google",
292
+ clientId: "unregistered-client-id",
293
+ callbackTransport: "gateway",
294
+ },
295
+ }),
296
+ ).rejects.toBeInstanceOf(NotFoundError);
297
+ });
298
+
299
+ test("no clientId and no registered app throws BadRequestError", async () => {
300
+ mockGetMostRecentAppByProvider = () => undefined;
301
+ await expect(
302
+ findRoute("internal_oauth_connect_start").handler({
303
+ body: {
304
+ service: "google",
305
+ callbackTransport: "gateway",
306
+ },
307
+ }),
308
+ ).rejects.toBeInstanceOf(BadRequestError);
309
+ });
310
+
311
+ test("missing client_secret when provider requiresClientSecret throws BadRequestError", async () => {
312
+ // Devin finding on PR #30251: requiresClientSecret was only checked
313
+ // inside the `!clientId` branch. Hoisting it ensures explicit-clientId
314
+ // callers also fail fast with an actionable error.
315
+ mockGetProvider = () => ({
316
+ authorizeUrl: "https://accounts.example.com/o/oauth2/auth",
317
+ requiresClientSecret: true,
318
+ });
319
+ mockGetAppClientSecret = async () => undefined;
320
+ await expect(
321
+ findRoute("internal_oauth_connect_start").handler({
322
+ body: {
323
+ service: "github",
324
+ clientId: "explicit-client-id",
325
+ callbackTransport: "gateway",
326
+ },
327
+ }),
328
+ ).rejects.toBeInstanceOf(BadRequestError);
329
+ });
330
+
331
+ test("explicit clientId + stored secret succeeds without caller-supplied secret", async () => {
332
+ mockGetProvider = () => ({
333
+ authorizeUrl: "https://accounts.example.com/o/oauth2/auth",
334
+ requiresClientSecret: true,
335
+ });
336
+ mockGetAppClientSecret = async () => "stored-secret-from-keyring";
337
+ const result = await findRoute("internal_oauth_connect_start").handler({
338
+ body: {
339
+ service: "github",
340
+ clientId: "explicit-client-id",
341
+ callbackTransport: "gateway",
342
+ },
343
+ });
344
+ expect(result).toMatchObject({
345
+ auth_url: "https://accounts.google.com/o/oauth2/auth?client_id=test",
346
+ state: "test-state-uuid-abc123",
347
+ });
348
+ });
186
349
  });
187
350
 
188
351
  describe("GET internal/oauth/connect/status/:state", () => {
@@ -245,22 +245,26 @@ describe("GET /v1/oauth/providers/:providerKey", () => {
245
245
  );
246
246
 
247
247
  expect(status).toBe(200);
248
+ // The GET-by-key endpoint uses `serializeProviderFull`, which intentionally
249
+ // emits camelCase keys (see provider-serializer.ts). The list endpoint
250
+ // uses `serializeProviderSummary` and emits snake_case — these are
251
+ // separate wire formats by design.
248
252
  const { provider } = body as {
249
253
  provider: {
250
- provider_key: string;
251
- display_name: string | null;
254
+ providerKey: string;
255
+ displayName: string | null;
252
256
  description: string | null;
253
- dashboard_url: string | null;
254
- client_id_placeholder: string | null;
255
- requires_client_secret: boolean;
256
- supports_managed_mode: boolean;
257
+ dashboardUrl: string | null;
258
+ clientIdPlaceholder: string | null;
259
+ requiresClientSecret: boolean;
260
+ supportsManagedMode: boolean;
257
261
  };
258
262
  };
259
263
 
260
- expect(provider.provider_key).toBe("google");
261
- expect(provider.display_name).toBe("Google");
262
- expect(provider.supports_managed_mode).toBe(true);
263
- expect(provider.requires_client_secret).toBe(true);
264
+ expect(provider.providerKey).toBe("google");
265
+ expect(provider.displayName).toBe("Google");
266
+ expect(provider.supportsManagedMode).toBe(true);
267
+ expect(provider.requiresClientSecret).toBe(true);
264
268
  });
265
269
 
266
270
  test("returns 404 for unknown provider", async () => {
@@ -13,8 +13,9 @@ import { describe, expect, test } from "bun:test";
13
13
  *
14
14
  * These guards fail CI if:
15
15
  * 1. The Responses provider file contains `chat.completions.create(` calls.
16
- * 2. The provider registry wires `openai` to anything other than
17
- * `OpenAIResponsesProvider`.
16
+ * 2. The adapter factory wires `openai` to anything other than
17
+ * `OpenAIResponsesProvider`. (Catalog-driven adapter construction lives
18
+ * in `inference/adapter-factory.ts`; `registry.ts` only orchestrates it.)
18
19
  * 3. A new file appears in `providers/openai/` that introduces
19
20
  * `chat.completions.create(` calls.
20
21
  *
@@ -40,6 +41,11 @@ import { describe, expect, test } from "bun:test";
40
41
 
41
42
  const PROVIDERS_DIR = join(import.meta.dir, "..", "providers");
42
43
  const OPENAI_PROVIDERS_DIR = join(PROVIDERS_DIR, "openai");
44
+ const ADAPTER_FACTORY_PATH = join(
45
+ PROVIDERS_DIR,
46
+ "inference",
47
+ "adapter-factory.ts",
48
+ );
43
49
 
44
50
  describe("OpenAI Responses API cutover guard", () => {
45
51
  test("responses-provider.ts does not contain chat.completions.create() calls", () => {
@@ -60,32 +66,34 @@ describe("OpenAI Responses API cutover guard", () => {
60
66
  ).toBe(false);
61
67
  });
62
68
 
63
- test("registry.ts wires the 'openai' provider to OpenAIResponsesProvider", () => {
64
- const source = readFileSync(join(PROVIDERS_DIR, "registry.ts"), "utf-8");
69
+ test("adapter-factory.ts wires the 'openai' provider to OpenAIResponsesProvider", () => {
70
+ // Catalog-driven adapter construction lives in `adapter-factory.ts`.
71
+ // `registry.ts` only orchestrates and wraps the adapter; the only place
72
+ // that names a provider class for the "openai" id is the factory table.
73
+ const source = readFileSync(ADAPTER_FACTORY_PATH, "utf-8");
65
74
 
66
- // The registry should import OpenAIResponsesProvider
75
+ // The factory must import OpenAIResponsesProvider.
67
76
  expect(
68
77
  source.includes("OpenAIResponsesProvider"),
69
- "registry.ts must import OpenAIResponsesProvider for the openai provider.",
78
+ "adapter-factory.ts must import OpenAIResponsesProvider for the openai provider.",
70
79
  ).toBe(true);
71
80
 
72
- // The registry should instantiate OpenAIResponsesProvider for the "openai" key.
73
- // Look for `new OpenAIResponsesProvider(` near the openai registration block.
81
+ // The factory must instantiate OpenAIResponsesProvider.
74
82
  const hasResponsesInstantiation = source.includes(
75
83
  "new OpenAIResponsesProvider(",
76
84
  );
77
85
  expect(
78
86
  hasResponsesInstantiation,
79
87
  [
80
- "registry.ts must instantiate OpenAIResponsesProvider for the 'openai' provider.",
88
+ "adapter-factory.ts must instantiate OpenAIResponsesProvider for the 'openai' provider.",
81
89
  "OpenAI inference uses the Responses API, not chat completions.",
82
90
  ].join("\n"),
83
91
  ).toBe(true);
84
92
 
85
- // The registry should NOT instantiate OpenAIChatCompletionsProvider or
93
+ // The factory must NOT instantiate OpenAIChatCompletionsProvider or
86
94
  // OpenAIProvider (the backward-compatible alias) for the "openai" key.
87
95
  // Chat-completions classes may appear in imports but should not be
88
- // instantiated in the openai registration block.
96
+ // instantiated in the openai factory entry.
89
97
  const chatCompletionsInstantiations = [
90
98
  ...source.matchAll(/new\s+OpenAIChatCompletionsProvider\s*\(/g),
91
99
  ...source.matchAll(/new\s+OpenAIProvider\s*\(/g),
@@ -93,10 +101,23 @@ describe("OpenAI Responses API cutover guard", () => {
93
101
  expect(
94
102
  chatCompletionsInstantiations.length,
95
103
  [
96
- "registry.ts must NOT instantiate OpenAIChatCompletionsProvider or",
104
+ "adapter-factory.ts must NOT instantiate OpenAIChatCompletionsProvider or",
97
105
  "OpenAIProvider (legacy alias). Use OpenAIResponsesProvider for openai.",
98
106
  ].join("\n"),
99
107
  ).toBe(0);
108
+
109
+ // The factory's "openai" entry must specifically map to OpenAIResponsesProvider.
110
+ // Match `openai:` followed (within ~400 chars) by `new OpenAIResponsesProvider(`
111
+ // to confirm wiring at the entry level, not just an unrelated reference.
112
+ const openaiEntryWiring =
113
+ /openai\s*:\s*\([^)]*\)\s*=>\s*[\s\S]{0,400}?new\s+OpenAIResponsesProvider\s*\(/;
114
+ expect(
115
+ openaiEntryWiring.test(source),
116
+ [
117
+ "adapter-factory.ts ADAPTER_FACTORIES['openai'] entry must construct",
118
+ "OpenAIResponsesProvider. If the factory shape changed, update this guard.",
119
+ ].join("\n"),
120
+ ).toBe(true);
100
121
  });
101
122
 
102
123
  test("no files in providers/openai/ introduce chat.completions.create() calls", () => {
@@ -677,6 +677,23 @@ describe("OpenAIResponsesProvider", () => {
677
677
  expect(lastStreamParams!.text).toEqual({ verbosity: "high" });
678
678
  });
679
679
 
680
+ test("verbosity is forwarded for GPT-5 fine-tune IDs", async () => {
681
+ const ftProvider = new OpenAIResponsesProvider(
682
+ "sk-test",
683
+ "ft:gpt-5.2:acme::abc123",
684
+ );
685
+ fakeStreamEvents = [textDeltaEvent("OK"), completedEvent(10, 2)];
686
+
687
+ await ftProvider.sendMessage(
688
+ [{ role: "user", content: [{ type: "text", text: "Hi" }] }],
689
+ undefined,
690
+ undefined,
691
+ { config: { verbosity: "low" } },
692
+ );
693
+
694
+ expect(lastStreamParams!.text).toEqual({ verbosity: "low" });
695
+ });
696
+
680
697
  // -----------------------------------------------------------------------
681
698
  // Model override
682
699
  // -----------------------------------------------------------------------
@@ -70,15 +70,43 @@ const fakeCtx: DaemonContext = {
70
70
  assistantVersion: "9.9.9-test",
71
71
  };
72
72
 
73
+ /**
74
+ * Test helper. Accepts the new `hooks` bag and ALSO legacy top-level
75
+ * `init` / `onShutdown` for ergonomics — the helper merges them into a
76
+ * single `hooks` field that matches the runtime Plugin shape. This keeps
77
+ * the test call sites compact without leaking the old contract.
78
+ */
73
79
  function buildPlugin(
74
80
  name: string,
75
- extras: Partial<Omit<Plugin, "manifest">> = {},
81
+ extras: Partial<Omit<Plugin, "manifest" | "hooks">> & {
82
+ hooks?: Plugin["hooks"];
83
+ init?: (ctx: PluginInitContext) => Promise<void>;
84
+ onShutdown?: () => Promise<void>;
85
+ } = {},
76
86
  options: {
77
87
  requires?: Record<string, string>;
78
88
  requiresCredential?: string[];
79
89
  requiresFlag?: string[];
80
90
  } = {},
81
91
  ): Plugin {
92
+ const {
93
+ init: legacyInit,
94
+ onShutdown: legacyOnShutdown,
95
+ hooks: explicitHooks,
96
+ ...rest
97
+ } = extras;
98
+ const mergedHooks: Plugin["hooks"] | undefined =
99
+ legacyInit !== undefined ||
100
+ legacyOnShutdown !== undefined ||
101
+ explicitHooks !== undefined
102
+ ? {
103
+ ...(explicitHooks ?? {}),
104
+ ...(legacyInit !== undefined ? { init: legacyInit } : {}),
105
+ ...(legacyOnShutdown !== undefined
106
+ ? { shutdown: legacyOnShutdown }
107
+ : {}),
108
+ }
109
+ : undefined;
82
110
  return {
83
111
  manifest: {
84
112
  name,
@@ -89,7 +117,8 @@ function buildPlugin(
89
117
  : {}),
90
118
  ...(options.requiresFlag ? { requiresFlag: options.requiresFlag } : {}),
91
119
  },
92
- ...extras,
120
+ ...rest,
121
+ ...(mergedHooks ? { hooks: mergedHooks } : {}),
93
122
  };
94
123
  }
95
124
 
@@ -53,7 +53,7 @@ import {
53
53
  registerPlugin,
54
54
  resetPluginRegistryForTests,
55
55
  } from "../plugins/registry.js";
56
- import type { Plugin } from "../plugins/types.js";
56
+ import type { Plugin, PluginInitContext } from "../plugins/types.js";
57
57
  import {
58
58
  matchSkillRoute,
59
59
  resetSkillRoutesForTests,
@@ -76,17 +76,45 @@ const fakeCtx: DaemonContext = {
76
76
  };
77
77
 
78
78
  /** Build a minimal valid plugin with optional route contributions. */
79
+ /**
80
+ * Test helper. Accepts the new `hooks` bag and ALSO legacy top-level
81
+ * `init` / `onShutdown` for ergonomics — the helper merges them into a
82
+ * single `hooks` field that matches the runtime Plugin shape.
83
+ */
79
84
  function buildPlugin(
80
85
  name: string,
81
- extras: Partial<Omit<Plugin, "manifest">> = {},
86
+ extras: Partial<Omit<Plugin, "manifest" | "hooks">> & {
87
+ hooks?: Plugin["hooks"];
88
+ init?: (ctx: PluginInitContext) => Promise<void>;
89
+ onShutdown?: () => Promise<void>;
90
+ } = {},
82
91
  ): Plugin {
92
+ const {
93
+ init: legacyInit,
94
+ onShutdown: legacyOnShutdown,
95
+ hooks: explicitHooks,
96
+ ...rest
97
+ } = extras;
98
+ const mergedHooks: Plugin["hooks"] | undefined =
99
+ legacyInit !== undefined ||
100
+ legacyOnShutdown !== undefined ||
101
+ explicitHooks !== undefined
102
+ ? {
103
+ ...(explicitHooks ?? {}),
104
+ ...(legacyInit !== undefined ? { init: legacyInit } : {}),
105
+ ...(legacyOnShutdown !== undefined
106
+ ? { shutdown: legacyOnShutdown }
107
+ : {}),
108
+ }
109
+ : undefined;
83
110
  return {
84
111
  manifest: {
85
112
  name,
86
113
  version: "0.0.1",
87
114
  requires: { pluginRuntime: "v1" },
88
115
  },
89
- ...extras,
116
+ ...rest,
117
+ ...(mergedHooks ? { hooks: mergedHooks } : {}),
90
118
  };
91
119
  }
92
120
 
@@ -48,7 +48,7 @@ import {
48
48
  registerPlugin,
49
49
  resetPluginRegistryForTests,
50
50
  } from "../plugins/registry.js";
51
- import type { Plugin } from "../plugins/types.js";
51
+ import type { Plugin, PluginInitContext } from "../plugins/types.js";
52
52
  import type { ToolDefinition } from "../providers/types.js";
53
53
  import {
54
54
  __clearRegistryForTesting,
@@ -99,17 +99,45 @@ function makeFakeTool(name: string, extras: Partial<Tool> = {}): Tool {
99
99
  };
100
100
  }
101
101
 
102
+ /**
103
+ * Test helper. Accepts the new `hooks` bag and ALSO legacy top-level
104
+ * `init` / `onShutdown` for ergonomics — the helper merges them into a
105
+ * single `hooks` field that matches the runtime Plugin shape.
106
+ */
102
107
  function buildPlugin(
103
108
  name: string,
104
- extras: Partial<Omit<Plugin, "manifest">> = {},
109
+ extras: Partial<Omit<Plugin, "manifest" | "hooks">> & {
110
+ hooks?: Plugin["hooks"];
111
+ init?: (ctx: PluginInitContext) => Promise<void>;
112
+ onShutdown?: () => Promise<void>;
113
+ } = {},
105
114
  ): Plugin {
115
+ const {
116
+ init: legacyInit,
117
+ onShutdown: legacyOnShutdown,
118
+ hooks: explicitHooks,
119
+ ...rest
120
+ } = extras;
121
+ const mergedHooks: Plugin["hooks"] | undefined =
122
+ legacyInit !== undefined ||
123
+ legacyOnShutdown !== undefined ||
124
+ explicitHooks !== undefined
125
+ ? {
126
+ ...(explicitHooks ?? {}),
127
+ ...(legacyInit !== undefined ? { init: legacyInit } : {}),
128
+ ...(legacyOnShutdown !== undefined
129
+ ? { shutdown: legacyOnShutdown }
130
+ : {}),
131
+ }
132
+ : undefined;
106
133
  return {
107
134
  manifest: {
108
135
  name,
109
136
  version: "0.0.1",
110
137
  requires: { pluginRuntime: "v1" },
111
138
  },
112
- ...extras,
139
+ ...rest,
140
+ ...(mergedHooks ? { hooks: mergedHooks } : {}),
113
141
  };
114
142
  }
115
143
 
@@ -228,17 +228,19 @@ describe("plugin core types", () => {
228
228
 
229
229
  const plugin = {
230
230
  manifest,
231
- async init(ctx: PluginInitContext) {
232
- // Touch every field so refactors that rename any of them break here.
233
- void ctx.config;
234
- void ctx.credentials;
235
- void ctx.logger;
236
- void ctx.pluginStorageDir;
237
- void ctx.assistantVersion;
238
- void ctx.apiVersions;
239
- },
240
- async onShutdown() {
241
- // no-op
231
+ hooks: {
232
+ async init(ctx: PluginInitContext) {
233
+ // Touch every field so refactors that rename any of them break here.
234
+ void ctx.config;
235
+ void ctx.credentials;
236
+ void ctx.logger;
237
+ void ctx.pluginStorageDir;
238
+ void ctx.assistantVersion;
239
+ void ctx.apiVersions;
240
+ },
241
+ async shutdown() {
242
+ // no-op
243
+ },
242
244
  },
243
245
  tools: [sampleTool],
244
246
  routes: [
@@ -30,6 +30,14 @@ mock.module("../memory/conversation-disk-view.js", () => ({
30
30
  updateMetaFile: () => {},
31
31
  }));
32
32
 
33
+ const broadcastMessages: unknown[] = [];
34
+
35
+ mock.module("../runtime/assistant-event-hub.js", () => ({
36
+ broadcastMessage: (msg: unknown) => {
37
+ broadcastMessages.push(msg);
38
+ },
39
+ }));
40
+
33
41
  mock.module("../runtime/confirmation-request-guardian-bridge.js", () => ({
34
42
  bridgeConfirmationRequestToGuardian: () => {},
35
43
  }));
@@ -240,6 +248,7 @@ describe("processMessageInBackground Slack option propagation", () => {
240
248
  beforeEach(() => {
241
249
  activeConversation = makeConversation();
242
250
  mergeConversationOptionsMock.mockClear();
251
+ broadcastMessages.length = 0;
243
252
  });
244
253
 
245
254
  test("passes Slack inbound metadata to persistence and exposes the runtime notice during the loop", async () => {
@@ -309,6 +318,43 @@ describe("processMessageInBackground Slack option propagation", () => {
309
318
  expect(activeConversation.__clientSenders).toHaveLength(2);
310
319
  });
311
320
 
321
+ test("observes live agent events without replacing the broadcast emitter", async () => {
322
+ const observedMessages: unknown[] = [];
323
+
324
+ const processing = processMessage(
325
+ "conv-background-slack",
326
+ "Reply from Slack",
327
+ undefined,
328
+ {
329
+ onEvent: (msg) => {
330
+ observedMessages.push(msg);
331
+ },
332
+ },
333
+ "slack",
334
+ "slack",
335
+ );
336
+
337
+ await waitForRunAgentLoopCall();
338
+
339
+ const loopOnEvent = activeConversation.runAgentLoop.mock.calls[0][2] as
340
+ | ((msg: unknown) => void)
341
+ | undefined;
342
+ const delta = {
343
+ type: "assistant_text_delta",
344
+ text: "Working on it.",
345
+ conversationId: "conv-background-slack",
346
+ };
347
+ loopOnEvent?.(delta);
348
+
349
+ expect(broadcastMessages).toEqual([delta]);
350
+ expect(observedMessages).toEqual([delta]);
351
+
352
+ activeConversation.__loopDeferred.resolve();
353
+ await expect(processing).resolves.toEqual({
354
+ messageId: "persisted-user-message-id",
355
+ });
356
+ });
357
+
312
358
  test("leaves non-Slack background persistence metadata absent", async () => {
313
359
  await processMessageInBackground(
314
360
  "conv-background-slack",
@@ -0,0 +1,43 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { ProfileEntry } from "../config/schemas/llm.js";
4
+
5
+ describe("ProfileEntry status field", () => {
6
+ test("parses a profile with status: disabled", () => {
7
+ const result = ProfileEntry.safeParse({
8
+ status: "disabled",
9
+ });
10
+ expect(result.success).toBe(true);
11
+ if (result.success) {
12
+ expect(result.data.status).toBe("disabled");
13
+ }
14
+ });
15
+
16
+ test("parses a profile without status — status is undefined (treated as active)", () => {
17
+ const result = ProfileEntry.safeParse({
18
+ provider: "anthropic",
19
+ model: "claude-opus-4-7",
20
+ });
21
+ expect(result.success).toBe(true);
22
+ if (result.success) {
23
+ expect(result.data.status).toBeUndefined();
24
+ }
25
+ });
26
+
27
+ test("parses a profile with status: active", () => {
28
+ const result = ProfileEntry.safeParse({
29
+ status: "active",
30
+ });
31
+ expect(result.success).toBe(true);
32
+ if (result.success) {
33
+ expect(result.data.status).toBe("active");
34
+ }
35
+ });
36
+
37
+ test("rejects an invalid status value", () => {
38
+ const result = ProfileEntry.safeParse({
39
+ status: "hidden",
40
+ });
41
+ expect(result.success).toBe(false);
42
+ });
43
+ });