@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
@@ -1,17 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
- import {
4
- afterEach,
5
- beforeEach,
6
- describe,
7
- expect,
8
- mock,
9
- test,
10
- } from "bun:test";
3
+ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
11
4
 
12
5
  import { getWorkspacePromptPath } from "../util/platform.js";
13
6
 
14
- // ── fs.readFileSync override (for gap 3 test) ────────────────────────
7
+ // ── fs.readFileSync override (for read-failure test) ─────────────────
15
8
  // We mock node:fs so we can inject a readFileSync that throws for the
16
9
  // workspace path. All other call sites fall through to the real fs.
17
10
  const realReadFileSync = readFileSync;
@@ -54,62 +47,58 @@ mock.module("../config/loader.js", () => ({
54
47
  getConfig: () => ({ updates: updatesConfig }),
55
48
  }));
56
49
 
57
- // ── bootstrapConversation + wakeAgentForOpportunity mocks ────────────
58
- let bootstrapCalls = 0;
59
- let bootstrapLastArgs: Record<string, unknown> | null = null;
60
- let wakeCalls = 0;
61
- let wakeLastArgs: Record<string, unknown> | null = null;
62
- let wakeShouldThrow = false;
63
- let wakeInvoked = true;
64
- let wakeProducedToolCalls = false;
65
- // A side-effect function invoked during wake. Lets tests simulate the
66
- // agent deleting UPDATES.md while the wake is in flight.
67
- let wakeSideEffect: (() => void) | null = null;
68
-
69
- mock.module("../memory/conversation-bootstrap.js", () => ({
70
- bootstrapConversation: (opts: Record<string, unknown>) => {
71
- bootstrapCalls += 1;
72
- bootstrapLastArgs = opts;
73
- return { id: `conv-${bootstrapCalls}` };
74
- },
75
- }));
50
+ // ── pre-first-message gate stub ──────────────────────────────────────
51
+ // Default: gate open (user has interacted) so the existing happy/sad
52
+ // paths exercise the bulletin logic. A dedicated test below flips this
53
+ // to false to assert the gate trips.
54
+ let preFirstMessageGateOpen = true;
76
55
 
