@vellumai/assistant 0.8.0 → 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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Home-feed side effect for the notification pipeline.
3
+ *
4
+ * Writes a `FeedItem` into the home activity feed when a notification
5
+ * signal originates from a non-interactive (background or scheduled)
6
+ * conversation, or carries the `isAsyncBackground` attention hint.
7
+ *
8
+ * Producer flows like the scheduler, watchers, and background activity
9
+ * jobs already emit through `emitNotificationSignal()` — this helper
10
+ * mirrors the high-signal subset of that traffic into the home feed so
11
+ * the macOS Home page surfaces them alongside other activity.
12
+ */
13
+ import {
14
+ type FeedItem,
15
+ feedItemSchema,
16
+ type FeedItemUrgency,
17
+ } from "../home/feed-types.js";
18
+ import { appendFeedItem } from "../home/feed-writer.js";
19
+ import { getConversation } from "../memory/conversation-crud.js";
20
+ import { isBackgroundConversationType } from "../memory/conversation-types.js";
21
+ import { getLogger } from "../util/logger.js";
22
+ import type { NotificationSignal } from "./signal.js";
23
+ import type {
24
+ NotificationDecision,
25
+ NotificationDeliveryResult,
26
+ } from "./types.js";
27
+
28
+ const log = getLogger("home-feed-side-effect");
29
+
30
+ const FEED_ITEM_URGENCIES: ReadonlySet<string> = new Set<FeedItemUrgency>([
31
+ "low",
32
+ "medium",
33
+ "high",
34
+ "critical",
35
+ ]);
36
+
37
+ /**
38
+ * Append a `FeedItem` for the given notification signal when the
39
+ * filter criteria pass.
40
+ *
41
+ * Returns the persisted `FeedItem`, or `null` if the signal does not
42
+ * qualify for home-feed mirroring (non-background origin AND no
43
+ * `isAsyncBackground` hint) or if schema validation fails.
44
+ */
45
+ export async function writeHomeFeedItemForSignal(
46
+ signal: NotificationSignal,
47
+ decision: NotificationDecision,
48
+ deliveryResults: NotificationDeliveryResult[],
49
+ ): Promise<FeedItem | null> {
50
+ if (!shouldMirrorToHomeFeed(signal)) return null;
51
+
52
+ const renderedCopy = decision.renderedCopy.vellum;
53
+ const payloadTitle = readPayloadString(signal.contextPayload, "title");
54
+ const payloadBody = readPayloadString(signal.contextPayload, "body");
55
+
56
+ const conversationId = deliveryResults.find(
57
+ (r) => r.channel === "vellum",
58
+ )?.conversationId;
59
+ const urgency = FEED_ITEM_URGENCIES.has(signal.attentionHints.urgency)
60
+ ? (signal.attentionHints.urgency as FeedItemUrgency)
61
+ : undefined;
62
+ const now = new Date().toISOString();
63
+
64
+ const item: FeedItem = {
65
+ id: `notif:${signal.signalId}`,
66
+ type: "notification",
67
+ priority: 50,
68
+ title: renderedCopy?.title ?? payloadTitle ?? signal.sourceEventName,
69
+ summary: renderedCopy?.body ?? payloadBody ?? signal.sourceEventName,
70
+ timestamp: now,
71
+ createdAt: now,
72
+ status: "new",
73
+ ...(urgency ? { urgency } : {}),
74
+ ...(conversationId ? { conversationId } : {}),
75
+ };
76
+
77
+ try {
78
+ feedItemSchema.parse(item);
79
+ } catch (err) {
80
+ log.warn(
81
+ { err, signalId: signal.signalId },
82
+ "FeedItem failed schema validation; skipping home-feed write",
83
+ );
84
+ return null;
85
+ }
86
+
87
+ await appendFeedItem(item);
88
+ return item;
89
+ }
90
+
91
+ /**
92
+ * `sourceContextId` is best-effort — it may not be a conversation id
93
+ * (e.g. scheduler job id, watcher event id), so a lookup failure
94
+ * falls through to "not a background conversation" rather than throwing.
95
+ */
96
+ function shouldMirrorToHomeFeed(signal: NotificationSignal): boolean {
97
+ if (signal.attentionHints.isAsyncBackground) return true;
98
+ if (!signal.sourceContextId) return false;
99
+ try {
100
+ const row = getConversation(signal.sourceContextId);
101
+ return isBackgroundConversationType(row?.conversationType);
102
+ } catch {
103
+ return false;
104
+ }
105
+ }
106
+
107
+ function readPayloadString(payload: unknown, key: string): string | undefined {
108
+ if (!payload || typeof payload !== "object") return undefined;
109
+ const value = (payload as Record<string, unknown>)[key];
110
+ return typeof value === "string" ? value : undefined;
111
+ }
@@ -88,6 +88,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
88
88
  description: "Tool requires user confirmation before executing",