77
- // ── deleteConversation mock (orphan cleanup path) ────────────────────
78
- let deleteCalls = 0;
79
- const deletedIds: string[] = [];
80
- let deleteShouldThrow = false;
81
-
82
- mock.module("../memory/conversation-crud.js", () => ({
83
- deleteConversation: (id: string) => {
84
- deleteCalls += 1;
85
- deletedIds.push(id);
86
- if (deleteShouldThrow) {
87
- throw new Error("simulated delete failure");
88
- }
89
- return { segmentIds: [], deletedSummaryIds: [] };
90
- },
56
+ mock.module("../runtime/pre-first-message-gate.js", () => ({
57
+ hasReceivedUserMessage: () => preFirstMessageGateOpen,
91
58
  }));
92
59
 
93
- mock.module("../runtime/agent-wake.js", () => ({
94
- wakeAgentForOpportunity: async (opts: Record<string, unknown>) => {
95
- wakeCalls += 1;
96
- wakeLastArgs = opts;
97
- if (wakeSideEffect) {
98
- wakeSideEffect();
60
+ // ── runBackgroundJob mock ────────────────────────────────────────────
61
+ let runBackgroundJobCalls = 0;
62
+ let runBackgroundJobLastArgs: Record<string, unknown> | null = null;
63
+ let runBackgroundJobShouldThrow = false;
64
+ let runBackgroundJobOk = true;
65
+ let runBackgroundJobErrorKind:
66
+ | "timeout"
67
+ | "model_provider"
68
+ | "exception"
69
+ | undefined = undefined;
70
+ let runBackgroundJobErrorMessage: string | undefined = undefined;
71
+ // A side-effect function invoked during the job. Lets tests simulate the
72
+ // agent deleting UPDATES.md while the job is running.
73
+ let runBackgroundJobSideEffect: (() => void) | null = null;
74
+
75
+ mock.module("../runtime/background-job-runner.js", () => ({
76
+ runBackgroundJob: async (opts: Record<string, unknown>) => {
77
+ runBackgroundJobCalls += 1;
78
+ runBackgroundJobLastArgs = opts;
79
+ if (runBackgroundJobSideEffect) {
80
+ runBackgroundJobSideEffect();
99
81
  }
100
- if (wakeShouldThrow) {
101
- throw new Error("simulated wake failure");
82
+ if (runBackgroundJobShouldThrow) {
83
+ throw new Error("simulated runner failure");
84
+ }
85
+ if (runBackgroundJobOk) {
86
+ return {
87
+ conversationId: `conv-${runBackgroundJobCalls}`,
88
+ ok: true,
89
+ };
102
90
  }
103
91
  return {
104
- invoked: wakeInvoked,
105
- producedToolCalls: wakeProducedToolCalls,
92
+ conversationId: `conv-${runBackgroundJobCalls}`,
93
+ ok: false,
94
+ error: new Error(runBackgroundJobErrorMessage ?? "simulated failure"),
95
+ errorKind: runBackgroundJobErrorKind ?? "exception",
106
96
  };
107
97
  },
108
98
  }));
109
99
 
110
- const { runUpdateBulletinJobIfNeeded } = await import(
111
- "../prompts/update-bulletin-job.js"
112
- );
100
+ const { runUpdateBulletinJobIfNeeded } =
101
+ await import("../prompts/update-bulletin-job.js");
113
102
 
114
103
  const HASH_CHECKPOINT_KEY = "updates:last_processed_hash";
115
104
  const EMPTY_HASH = "empty";
@@ -124,19 +113,16 @@ describe("runUpdateBulletinJobIfNeeded", () => {
124
113
  beforeEach(() => {
125
114
  store.clear();
126
115
  setCheckpointCallCount = 0;
127
- bootstrapCalls = 0;
128
- bootstrapLastArgs = null;
129
- wakeCalls = 0;
130
- wakeLastArgs = null;
131
- wakeShouldThrow = false;
132
- wakeInvoked = true;
133
- wakeProducedToolCalls = false;
134
- wakeSideEffect = null;
116
+ runBackgroundJobCalls = 0;
117
+ runBackgroundJobLastArgs = null;
118
+ runBackgroundJobShouldThrow = false;
119
+ runBackgroundJobOk = true;
120
+ runBackgroundJobErrorKind = undefined;
121
+ runBackgroundJobErrorMessage = undefined;
122
+ runBackgroundJobSideEffect = null;
135
123
  readFileSyncOverride = null;
136
124
  updatesConfig.enabled = true;
137
- deleteCalls = 0;
138
- deletedIds.length = 0;
139
- deleteShouldThrow = false;
125
+ preFirstMessageGateOpen = true;
140
126
  if (existsSync(workspacePath)) {
141
127
  rmSync(workspacePath);
142
128
  }
@@ -148,38 +134,45 @@ describe("runUpdateBulletinJobIfNeeded", () => {
148
134
  }
149
135
  });
150
136
 
151
- test("config disabled — no bootstrap, no wake, no checkpoint change", async () => {
137
+ test("config disabled — no job, no checkpoint change", async () => {
152
138
  updatesConfig.enabled = false;
153
139
  writeFileSync(workspacePath, "## Real content", "utf-8");
154
140
 
155
141
  await runUpdateBulletinJobIfNeeded();
156
142
 
157
- expect(bootstrapCalls).toBe(0);
158
- expect(wakeCalls).toBe(0);
143
+ expect(runBackgroundJobCalls).toBe(0);
144
+ expect(setCheckpointCallCount).toBe(0);
145
+ expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
146
+ });
147
+
148
+ test("pre-first-message gate closed — no job, checkpoint left UNCHANGED so the job retries after the user interacts", async () => {
149
+ preFirstMessageGateOpen = false;
150
+ writeFileSync(workspacePath, "## Real content", "utf-8");
151
+
152
+ await runUpdateBulletinJobIfNeeded();
153
+
154
+ expect(runBackgroundJobCalls).toBe(0);
159
155
  expect(setCheckpointCallCount).toBe(0);
160
156
  expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
161
157
  });
162
158
 
163
- test("file missing, stored hash absent — no wake; stored becomes 'empty'", async () => {
159
+ test("file missing, stored hash absent — no job; stored becomes 'empty'", async () => {
164
160
  expect(existsSync(workspacePath)).toBe(false);
165
161
  expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
166
162
 
167
163
  await runUpdateBulletinJobIfNeeded();
168
164
 
169
- expect(bootstrapCalls).toBe(0);
170
- expect(wakeCalls).toBe(0);
165
+ expect(runBackgroundJobCalls).toBe(0);
171
166
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(EMPTY_HASH);
172
167
  });
173
168
 
174
- test("file missing, stored hash already 'empty' — no wake; no checkpoint write", async () => {
169
+ test("file missing, stored hash already 'empty' — no job; no checkpoint write", async () => {
175
170
  store.set(HASH_CHECKPOINT_KEY, EMPTY_HASH);
176
- // Reset the counter to ignore the priming write above.
177
171
  setCheckpointCallCount = 0;
178
172
 
179
173
  await runUpdateBulletinJobIfNeeded();
180
174
 
181
- expect(bootstrapCalls).toBe(0);
182
- expect(wakeCalls).toBe(0);
175
+ expect(runBackgroundJobCalls).toBe(0);
183
176
  expect(setCheckpointCallCount).toBe(0);
184
177
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(EMPTY_HASH);
185
178
  });
@@ -189,28 +182,25 @@ describe("runUpdateBulletinJobIfNeeded", () => {
189
182
 
190
183
  await runUpdateBulletinJobIfNeeded();
191
184
 
192
- expect(bootstrapCalls).toBe(0);
193
- expect(wakeCalls).toBe(0);
185
+ expect(runBackgroundJobCalls).toBe(0);
194
186
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(EMPTY_HASH);
195
187
  });
196
188
 
197
- test("file present with content, wake produced tool calls bootstrap + wake; stored hash is sha256(trimmed); source/origin are snake_case", async () => {
189
+ test("file present, job ok=true, file unchanged — stored hash is sha256(trimmed); jobName/source are kebab-case", async () => {
198
190
  const content = "## Release 1.2.3\n\nNew thing.\n";
199
191
  writeFileSync(workspacePath, content, "utf-8");
200
- wakeProducedToolCalls = true;
201
192
 
202
193
  await runUpdateBulletinJobIfNeeded();
203
194
 
204
- expect(bootstrapCalls).toBe(1);
205
- expect(wakeCalls).toBe(1);
195
+ expect(runBackgroundJobCalls).toBe(1);
206
196
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(sha256(content.trim()));
207
- // Gap 4: confirm snake_case reached the downstream mocks.
208
- expect(bootstrapLastArgs?.source).toBe("updates_bulletin");
209
- expect(bootstrapLastArgs?.origin).toBe("updates_bulletin");
210
- expect(wakeLastArgs?.source).toBe("updates_bulletin");
197
+ expect(runBackgroundJobLastArgs?.jobName).toBe("update-bulletin");
198
+ expect(runBackgroundJobLastArgs?.source).toBe("update-bulletin");
199
+ expect(runBackgroundJobLastArgs?.origin).toBe("updates_bulletin");
200
+ expect(runBackgroundJobLastArgs?.callSite).toBe("mainAgent");
211
201
  });
212
202
 
213
- test("file present, stored hash matches current — no wake", async () => {
203
+ test("file present, stored hash matches current — no job", async () => {
214
204
  const content = "## Release 1.2.3\n\nSame content.\n";
215
205
  writeFileSync(workspacePath, content, "utf-8");
216
206
  store.set(HASH_CHECKPOINT_KEY, sha256(content.trim()));
@@ -218,138 +208,53 @@ describe("runUpdateBulletinJobIfNeeded", () => {
218
208
 
219
209
  await runUpdateBulletinJobIfNeeded();
220
210
 
221
- expect(bootstrapCalls).toBe(0);
222
- expect(wakeCalls).toBe(0);
223
- expect(setCheckpointCallCount).toBe(0);
224
- });
225
-
226
- test("wake returns invoked:false — checkpoint UNCHANGED + orphan conversation is cleaned up", async () => {
227
- const content = "## Release Q\n\nResolver-missing scenario.\n";
228
- writeFileSync(workspacePath, content, "utf-8");
229
- wakeInvoked = false;
230
- wakeProducedToolCalls = false;
231
-
232
- await runUpdateBulletinJobIfNeeded();
233
-
234
- expect(bootstrapCalls).toBe(1);
235
- expect(wakeCalls).toBe(1);
236
- // Critical: do NOT poison the checkpoint (round-1 behavior preserved).
237
- expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
238
- expect(setCheckpointCallCount).toBe(0);
239
- // Belt-and-suspenders: the orphan background conversation bootstrapped
240
- // before the wake must be deleted so we don't leak DB rows on every
241
- // silent no-op.
242
- expect(deleteCalls).toBe(1);
243
- expect(deletedIds).toEqual(["conv-1"]);
244
- });
245
-
246
- test("wake returns invoked:false AND deleteConversation throws — function still returns (cleanup error is swallowed)", async () => {
247
- const content = "## Release Q2\n\nDelete-throws scenario.\n";
248
- writeFileSync(workspacePath, content, "utf-8");
249
- wakeInvoked = false;
250
- wakeProducedToolCalls = false;
251
- deleteShouldThrow = true;
252
-
253
- await expect(runUpdateBulletinJobIfNeeded()).resolves.toBeUndefined();
254
-
255
- expect(bootstrapCalls).toBe(1);
256
- expect(wakeCalls).toBe(1);
257
- expect(deleteCalls).toBe(1);
258
- // Checkpoint still untouched.
259
- expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
211
+ expect(runBackgroundJobCalls).toBe(0);
260
212
  expect(setCheckpointCallCount).toBe(0);
261
213
  });
262
214
 
263
- test("wake invoked normallydeleteConversation is NOT called (happy path)", async () => {
264
- const content = "## Release Q3\n\nNormal happy-path scenario.\n";
265
- writeFileSync(workspacePath, content, "utf-8");
266
- wakeInvoked = true;
267
- wakeProducedToolCalls = true;
268
-
269
- await runUpdateBulletinJobIfNeeded();
270
-
271
- expect(bootstrapCalls).toBe(1);
272
- expect(wakeCalls).toBe(1);
273
- expect(deleteCalls).toBe(0);
274
- expect(deletedIds).toEqual([]);
275
- });
276
-
277
- test("wake invoked but no tool calls AND file unchanged — checkpoint UNCHANGED (retry next startup)", async () => {
278
- const content = "## Release R\n\nSilent no-op scenario.\n";
215
+ test("runBackgroundJob returns ok=falsecheckpoint UNCHANGED so next startup retries", async () => {
216
+ const content = "## Release Q\n\nFailure scenario.\n";
279
217
  writeFileSync(workspacePath, content, "utf-8");
280
- wakeInvoked = true;
281
- wakeProducedToolCalls = false;
218
+ runBackgroundJobOk = false;
219
+ runBackgroundJobErrorKind = "exception";
220
+ runBackgroundJobErrorMessage = "boom";
282
221
 
283
222
  await runUpdateBulletinJobIfNeeded();
284
223
 
285
- expect(bootstrapCalls).toBe(1);
286
- expect(wakeCalls).toBe(1);
224
+ expect(runBackgroundJobCalls).toBe(1);
225
+ // Critical: do NOT poison the checkpoint when the job fails.
287
226
  expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
288
227
  expect(setCheckpointCallCount).toBe(0);
289
228
  });
290
229
 
291
- test("wake invoked, no tool calls, but file deleted mid-wakecheckpoint becomes 'empty'", async () => {
292
- const content = "## Release S\n\nAgent deleted file.\n";
230
+ test("runBackgroundJob ok=true + agent deletes file mid-runstored hash becomes 'empty'", async () => {
231
+ const content = "## Release X\n\nStuff to process.\n";
293
232
  writeFileSync(workspacePath, content, "utf-8");
294
- wakeInvoked = true;
295
- wakeProducedToolCalls = false;
296
- wakeSideEffect = () => {
233
+ runBackgroundJobSideEffect = () => {
297
234
  rmSync(workspacePath);
298
235
  };
299
236
 
300
237
  await runUpdateBulletinJobIfNeeded();
301
238
 
302
- expect(bootstrapCalls).toBe(1);
303
- expect(wakeCalls).toBe(1);
239
+ expect(runBackgroundJobCalls).toBe(1);
304
240
  expect(existsSync(workspacePath)).toBe(false);
305
241
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(EMPTY_HASH);
306
242
  });
307
243
 
308
- test("wake invoked + produced tool calls + file unchanged checkpoint = hash of content (agent decided this is the right state)", async () => {
309
- const content = "## Release T\n\nAgent processed, chose to leave file.\n";
310
- writeFileSync(workspacePath, content, "utf-8");
311
- wakeInvoked = true;
312
- wakeProducedToolCalls = true;
313
-
314
- await runUpdateBulletinJobIfNeeded();
315
-
316
- expect(bootstrapCalls).toBe(1);
317
- expect(wakeCalls).toBe(1);
318
- expect(store.get(HASH_CHECKPOINT_KEY)).toBe(sha256(content.trim()));
319
- });
320
-
321
- test("file present, stored hash differs — wake invoked; stored hash updates", async () => {
244
+ test("file present, stored hash differs job invoked; stored hash updates", async () => {
322
245
  const oldContent = "## Old";
323
246
  const newContent = "## New content v2";
324
247
  writeFileSync(workspacePath, newContent, "utf-8");
325
248
  store.set(HASH_CHECKPOINT_KEY, sha256(oldContent));
326
- wakeProducedToolCalls = true;
327
249
 
328
250
  await runUpdateBulletinJobIfNeeded();
329
251
 
330
- expect(bootstrapCalls).toBe(1);
331
- expect(wakeCalls).toBe(1);
252
+ expect(runBackgroundJobCalls).toBe(1);
332
253
  expect(store.get(HASH_CHECKPOINT_KEY)).toBe(sha256(newContent.trim()));
333
254
  expect(store.get(HASH_CHECKPOINT_KEY)).not.toBe(sha256(oldContent));
334
255
  });
335
256
 
336
- test("agent deletes file mid-wake (producedToolCalls=true)stored hash becomes 'empty'", async () => {
337
- const content = "## Release X\n\nStuff to process.\n";
338
- writeFileSync(workspacePath, content, "utf-8");
339
- wakeProducedToolCalls = true;
340
- wakeSideEffect = () => {
341
- rmSync(workspacePath);
342
- };
343
-
344
- await runUpdateBulletinJobIfNeeded();
345
-
346
- expect(bootstrapCalls).toBe(1);
347
- expect(wakeCalls).toBe(1);
348
- expect(existsSync(workspacePath)).toBe(false);
349
- expect(store.get(HASH_CHECKPOINT_KEY)).toBe(EMPTY_HASH);
350
- });
351
-
352
- test("file present but readFileSync throws — checkpoint UNCHANGED; warn logged (gap 3)", async () => {
257
+ test("file present but readFileSync throwscheckpoint UNCHANGED; warn logged", async () => {
353
258
  const content = "## Release U\n\nSimulated read failure.\n";
354
259
  writeFileSync(workspacePath, content, "utf-8");
355
260
 
@@ -366,22 +271,20 @@ describe("runUpdateBulletinJobIfNeeded", () => {
366
271
  readFileSyncOverride = null;
367
272
  }
368
273
 
369
- expect(bootstrapCalls).toBe(0);
370
- expect(wakeCalls).toBe(0);
274
+ expect(runBackgroundJobCalls).toBe(0);
371
275
  expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
372
276
  expect(setCheckpointCallCount).toBe(0);
373
277
  });
374
278
 
375
- test("wake throws — function does not reject; warning logged", async () => {
279
+ test("runBackgroundJob throws — function does not reject; warning logged", async () => {
376
280
  const content = "## Release Z";
377
281
  writeFileSync(workspacePath, content, "utf-8");
378
- wakeShouldThrow = true;
282
+ runBackgroundJobShouldThrow = true;
379
283
 
380
284
  // Must not throw.
381
285
  await expect(runUpdateBulletinJobIfNeeded()).resolves.toBeUndefined();
382
286
 
383
- expect(bootstrapCalls).toBe(1);
384
- expect(wakeCalls).toBe(1);
287
+ expect(runBackgroundJobCalls).toBe(1);
385
288
  // Hash was never updated because the try/catch returned before the
386
289
  // self-healing step.
387
290
  expect(store.has(HASH_CHECKPOINT_KEY)).toBe(false);
@@ -1,3 +1,14 @@
1
+ /**
2
+ * CLI plumbing tests for `assistant usage` (cli/commands/usage.ts).
3
+ *
4
+ * The `usage breakdown` subcommand is daemon-mediated via `cliIpcCall`; only
5
+ * argument validation runs in the CLI process. Table formatting and
6
+ * aggregation behavior are covered daemon-side in `usage-routes.test.ts`.
7
+ *
8
+ * Follow-up opportunity: mock `../ipc/cli-client.js` and assert CLI plumbing
9
+ * (table formatting, --json output shape) against canned IPC responses.
10
+ */
11
+
1
12
  import { beforeEach, describe, expect, mock, test } from "bun:test";
2
13
 
3
14
  import { Command } from "commander";
@@ -19,13 +30,8 @@ mock.module("../util/logger.js", () => ({
19
30
  }),
20
31
  }));
21
32
 
22
- const { initializeDb } = await import("../memory/db-init.js");
23
- const { getDb } = await import("../memory/db-connection.js");
24
- const { recordUsageEvent } = await import("../memory/llm-usage-store.js");
25
33
  const { registerUsageCommand } = await import("../cli/commands/usage.js");
26
34
 
27
- initializeDb();
28
-
29
35
  async function runCommand(args: string[]): Promise<{
30
36
  exitCode: number;
31
37
  output: string;
@@ -54,77 +60,9 @@ async function runCommand(args: string[]): Promise<{
54
60
  return { exitCode, output: logLines.join("\n") };
55
61
  }
56
62
 
57
- function insertUsage(
58
- overrides: Partial<Parameters<typeof recordUsageEvent>[0]>,
59
- estimatedCostUsd = 0.01,
60
- ): void {
61
- recordUsageEvent(
62
- {
63
- conversationId: null,
64
- runId: null,
65
- requestId: null,
66
- actor: "main_agent",
67
- provider: "anthropic",
68
- model: "claude-sonnet-4-20250514",
69
- inputTokens: 100,
70
- outputTokens: 50,
71
- cacheCreationInputTokens: 0,
72
- cacheReadInputTokens: 0,
73
- ...overrides,
74
- },
75
- { estimatedCostUsd, pricingStatus: "priced" },
76
- );
77
- }
78
-
79
63
  describe("assistant usage CLI", () => {
80
64
  beforeEach(() => {
81
65
  logLines.length = 0;
82
- getDb().run("DELETE FROM llm_usage_events");
83
- });
84
-
85
- test("breakdown JSON includes call-site display labels and groupKey", async () => {
86
- insertUsage({ callSite: "mainAgent" });
87
- insertUsage({ callSite: null, inputTokens: 200 }, 0.005);
88
-
89
- const result = await runCommand([
90
- "usage",
91
- "breakdown",
92
- "--range",
93
- "all",
94
- "--group-by",
95
- "call_site",
96
- "--json",
97
- ]);
98
-
99
- expect(result.exitCode).toBe(0);
100
- const parsed = JSON.parse(result.output) as {
101
- breakdown: Array<{ group: string; groupKey: string | null }>;
102
- };
103
- expect(parsed.breakdown.map((row) => row.group)).toEqual([
104
- "Main Agent",
105
- "Unknown Task",
106
- ]);
107
- expect(parsed.breakdown.map((row) => row.groupKey)).toEqual([
108
- "mainAgent",
109
- null,
110
- ]);
111
- });
112
-
113
- test("breakdown table prints friendly profile fallback labels", async () => {
114
- insertUsage({ inferenceProfile: null });
115
-
116
- const result = await runCommand([
117
- "usage",
118
- "breakdown",
119
- "--range",
120
- "all",
121
- "--group-by",
122
- "inference_profile",
123
- ]);
124
-
125
- expect(result.exitCode).toBe(0);
126
- expect(result.output).toContain("PROFILE");
127
- expect(result.output).toContain("Default / Unset");
128
66
  });
129
67
 
130
68
  test("rejects invalid breakdown dimensions", async () => {
@@ -230,4 +230,149 @@ registerPlugin({
230
230
  await loadUserPlugins();
231
231
  expect(getRegisteredPlugins()).toHaveLength(0);
232
232
  });
233
+
234
+ describe("experimental plugin framework branch", () => {
235
+ /**
236
+ * Write a directory-convention plugin (package.json + optional
237
+ * hooks/tools default exports). Mirrors `writePlugin()` above but
238
+ * targets the new experimental loader path.
239
+ */
240
+ function writeExperimentalPlugin(
241
+ name: string,
242
+ pkg: Record<string, unknown>,
243
+ files: Record<string, string> = {},
244
+ ): void {
245
+ const pluginDir = join(PLUGINS_DIR, name);
246
+ mkdirSync(pluginDir, { recursive: true });
247
+ writeFileSync(
248
+ join(pluginDir, "package.json"),
249
+ JSON.stringify(pkg, null, 2),
250
+ );
251
+ for (const [rel, body] of Object.entries(files)) {
252
+ const parts = rel.split("/");
253
+ parts.pop();
254
+ if (parts.length > 0) {
255
+ mkdirSync(join(pluginDir, ...parts), { recursive: true });
256
+ }
257
+ writeFileSync(join(pluginDir, rel), body);
258
+ }
259
+ }
260
+
261
+ test("loads a plugin via the package.json branch and registers it", async () => {
262
+ writeExperimentalPlugin(
263
+ "experimental-one",
264
+ { name: "experimental-one", version: "0.1.0" },
265
+ {
266
+ "hooks/init.ts":
267
+ "export default async function init(_ctx: unknown): Promise<void> {}\n",
268
+ },
269
+ );
270
+
271
+ await loadUserPlugins();
272
+
273
+ const names = getRegisteredPlugins().map((p) => p.manifest.name);
274
+ expect(names).toContain("experimental-one");
275
+ const registered = getRegisteredPlugins().find(
276
+ (p) => p.manifest.name === "experimental-one",
277
+ );
278
+ expect(typeof registered?.hooks?.init).toBe("function");
279
+ });
280
+
281
+ test("strips npm scope from package.json name", async () => {
282
+ writeExperimentalPlugin("scoped", {
283
+ name: "@vellumai/cool-plugin",
284
+ version: "0.1.0",
285
+ });
286
+
287
+ await loadUserPlugins();
288
+
289
+ const names = getRegisteredPlugins().map((p) => p.manifest.name);
290
+ expect(names).toContain("cool-plugin");
291
+ });
292
+
293
+ test("a broken experimental plugin is logged and skipped without affecting others", async () => {
294
+ // Plugin A has a malformed package.json; Plugin B is a healthy
295
+ // legacy register.ts. The loader must isolate A's failure and still
296
+ // register B — same per-plugin contract as the legacy path.
297
+ const brokenDir = join(PLUGINS_DIR, "broken-experimental");
298
+ mkdirSync(brokenDir, { recursive: true });
299
+ writeFileSync(join(brokenDir, "package.json"), "{ not valid json");
300
+
301
+ writePlugin(
302
+ "healthy-legacy",
303
+ `
304
+ registerPlugin({
305
+ manifest: {
306
+ name: "healthy-legacy",
307
+ version: "0.0.1",
308
+ requires: { pluginRuntime: "v1" },
309
+ },
310
+ });
311
+ `,
312
+ );
313
+
314
+ await loadUserPlugins();
315
+
316
+ const names = getRegisteredPlugins().map((p) => p.manifest.name);
317
+ expect(names).toContain("healthy-legacy");
318
+ expect(names).not.toContain("broken-experimental");
319
+ });
320
+
321
+ test("experimental and legacy plugins coexist in one workspace", async () => {
322
+ writeExperimentalPlugin("new-style", {
323
+ name: "new-style",
324
+ version: "0.1.0",
325
+ });
326
+ writePlugin(
327
+ "old-style",
328
+ `
329
+ registerPlugin({
330
+ manifest: {
331
+ name: "old-style",
332
+ version: "0.0.1",
333
+ requires: { pluginRuntime: "v1" },
334
+ },
335
+ });
336
+ `,
337
+ );
338
+
339
+ await loadUserPlugins();
340
+
341
+ const names = getRegisteredPlugins()
342
+ .map((p) => p.manifest.name)
343
+ .sort();
344
+ expect(names).toEqual(["new-style", "old-style"]);
345
+ });
346
+
347
+ test("package.json branch wins over a stale register.ts in the same dir", async () => {
348
+ // A migrated plugin may keep its old register.ts on disk while it
349
+ // adopts the new convention. The package.json gate takes the
350
+ // experimental path and the legacy register.ts is never imported,
351
+ // so the plugin must register exactly once.
352
+ const dir = join(PLUGINS_DIR, "migrated");
353
+ mkdirSync(dir, { recursive: true });
354
+ writeFileSync(
355
+ join(dir, "package.json"),
356
+ JSON.stringify({ name: "migrated", version: "0.1.0" }),
357
+ );
358
+ // A register.ts that would double-register if both paths fired.
359
+ const registryPath = join(
360
+ import.meta.dir,
361
+ "..",
362
+ "plugins",
363
+ "registry.ts",
364
+ );
365
+ writeFileSync(
366
+ join(dir, "register.ts"),
367
+ `import { registerPlugin } from ${JSON.stringify(registryPath)};
368
+ registerPlugin({ manifest: { name: "migrated", version: "0.0.1", requires: { pluginRuntime: "v1" } } });
369
+ `,
370
+ );
371
+
372
+ await loadUserPlugins();
373
+
374
+ const names = getRegisteredPlugins().map((p) => p.manifest.name);
375
+ expect(names.filter((n) => n === "migrated")).toHaveLength(1);
376
+ });
377
+ });
233
378
  });