89
89
  },
90
90
  { id: "activity.complete", description: "Background activity finished" },
91
+ {
92
+ id: "activity.failed",
93
+ description:
94
+ "Background job execution failed (model_provider, exception, or timeout)",
95
+ },
91
96
  {
92
97
  id: "quick_chat.response_ready",
93
98
  description: "Quick chat response ready for review",
@@ -289,6 +289,17 @@ function buildClassifyRiskParams(
289
289
  ): ClassifyRiskParams {
290
290
  // ── Bash/host_bash ──
291
291
  if (toolName === "bash" || toolName === "host_bash") {
292
+ // Count credential references attached to this invocation.
293
+ let credentialRefCount: number | undefined;
294
+ if (Array.isArray(input.credential_ids)) {
295
+ const validIds = (input.credential_ids as unknown[]).filter(
296
+ (id) => typeof id === "string" && id.length > 0,
297
+ );
298
+ if (validIds.length > 0) {
299
+ credentialRefCount = validIds.length;
300
+ }
301
+ }
302
+
292
303
  return {
293
304
  tool: toolName,
294
305
  command: getStringField(input, "command"),
@@ -297,6 +308,7 @@ function buildClassifyRiskParams(
297
308
  isContainerized: getIsContainerized(),
298
309
  networkMode:
299
310
  typeof input.network_mode === "string" ? input.network_mode : undefined,
311
+ credentialRefCount,
300
312
  };
301
313
  }
302
314
 
@@ -92,4 +92,6 @@ export interface ClassifyRiskParams {
92
92
  skillMetadata?: SkillMetadata;
93
93
  /** Tool registry default risk level for unknown tools. */
94
94
  registryDefaultRisk?: string;
95
+ /** Number of credential references attached to this tool invocation. */
96
+ credentialRefCount?: number;
95
97
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Public entry point for the `@vellumai/plugin-api` package.
3
+ *
4
+ * Plugin authors import from `"@vellumai/plugin-api"`; this file is what
5
+ * their import lands on (directly via the published npm package, or via a
6
+ * boot-time shim that re-exports from the assistant binary's embedded
7
+ * bundle).
8
+ *
9
+ * Keep this file's surface stable across minor/patch releases. Anything
10
+ * exported here is part of the public contract.
11
+ */
12
+
13
+ export type { PluginInitContext, PluginShutdownContext } from "./types.js";
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "@vellumai/plugin-api",
3
+ "version": "0.0.0-source",
4
+ "description": "Public API surface for Vellum assistant plugins. Source-of-truth lives here; the bundled artifact is what gets published to npm and embedded into the assistant binary.",
5
+ "type": "module",
6
+ "private": true,
7
+ "main": "./index.ts",
8
+ "types": "./index.ts",
9
+ "exports": {
10
+ ".": "./index.ts"
11
+ }
12
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Public plugin-API types.
3
+ *
4
+ * This module is the source-of-truth for types that plugin authors depend on.
5
+ * The rest of the assistant imports from here via relative paths
6
+ * (`../plugin-api/types.js`). At publish time, this file's contents are
7
+ * bundled into the `@vellumai/plugin-api` npm package; at runtime in the
8
+ * assistant binary, the same source is reachable to user plugins via a
9
+ * boot-time shim that re-exports from the embedded bundle.
10
+ *
11
+ * Today this module is intentionally narrow — only `PluginInitContext` and
12
+ * `PluginShutdownContext`. Additional public types migrate over in
13
+ * follow-up PRs as the surface stabilizes.
14
+ *
15
+ * Internal-only types (pipeline shapes, middleware, manifest validation,
16
+ * etc.) stay in `assistant/src/plugins/types.ts` until they're ready to
17
+ * become public.
18
+ */
19
+
20
+ // ─── Init context ────────────────────────────────────────────────────────────
21
+
22
+ /**
23
+ * Context passed to `Plugin.init()` during bootstrap. Carries resolved
24
+ * config/credentials, a pino-compatible logger scoped to the plugin, a
25
+ * per-plugin writable data directory, and the assistant's version metadata.
26
+ */
27
+ export interface PluginInitContext {
28
+ /** Parsed config for this plugin (may be `unknown` until the manifest validates). */
29
+ config: unknown;
30
+ /** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
31
+ credentials: Record<string, string>;
32
+ /**
33
+ * Pino-compatible child logger bound to `{ plugin: <name> }`. Untyped here
34
+ * to avoid pulling pino into the types module.
35
+ */
36
+ logger: unknown;
37
+ /** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
38
+ pluginStorageDir: string;
39
+ /** Assistant semver for compatibility checks inside the plugin. */
40
+ assistantVersion: string;
41
+ /** Capability → version-list map (`ASSISTANT_API_VERSIONS`) for defensive runtime checks. */
42
+ apiVersions: Record<string, string[]>;
43
+ }
44
+
45
+ // ─── Shutdown context ────────────────────────────────────────────────────────
46
+
47
+ /**
48
+ * Context passed to the `shutdown` hook during daemon teardown. Kept
49
+ * intentionally narrower than {@link PluginInitContext} — most teardown
50
+ * paths only need to know which assistant version they're shutting
51
+ * down against (e.g. for version-conditional cleanup of state files
52
+ * written by a previous boot).
53
+ *
54
+ * Additional fields may be added as concrete plugin needs surface; the
55
+ * `assistantVersion` field mirrors the init context's so plugins that
56
+ * stash a version stamp at init can compare against the same name on
57
+ * tear-down without keeping their own copy.
58
+ */
59
+ export interface PluginShutdownContext {
60
+ /** Assistant semver for compatibility checks inside the plugin. */
61
+ assistantVersion: string;
62
+ }
@@ -251,9 +251,24 @@ const pkbReminderInjector: Injector = {
251
251
  const mode = inputs.mode ?? "full";
252
252
  if (mode !== "full") return null;
253
253
  if (!inputs.pkbActive) return null;
254
+ // The `memory-retrospective` feature flag enables a focused background
255
+ // retrospective pass that catches what the in-conversation `remember`
256
+ // calls miss. When that backstop is on, the per-turn pressure to call
257
+ // `remember` softens to a judgment framing. When it's off, the original
258
+ // high-pressure BODY is used so users without the retrospective still
259
+ // get aggressive capture in-conversation.
260
+ let relaxed = false;
261
+ try {
262
+ relaxed = isAssistantFeatureFlagEnabled(
263
+ "memory-retrospective",
264
+ getConfig(),
265
+ );
266
+ } catch {
267
+ // Best-effort — fall back to the default (non-relaxed) BODY.
268
+ }
254
269
  const reminder = isPkbInjectionSilencedByV2()
255
- ? buildPkbReminder([])
256
- : await buildPkbReminderWithHints(inputs);
270
+ ? buildPkbReminder([], relaxed)
271
+ : await buildPkbReminderWithHints(inputs, relaxed);
257
272
  return {
258
273
  id: "pkb-reminder",
259
274
  text: reminder,
@@ -283,6 +298,7 @@ function buildPkbContextBlock(content: string): string {
283
298
  */
284
299
  async function buildPkbReminderWithHints(
285
300
  inputs: TurnInjectionInputs,
301
+ relaxed: boolean,
286
302
  ): Promise<string> {
287
303
  let hints: string[] = [];
288
304
  const queryVector = inputs.pkbQueryVector;
@@ -343,7 +359,7 @@ async function buildPkbReminderWithHints(
343
359
  hints = [];
344
360
  }
345
361
  }
346
- return buildPkbReminder(hints);
362
+ return buildPkbReminder(hints, relaxed);
347
363
  }
348
364
 
349
365
  /**
@@ -0,0 +1,294 @@
1
+ /**
2
+ * External plugin loader — builds a {@link Plugin} from a directory and
3
+ * registers it with the runtime.
4
+ *
5
+ * The convention this loader walks is currently **experimental**: surface
6
+ * set, manifest fields, and discovery shape may all change before the
7
+ * framework stabilizes. We keep this module's identifiers harness-neutral
8
+ * ("external") so the stable call path through the harness —
9
+ * `loadUserPlugins → loadExternalPlugin → registerPlugin` — does not
10
+ * need to be renamed when the convention shifts.
11
+ *
12
+ * <pluginDir>/
13
+ * package.json ← manifest.name comes from `name`
14
+ * (npm scope stripped); manifest.requires
15
+ * comes from `vellum.requires` if present
16
+ * hooks/
17
+ * <name>.ts ← default export → plugin.hooks[<name>]
18
+ * (today the runtime invokes "init" at
19
+ * bootstrap and "shutdown" at teardown;
20
+ * other filenames sit in the map for
21
+ * forward compatibility)
22
+ * tools/
23
+ * *.ts ← each file's default export → plugin.tools[]
24
+ * src/ ← internal helpers, ignored by the loader
25
+ *
26
+ * Per-surface, `.js` is preferred over `.ts` (compiled-binary semantics).
27
+ * Missing surface files are silently omitted (the harness treats absent
28
+ * fields as "this plugin contributes nothing here"). Surface files
29
+ * present without a usable default export are a hard failure: the
30
+ * loader logs with attribution and skips the plugin.
31
+ *
32
+ * This function owns the per-plugin isolation contract: it never throws,
33
+ * times out after `importTimeoutMs`, catches any error from the build or
34
+ * `registerPlugin` call, and logs an attributed entry. Callers can
35
+ * `await loadExternalPlugin(...)` in a loop with no per-iteration guard.
36
+ */
37
+
38
+ import { existsSync, readdirSync, statSync } from "node:fs";
39
+ import { readFile } from "node:fs/promises";
40
+ import { join } from "node:path";
41
+ import { pathToFileURL } from "node:url";
42
+
43
+ import { z } from "zod";
44
+
45
+ import { getLogger } from "../util/logger.js";
46
+ import { registerPlugin } from "./registry.js";
47
+ import type {
48
+ Plugin,
49
+ PluginHookFn,
50
+ PluginHooks,
51
+ PluginManifest,
52
+ PluginToolRegistration,
53
+ } from "./types.js";
54
+
55
+ const log = getLogger("external-plugin-loader");
56
+
57
+ /** Default upper bound on how long a single plugin load may take. */
58
+ const DEFAULT_IMPORT_TIMEOUT_MS = 10_000;
59
+
60
+ /**
61
+ * Zod schema for the subset of `package.json` the external loader reads.
62
+ *
63
+ * - `name` is the only required field; everything else is best-effort.
64
+ * - `vellum.requires` is forwarded to {@link PluginManifest.requires}
65
+ * verbatim (no merge with defaults) — empty objects propagate so the
66
+ * registry can reject under-specified plugins.
67
+ * - Unknown fields pass through (`passthrough`) so the loader does not
68
+ * destructively reshape the file when the rest of the npm ecosystem
69
+ * writes to it.
70
+ */
71
+ const PluginPackageJsonSchema = z
72
+ .object({
73
+ name: z.string().min(1, "package.json `name` must be a non-empty string"),
74
+ version: z.string().optional(),
75
+ vellum: z
76
+ .object({
77
+ requires: z.record(z.string(), z.string()).optional(),
78
+ })
79
+ .passthrough()
80
+ .optional(),
81
+ })
82
+ .passthrough();
83
+
84
+ type PluginPackageJson = z.infer<typeof PluginPackageJsonSchema>;
85
+
86
+ export interface LoadExternalPluginOptions {
87
+ /**
88
+ * Maximum time to spend building the `Plugin` from disk before bailing.
89
+ * The build runs to completion in the background if it eventually
90
+ * resolves, but the loader has already moved on. Defaults to
91
+ * {@link DEFAULT_IMPORT_TIMEOUT_MS}.
92
+ */
93
+ readonly importTimeoutMs?: number;
94
+ }
95
+
96
+ /**
97
+ * Strip the npm scope from a package name. `@vellumai/simple-memory` →
98
+ * `simple-memory`; an unscoped name passes through unchanged.
99
+ */
100
+ function stripScope(name: string): string {
101
+ const match = /^@[^/]+\/(.+)$/.exec(name);
102
+ return match ? match[1]! : name;
103
+ }
104
+
105
+ /**
106
+ * Dynamic-import `absolutePath` and return its default export. Throws when
107
+ * the module has no default export — callers attribute the error.
108
+ */
109
+ async function importDefault<T>(absolutePath: string): Promise<T> {
110
+ const url = pathToFileURL(absolutePath).href;
111
+ const mod = (await import(url)) as { default?: T };
112
+ if (mod.default === undefined) {
113
+ throw new Error(
114
+ `module ${absolutePath} has no default export — external plugins must default-export their interface surfaces`,
115
+ );
116
+ }
117
+ return mod.default;
118
+ }
119
+
120
+ interface SurfaceFile {
121
+ /** Basename without `.js`/`.ts` extension. */
122
+ readonly name: string;
123
+ /** Absolute path on disk. */
124
+ readonly path: string;
125
+ }
126
+
127
+ /**
128
+ * List every `.js`/`.ts` file directly under `dir`, deduplicating `.js`
129
+ * over `.ts` when both are present for the same basename. Returns entries
130
+ * sorted by basename so plugin authors get a deterministic per-plugin
131
+ * registration sequence; cross-plugin order remains the registry's job.
132
+ *
133
+ * Used to walk both `hooks/` and `tools/` — neither surface needs
134
+ * subdirectory recursion today, so this stays flat on purpose.
135
+ */
136
+ function listSurfaceDir(dir: string): SurfaceFile[] {
137
+ if (!existsSync(dir) || !statSync(dir).isDirectory()) return [];
138
+ const entries = readdirSync(dir);
139
+ const byBase = new Map<string, string>();
140
+ for (const entry of entries) {
141
+ // `.d.ts` declaration files are TypeScript type-only artifacts shipped
142
+ // alongside compiled `.js`. They have no default-exported runtime
143
+ // function and would crash `importDefault`, so the walker filters
144
+ // them out before the `.js`/`.ts` extension check.
145
+ if (entry.endsWith(".d.ts")) continue;
146
+ const base =
147
+ entry.endsWith(".js") || entry.endsWith(".ts")
148
+ ? entry.slice(0, -3)
149
+ : null;
150
+ if (base === null) continue;
151
+ const existing = byBase.get(base);
152
+ if (
153
+ existing === undefined ||
154
+ (existing.endsWith(".ts") && entry.endsWith(".js"))
155
+ ) {
156
+ byBase.set(base, entry);
157
+ }
158
+ }
159
+ return [...byBase.keys()]
160
+ .sort()
161
+ .map((name) => ({ name, path: join(dir, byBase.get(name)!) }));
162
+ }
163
+
164
+ /**
165
+ * Walk every file under `<pluginDir>/hooks/` and import each as a
166
+ * lifecycle hook keyed by filename basename. The runtime today invokes
167
+ * `init` at bootstrap and `shutdown` at teardown; other filenames are
168
+ * loaded into the map for forward compatibility with future lifecycle
169
+ * events but stay inert.
170
+ */
171
+ async function loadHooks(
172
+ pluginDir: string,
173
+ pluginName: string,
174
+ ): Promise<PluginHooks | undefined> {
175
+ const files = listSurfaceDir(join(pluginDir, "hooks"));
176
+ if (files.length === 0) return undefined;
177
+ const hooks: PluginHooks = {};
178
+ for (const { name, path } of files) {
179
+ const fn = await importDefault<PluginHookFn>(path);
180
+ if (typeof fn !== "function") {
181
+ throw new Error(
182
+ `external plugin ${pluginName}: hooks/${name} default export must be a function (got ${typeof fn})`,
183
+ );
184
+ }
185
+ hooks[name] = fn;
186
+ }
187
+ return hooks;
188
+ }
189
+
190
+ /**
191
+ * Build a `Plugin` object from the directory layout. Internal — the
192
+ * public entry point ({@link loadExternalPlugin}) wraps this in the
193
+ * timeout/try-catch/register triple.
194
+ */
195
+ async function buildPluginFromDir(pluginDir: string): Promise<Plugin> {
196
+ const pkgPath = join(pluginDir, "package.json");
197
+ let rawPkg: unknown;
198
+ try {
199
+ rawPkg = JSON.parse(await readFile(pkgPath, "utf8"));
200
+ } catch (err) {
201
+ const reason = err instanceof Error ? err.message : String(err);
202
+ throw new Error(
203
+ `package.json at ${pluginDir} could not be read or parsed: ${reason}`,
204
+ );
205
+ }
206
+ const parsed = PluginPackageJsonSchema.safeParse(rawPkg);
207
+ if (!parsed.success) {
208
+ throw new Error(
209
+ `package.json at ${pluginDir} failed schema validation: ${parsed.error.message}`,
210
+ );
211
+ }
212
+ const pkg: PluginPackageJson = parsed.data;
213
+ const name = stripScope(pkg.name);
214
+ const version = pkg.version && pkg.version.length > 0 ? pkg.version : "0.0.0";
215
+
216
+ // Default `requires` keeps the existing v1 negotiation working for
217
+ // plugins that have not yet opted into `vellum.requires`. Plugins that
218
+ // set `vellum.requires` get exactly what they declared — no merge.
219
+ const requires = pkg.vellum?.requires ?? { pluginRuntime: "v1" };
220
+
221
+ const manifest: PluginManifest = { name, version, requires };
222
+ const plugin: Plugin = { manifest };
223
+
224
+ const hooks = await loadHooks(pluginDir, name);
225
+ if (hooks !== undefined) plugin.hooks = hooks;
226
+
227
+ const tools: PluginToolRegistration[] = [];
228
+ for (const { path: toolPath } of listSurfaceDir(join(pluginDir, "tools"))) {
229
+ const tool = await importDefault<PluginToolRegistration>(toolPath);
230
+ if (
231
+ tool === null ||
232
+ typeof tool !== "object" ||
233
+ typeof (tool as { name?: unknown }).name !== "string"
234
+ ) {
235
+ throw new Error(
236
+ `external plugin ${name}: ${toolPath} default export must be a Tool object with a string "name"`,
237
+ );
238
+ }
239
+ tools.push(tool);
240
+ }
241
+ if (tools.length > 0) plugin.tools = tools;
242
+
243
+ return plugin;
244
+ }
245
+
246
+ /**
247
+ * Load the external plugin at `pluginDir` and register it.
248
+ */
249
+ export async function loadExternalPlugin(
250
+ pluginDir: string,
251
+ opts: LoadExternalPluginOptions = {},
252
+ ): Promise<void> {
253
+ const timeoutMs = opts.importTimeoutMs ?? DEFAULT_IMPORT_TIMEOUT_MS;
254
+ let timeoutHandle: ReturnType<typeof setTimeout> | undefined;
255
+ try {
256
+ const timeoutSentinel = Symbol("external-plugin-load-timeout");
257
+ const buildPromise = buildPluginFromDir(pluginDir);
258
+ const timeoutPromise = new Promise<typeof timeoutSentinel>((resolve) => {
259
+ timeoutHandle = setTimeout(() => resolve(timeoutSentinel), timeoutMs);
260
+ });
261
+ const result = await Promise.race([buildPromise, timeoutPromise]);
262
+ if (result === timeoutSentinel) {
263
+ // Abandoned build — surface imports may still be running. Attach a
264
+ // terminal `.catch` so a late rejection does not surface as an
265
+ // unhandled-rejection crash. The closed-registration latch in
266
+ // `registry.ts` rejects any late `registerPlugin()` call from a
267
+ // surface module that finishes evaluating after this loader has
268
+ // moved on.
269
+ buildPromise.catch(() => {
270
+ /* swallow — see comment above */
271
+ });
272
+ log.warn(
273
+ { pluginDir, timeoutMs },
274
+ `Timed out loading external plugin ${pluginDir} after ${timeoutMs}ms — skipping`,
275
+ );
276
+ return;
277
+ }
278
+ registerPlugin(result);
279
+ log.info(
280
+ { pluginDir, name: result.manifest.name },
281
+ "loaded external plugin",
282
+ );
283
+ } catch (err) {
284
+ // Per-plugin isolation: one bad external plugin must not crash the
285
+ // daemon. Surface the failure with attribution and move on.
286
+ const message = err instanceof Error ? err.message : String(err);
287
+ log.error(
288
+ { err, pluginDir },
289
+ `Failed to load external plugin ${pluginDir}: ${message}`,
290
+ );
291
+ } finally {
292
+ if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);
293
+ }
294
+ }
@@ -93,30 +93,14 @@ export interface PluginManifest {
93
93
  config?: unknown;
94
94
  }
95
95
 
96
- // ─── Init context ────────────────────────────────────────────────────────────
97
-
98
- /**
99
- * Context passed to `Plugin.init()` during bootstrap. Carries resolved
100
- * config/credentials, a pino-compatible logger scoped to the plugin, a
101
- * per-plugin writable data directory, and the assistant's version metadata.
102
- */
103
- export interface PluginInitContext {
104
- /** Parsed config for this plugin (may be `unknown` until the manifest validates). */
105
- config: unknown;
106
- /** Resolved credential values keyed by the entries of `manifest.requiresCredential`. */
107
- credentials: Record<string, string>;
108
- /**
109
- * Pino-compatible child logger bound to `{ plugin: <name> }`. Untyped here
110
- * to avoid pulling pino into the types module.
111
- */
112
- logger: unknown;
113
- /** Absolute path to `<workspaceDir>/plugins-data/<plugin>/` (created by bootstrap). */
114
- pluginStorageDir: string;
115
- /** Assistant semver for compatibility checks inside the plugin. */
116
- assistantVersion: string;
117
- /** Capability → version-list map (`ASSISTANT_API_VERSIONS`) for defensive runtime checks. */
118
- apiVersions: Record<string, string[]>;
119
- }
96
+ // ─── Init / Shutdown context ─────────────────────────────────────────────────
97
+ // Public types — defined in `assistant/src/plugin-api/types.ts` and re-exported
98
+ // here so existing internal call sites keep working. Plugin authors will
99
+ // import these from `@vellumai/plugin-api` once that package is published.
100
+ export type {
101
+ PluginInitContext,
102
+ PluginShutdownContext,
103
+ } from "../plugin-api/types.js";
120
104
 
121
105
  // ─── Middleware ──────────────────────────────────────────────────────────────
122
106
 
@@ -1077,19 +1061,51 @@ export interface PluginSkillRegistration {
1077
1061
 
1078
1062
  // ─── Plugin ──────────────────────────────────────────────────────────────────
1079
1063
 
1064
+ /**
1065
+ * A plugin lifecycle hook. Receives a per-lifecycle context shape and
1066
+ * may return either a transformed context or `void`. Today's runtime
1067
+ * consumes only the resolved-or-rejected nature of the promise; the
1068
+ * `TCtx` return is reserved for future hooks that fan a transformed
1069
+ * context out to downstream plugins.
1070
+ *
1071
+ * Each known hook key has a documented context shape:
1072
+ * - `init` — {@link PluginInitContext}
1073
+ * - `shutdown` — {@link PluginShutdownContext}
1074
+ *
1075
+ * Unknown keys are populated by the loader for forward compatibility
1076
+ * but are not invoked by today's runtime.
1077
+ */
1078
+ export type PluginHookFn<TCtx = unknown> = (
1079
+ ctx: TCtx,
1080
+ ) => Promise<TCtx | void>;
1081
+
1082
+ /**
1083
+ * Map of lifecycle hooks contributed by a plugin. Keys match file
1084
+ * basenames under `<plugin>/hooks/` — the external loader populates one
1085
+ * entry per `hooks/<name>.{ts,js}` it finds. The runtime invokes
1086
+ * known keys (`init`, `shutdown`) at the matching lifecycle event;
1087
+ * unknown keys are forward-compat scaffolding.
1088
+ *
1089
+ * See `assistant/src/daemon/external-plugins-bootstrap.ts` for the
1090
+ * full lifecycle, and {@link PluginHookFn} for the per-entry signature.
1091
+ */
1092
+ // The map stores hooks for arbitrary keys with arbitrary context shapes.
1093
+ // `any` (rather than `unknown`) is required so concrete plugin signatures
1094
+ // like `(ctx: PluginInitContext) => Promise<void>` and `() => Promise<void>`
1095
+ // both assign in/out of slot entries under strict-function-types contravariance.
1096
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1097
+ export type PluginHooks = Record<string, PluginHookFn<any>>;
1098
+
1080
1099
  /**
1081
1100
  * A registered plugin. Every field besides `manifest` is optional — a plugin
1082
1101
  * may contribute any combination of middleware, injectors, and model-visible
1083
- * capabilities. Lifecycle hooks (`init`, `onShutdown`) run sequentially
1084
- * during daemon startup/shutdown.
1102
+ * capabilities. Lifecycle hooks live under `hooks`.
1085
1103
  */
1086
1104
  export interface Plugin {
1087
1105
  /** Static manifest validated by the registry. */
1088
1106
  manifest: PluginManifest;
1089
- /** Optional async initializer. Runs once during bootstrap, before traffic. */
1090
- init?(ctx: PluginInitContext): Promise<void>;
1091
- /** Optional shutdown hook. Runs during daemon shutdown in reverse-registration order. */
1092
- onShutdown?(): Promise<void>;
1107
+ /** Lifecycle hooks (init, shutdown). See {@link PluginHooks}. */
1108
+ hooks?: PluginHooks;
1093
1109
  /** Tool registrations visible to the model. */
1094
1110
  tools?: PluginToolRegistration[];
1095
1111
  /** HTTP route registrations served by the assistant. */