@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,182 @@
1
+ /**
2
+ * Verifies that `emitNotificationSignal` invokes the home-feed side
3
+ * effect after dispatching, and that the side effect's background-only
4
+ * filter correctly suppresses interactive signals.
5
+ *
6
+ * The side effect itself is unit-tested in `home-feed-side-effect.test.ts`;
7
+ * this test exercises the wire-up boundary in `emit-signal.ts` by mocking
8
+ * at the `appendFeedItem` / `getConversation` boundary so the real
9
+ * background-filter logic runs end-to-end.
10
+ */
11
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
12
+
13
+ import type { FeedItem } from "../../home/feed-types.js";
14
+ import type {
15
+ NotificationDecision,
16
+ NotificationDeliveryResult,
17
+ } from "../types.js";
18
+
19
+ // ── Module mocks ───────────────────────────────────────────────────────
20
+ //
21
+ // `mock.module` is hoisted, so these intercepts apply before the module
22
+ // under test resolves its imports. Closures over module-scoped state
23
+ // let each test reset and inspect captured calls afterwards.
24
+
25
+ const appendCalls: FeedItem[] = [];
26
+ let conversationRow: { conversationType: string } | null = null;
27
+
28
+ mock.module("../../home/feed-writer.js", () => ({
29
+ appendFeedItem: async (item: FeedItem) => {
30
+ appendCalls.push(item);
31
+ },
32
+ }));
33
+
34
+ // home-feed-side-effect.ts only consumes `getConversation`.
35
+ mock.module("../../memory/conversation-crud.js", () => ({
36
+ getConversation: () => conversationRow,
37
+ }));
38
+
39
+ // Stub the broadcaster so emit-signal's `getBroadcaster()` does not need
40
+ // to build real adapters or pull in `conversation-pairing.ts` transitively
41
+ // (which would force us to mirror the full `conversation-crud.js` surface).
42
+ class StubBroadcaster {
43
+ setOnConversationCreated() {}
44
+ async broadcastDecision() {
45
+ return [];
46
+ }
47
+ }
48
+ mock.module("../broadcaster.js", () => ({
49
+ NotificationBroadcaster: StubBroadcaster,
50
+ }));
51
+
52
+ mock.module("../adapters/macos.js", () => ({
53
+ VellumAdapter: class {},
54
+ isGuardianSensitiveEvent: () => false,
55
+ }));
56
+ mock.module("../adapters/slack.js", () => ({
57
+ SlackAdapter: class {},
58
+ }));
59
+ mock.module("../adapters/telegram.js", () => ({
60
+ TelegramAdapter: class {},
61
+ }));
62
+
63
+ // Stub out the persistence + channel resolution layers so emitNotificationSignal
64
+ // can run end-to-end without touching the DB / contacts store / LLM.
65
+
66
+ mock.module("../events-store.js", () => ({
67
+ createEvent: (params: { id: string }) => ({
68
+ id: params.id,
69
+ sourceEventName: "schedule.notify",
70
+ sourceChannel: "scheduler",
71
+ sourceContextId: "conv-source-1",
72
+ attentionHintsJson: "{}",
73
+ payloadJson: "{}",
74
+ dedupeKey: null,
75
+ createdAt: 0,
76
+ updatedAt: 0,
77
+ }),
78
+ updateEventDedupeKey: () => {},
79
+ }));
80
+
81
+ mock.module("../decisions-store.js", () => ({
82
+ updateDecision: () => {},
83
+ }));
84
+
85
+ mock.module("../../contacts/contact-store.js", () => ({
86
+ findGuardianForChannel: () => null,
87
+ listGuardianChannels: () => [],
88
+ }));
89
+
90
+ const stubDecision: NotificationDecision = {
91
+ shouldNotify: true,
92
+ selectedChannels: ["vellum"],
93
+ reasoningSummary: "test",
94
+ renderedCopy: {
95
+ vellum: { title: "Background job done", body: "Summary of what happened." },
96
+ },
97
+ dedupeKey: "dk-1",
98
+ confidence: 1,
99
+ fallbackUsed: false,
100
+ };
101
+
102
+ mock.module("../decision-engine.js", () => ({
103
+ evaluateSignal: async () => stubDecision,
104
+ // Pass the decision through unchanged — emit-signal calls this after
105
+ // evaluateSignal and only re-persists when the reference changes.
106
+ enforceRoutingIntent: (decision: NotificationDecision) => decision,
107
+ }));
108
+
109
+ mock.module("../deterministic-checks.js", () => ({
110
+ runDeterministicChecks: async () => ({ passed: true }),
111
+ }));
112
+
113
+ const stubDeliveryResults: NotificationDeliveryResult[] = [
114
+ {
115
+ channel: "vellum",
116
+ destination: "vellum-client",
117
+ status: "sent",
118
+ conversationId: "conv-vellum-1",
119
+ },
120
+ ];
121
+
122
+ mock.module("../runtime-dispatch.js", () => ({
123
+ dispatchDecision: async () => ({
124
+ dispatched: true,
125
+ reason: "Dispatched to 1/1 channels",
126
+ deliveryResults: stubDeliveryResults,
127
+ }),
128
+ }));
129
+
130
+ const { emitNotificationSignal } = await import("../emit-signal.js");
131
+
132
+ // ── Tests ──────────────────────────────────────────────────────────────
133
+
134
+ beforeEach(() => {
135
+ appendCalls.length = 0;
136
+ conversationRow = null;
137
+ });
138
+
139
+ describe("emitNotificationSignal home-feed wire-up", () => {
140
+ test("background-conversation signal triggers appendFeedItem", async () => {
141
+ conversationRow = { conversationType: "background" };
142
+
143
+ const result = await emitNotificationSignal({
144
+ sourceEventName: "schedule.notify",
145
+ sourceChannel: "scheduler",
146
+ sourceContextId: "conv-source-1",
147
+ attentionHints: {
148
+ requiresAction: false,
149
+ urgency: "medium",
150
+ isAsyncBackground: false,
151
+ visibleInSourceNow: false,
152
+ },
153
+ });
154
+
155
+ expect(result.dispatched).toBe(true);
156
+ expect(appendCalls).toHaveLength(1);
157
+ const appended = appendCalls[0]!;
158
+ expect(appended.id).toBe(`notif:${result.signalId}`);
159
+ expect(appended.title).toBe("Background job done");
160
+ expect(appended.summary).toBe("Summary of what happened.");
161
+ expect(appended.conversationId).toBe("conv-vellum-1");
162
+ });
163
+
164
+ test("interactive standard conversation does NOT trigger appendFeedItem", async () => {
165
+ conversationRow = { conversationType: "standard" };
166
+
167
+ const result = await emitNotificationSignal({
168
+ sourceEventName: "schedule.notify",
169
+ sourceChannel: "scheduler",
170
+ sourceContextId: "conv-source-1",
171
+ attentionHints: {
172
+ requiresAction: false,
173
+ urgency: "medium",
174
+ isAsyncBackground: false,
175
+ visibleInSourceNow: true,
176
+ },
177
+ });
178
+
179
+ expect(result.dispatched).toBe(true);
180
+ expect(appendCalls).toHaveLength(0);
181
+ });
182
+ });
@@ -0,0 +1,199 @@
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
+
3
+ import type { FeedItem } from "../../home/feed-types.js";
4
+ import type { NotificationSignal } from "../signal.js";
5
+ import type {
6
+ NotificationDecision,
7
+ NotificationDeliveryResult,
8
+ } from "../types.js";
9
+
10
+ // ── Module mocks ───────────────────────────────────────────────────────
11
+ //
12
+ // `mock.module` is hoisted, so these intercepts apply before the module
13
+ // under test resolves its imports. Closures over the module-scoped
14
+ // arrays/flag below let each test reset state via `beforeEach` and
15
+ // inspect captured calls afterwards.
16
+
17
+ const appendCalls: FeedItem[] = [];
18
+ const conversationLookups: string[] = [];
19
+ let conversationRow: { conversationType: string } | null = null;
20
+ let conversationLookupShouldThrow = false;
21
+
22
+ mock.module("../../home/feed-writer.js", () => ({
23
+ appendFeedItem: async (item: FeedItem) => {
24
+ appendCalls.push(item);
25
+ },
26
+ }));
27
+
28
+ mock.module("../../memory/conversation-crud.js", () => ({
29
+ getConversation: (id: string) => {
30
+ conversationLookups.push(id);
31
+ if (conversationLookupShouldThrow) {
32
+ throw new Error("simulated conversation lookup failure");
33
+ }
34
+ return conversationRow;
35
+ },
36
+ }));
37
+
38
+ const { writeHomeFeedItemForSignal } =
39
+ await import("../home-feed-side-effect.js");
40
+
41
+ // ── Test fixtures ──────────────────────────────────────────────────────
42
+
43
+ function makeSignal(
44
+ overrides: Partial<NotificationSignal> = {},
45
+ ): NotificationSignal {
46
+ return {
47
+ signalId: "sig-test-1",
48
+ createdAt: 1700000000000,
49
+ sourceChannel: "scheduler",
50
+ sourceContextId: "conv-source-1",
51
+ sourceEventName: "schedule.notify",
52
+ contextPayload: {},
53
+ attentionHints: {
54
+ requiresAction: false,
55
+ urgency: "medium",
56
+ isAsyncBackground: false,
57
+ visibleInSourceNow: false,
58
+ },
59
+ ...overrides,
60
+ };
61
+ }
62
+
63
+ function makeDecision(
64
+ overrides: Partial<NotificationDecision> = {},
65
+ ): NotificationDecision {
66
+ return {
67
+ shouldNotify: true,
68
+ selectedChannels: [],
69
+ reasoningSummary: "test",
70
+ renderedCopy: {},
71
+ dedupeKey: "dk-1",
72
+ confidence: 1,
73
+ fallbackUsed: false,
74
+ ...overrides,
75
+ };
76
+ }
77
+
78
+ beforeEach(() => {
79
+ appendCalls.length = 0;
80
+ conversationLookups.length = 0;
81
+ conversationRow = null;
82
+ conversationLookupShouldThrow = false;
83
+ });
84
+
85
+ describe("writeHomeFeedItemForSignal", () => {
86
+ test("background conversation signal writes a feed item with rendered copy", async () => {
87
+ conversationRow = { conversationType: "background" };
88
+ const signal = makeSignal();
89
+ const decision = makeDecision({
90
+ renderedCopy: {
91
+ vellum: {
92
+ title: "Background job done",
93
+ body: "Summary of what happened.",
94
+ },
95
+ },
96
+ });
97
+
98
+ const item = await writeHomeFeedItemForSignal(signal, decision, []);
99
+
100
+ expect(conversationLookups).toEqual(["conv-source-1"]);
101
+ expect(item).not.toBeNull();
102
+ expect(appendCalls).toHaveLength(1);
103
+ const appended = appendCalls[0]!;
104
+ expect(appended.id).toBe("notif:sig-test-1");
105
+ expect(appended.type).toBe("notification");
106
+ // v2 dropped source/author — the side effect must construct items
107
+ // without those fields.
108
+ expect((appended as { source?: unknown }).source).toBeUndefined();
109
+ expect((appended as { author?: unknown }).author).toBeUndefined();
110
+ expect(appended.priority).toBe(50);
111
+ expect(appended.status).toBe("new");
112
+ expect(appended.title).toBe("Background job done");
113
+ expect(appended.summary).toBe("Summary of what happened.");
114
+ expect(appended.urgency).toBe("medium");
115
+ expect(typeof appended.timestamp).toBe("string");
116
+ expect(appended.createdAt).toBe(appended.timestamp);
117
+ });
118
+
119
+ test("non-background conversation with no async hint returns null and does not write", async () => {
120
+ conversationRow = { conversationType: "standard" };
121
+ const signal = makeSignal({
122
+ attentionHints: {
123
+ requiresAction: false,
124
+ urgency: "low",
125
+ isAsyncBackground: false,
126
+ visibleInSourceNow: true,
127
+ },
128
+ });
129
+
130
+ const item = await writeHomeFeedItemForSignal(signal, makeDecision(), []);
131
+
132
+ expect(item).toBeNull();
133
+ expect(appendCalls).toHaveLength(0);
134
+ });
135
+
136
+ test("isAsyncBackground hint writes even when sourceContextId does not resolve", async () => {
137
+ // No conversation row matches; the conversation lookup is bypassed
138
+ // entirely because the hint short-circuits the filter.
139
+ conversationLookupShouldThrow = true;
140
+ const signal = makeSignal({
141
+ sourceContextId: "not-a-conversation-id",
142
+ attentionHints: {
143
+ requiresAction: false,
144
+ urgency: "high",
145
+ isAsyncBackground: true,
146
+ visibleInSourceNow: false,
147
+ },
148
+ });
149
+
150
+ const item = await writeHomeFeedItemForSignal(signal, makeDecision(), []);
151
+
152
+ expect(item).not.toBeNull();
153
+ expect(appendCalls).toHaveLength(1);
154
+ expect(appendCalls[0]!.urgency).toBe("high");
155
+ // The async-background short-circuit must not consult the conversation store.
156
+ expect(conversationLookups).toHaveLength(0);
157
+ });
158
+
159
+ test("vellum delivery result conversationId propagates onto the feed item", async () => {
160
+ conversationRow = { conversationType: "background" };
161
+ const signal = makeSignal();
162
+ const deliveryResults: NotificationDeliveryResult[] = [
163
+ {
164
+ channel: "telegram",
165
+ destination: "chat-1",
166
+ status: "sent",
167
+ conversationId: "conv-telegram-1",
168
+ },
169
+ {
170
+ channel: "vellum",
171
+ destination: "vellum-client",
172
+ status: "sent",
173
+ conversationId: "conv-vellum-1",
174
+ },
175
+ ];
176
+
177
+ const item = await writeHomeFeedItemForSignal(
178
+ signal,
179
+ makeDecision(),
180
+ deliveryResults,
181
+ );
182
+
183
+ expect(item?.conversationId).toBe("conv-vellum-1");
184
+ expect(appendCalls[0]!.conversationId).toBe("conv-vellum-1");
185
+ });
186
+
187
+ test("falls back to sourceEventName when no rendered copy or payload title is present", async () => {
188
+ conversationRow = { conversationType: "scheduled" };
189
+ const signal = makeSignal({
190
+ sourceEventName: "watcher.notification",
191
+ contextPayload: {},
192
+ });
193
+
194
+ const item = await writeHomeFeedItemForSignal(signal, makeDecision(), []);
195
+
196
+ expect(item?.title).toBe("watcher.notification");
197
+ expect(item?.summary).toBe("watcher.notification");
198
+ });
199
+ });
@@ -0,0 +1,17 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import { NOTIFICATION_SOURCE_EVENT_NAMES } from "../signal.js";
4
+
5
+ describe("NOTIFICATION_SOURCE_EVENT_NAMES", () => {
6
+ test("includes activity.failed", () => {
7
+ expect(
8
+ NOTIFICATION_SOURCE_EVENT_NAMES.some((e) => e.id === "activity.failed"),
9
+ ).toBe(true);
10
+ });
11
+
12
+ test("still includes activity.complete (regression guard)", () => {
13
+ expect(
14
+ NOTIFICATION_SOURCE_EVENT_NAMES.some((e) => e.id === "activity.complete"),
15
+ ).toBe(true);
16
+ });
17
+ });
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Platform push adapter — delivers notifications to iOS/web clients via
3
+ * the platform's APNs dispatch endpoint.
4
+ *
5
+ * POSTs a `notification_intent` payload to
6
+ * `/v1/assistants/{id}/push/dispatch/`. The platform endpoint fans the
7
+ * notification out to all registered device tokens for the bound user and
8
+ * gates on the `ios-remote-push-enabled` LD flag server-side (returning 202
9
+ * with `{ skipped: "flag_off" }` when the flag is OFF — no action needed
10
+ * from the daemon).
11
+ *
12
+ * Guardian-sensitive notifications (approval requests, escalation alerts)
13
+ * are annotated with `targetGuardianPrincipalId` so the platform can
14
+ * scope APNs fan-out to guardian-bound devices, mirroring the macOS adapter.
15
+ */
16
+
17
+ import { VellumPlatformClient } from "../../platform/client.js";
18
+ import { getLogger } from "../../util/logger.js";
19
+ import {
20
+ isRetryableNetworkError,
21
+ isRetryableStatus,
22
+ sleep,
23
+ } from "../../util/retry.js";
24
+ import type {
25
+ ChannelAdapter,
26
+ ChannelDeliveryPayload,
27
+ ChannelDestination,
28
+ DeliveryResult,
29
+ NotificationChannel,
30
+ } from "../types.js";
31
+ import { isGuardianSensitiveEvent } from "./macos.js";
32
+
33
+ const log = getLogger("notif-adapter-platform");
34
+
35
+ // Exponential backoff delays for 5xx/timeout retries: 250ms → 1s → 4s
36
+ const RETRY_DELAYS_MS = [250, 1_000, 4_000] as const;
37
+
38
+ interface DispatchBody {
39
+ delivery_id?: string;
40
+ source_event_name: string;
41
+ title: string;
42
+ body: string;
43
+ deep_link_metadata?: Record<string, unknown>;
44
+ context_payload?: Record<string, unknown>;
45
+ target_guardian_principal_id?: string;
46
+ }
47
+
48
+ export class PlatformPushAdapter implements ChannelAdapter {
49
+ readonly channel: NotificationChannel = "platform";
50
+
51
+ async send(
52
+ payload: ChannelDeliveryPayload,
53
+ destination: ChannelDestination,
54
+ ): Promise<DeliveryResult> {
55
+ const client = await VellumPlatformClient.create();
56
+ if (!client) {
57
+ log.warn(
58
+ { sourceEventName: payload.sourceEventName },
59
+ "Platform client unavailable — skipping push dispatch",
60
+ );
61
+ return { success: false, error: "platform client unavailable" };
62
+ }
63
+
64
+ if (!client.platformAssistantId) {
65
+ log.warn(
66
+ { sourceEventName: payload.sourceEventName },
67
+ "Platform assistant ID not configured — skipping push dispatch",
68
+ );
69
+ return { success: false, error: "platform assistant ID not configured" };
70
+ }
71
+
72
+ const guardianPrincipalId =
73
+ typeof destination.metadata?.guardianPrincipalId === "string"
74
+ ? destination.metadata.guardianPrincipalId
75
+ : undefined;
76
+
77
+ const targetGuardianPrincipalId =
78
+ guardianPrincipalId &&
79
+ isGuardianSensitiveEvent(payload.sourceEventName)
80
+ ? guardianPrincipalId
81
+ : undefined;
82
+
83
+ const body: DispatchBody = {
84
+ delivery_id: payload.deliveryId,
85
+ source_event_name: payload.sourceEventName,
86
+ title: payload.copy.title,
87
+ body: payload.copy.body,
88
+ deep_link_metadata: payload.deepLinkTarget,
89
+ context_payload: payload.contextPayload,
90
+ target_guardian_principal_id: targetGuardianPrincipalId,
91
+ };
92
+
93
+ const path = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/push/dispatch/`;
94
+
95
+ for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
96
+ let response: Response;
97
+ try {
98
+ response = await client.fetch(path, {
99
+ method: "POST",
100
+ headers: { "Content-Type": "application/json" },
101
+ body: JSON.stringify(body),
102
+ });
103
+ } catch (err) {
104
+ if (
105
+ attempt < RETRY_DELAYS_MS.length &&
106
+ isRetryableNetworkError(err)
107
+ ) {
108
+ log.warn(
109
+ {
110
+ attempt,
111
+ sourceEventName: payload.sourceEventName,
112
+ err: err instanceof Error ? err.message : String(err),
113
+ },
114
+ "Network error dispatching push — retrying",
115
+ );
116
+ await sleep(RETRY_DELAYS_MS[attempt]!);
117
+ continue;
118
+ }
119
+ const message = err instanceof Error ? err.message : String(err);
120
+ log.error(
121
+ { attempt, sourceEventName: payload.sourceEventName, err },
122
+ "Failed to dispatch platform push notification",
123
+ );
124
+ return { success: false, error: message };
125
+ }
126
+
127
+ if (response.ok) {
128
+ log.info(
129
+ {
130
+ sourceEventName: payload.sourceEventName,
131
+ title: payload.copy.title,
132
+ guardianScoped: targetGuardianPrincipalId != null,
133
+ status: response.status,
134
+ },
135
+ "Platform push dispatched",
136
+ );
137
+ return { success: true };
138
+ }
139
+
140
+ if (attempt < RETRY_DELAYS_MS.length && isRetryableStatus(response.status)) {
141
+ log.warn(
142
+ {
143
+ attempt,
144
+ status: response.status,
145
+ sourceEventName: payload.sourceEventName,
146
+ },
147
+ "Retryable status from push dispatch endpoint",
148
+ );
149
+ await sleep(RETRY_DELAYS_MS[attempt]!);
150
+ continue;
151
+ }
152
+
153
+ const errorText = await response.text().catch(() => "");
154
+ log.error(
155
+ {
156
+ status: response.status,
157
+ sourceEventName: payload.sourceEventName,
158
+ body: errorText.slice(0, 256),
159
+ },
160
+ "Non-retryable error from push dispatch endpoint",
161
+ );
162
+ return {
163
+ success: false,
164
+ error: `HTTP ${response.status}: ${errorText.slice(0, 128)}`,
165
+ };
166
+ }
167
+
168
+ // Unreachable — loop always returns or continues, but TypeScript needs this.
169
+ return { success: false, error: "retry exhausted" };
170
+ }
171
+ }
@@ -103,11 +103,11 @@ export async function pairDeliveryWithConversation(
103
103
  try {
104
104
  const strategy = getConversationStrategy(channel as ChannelId);
105
105
 
106
- if (strategy === "not_deliverable") {
106
+ if (strategy === "not_deliverable" || strategy === "push_only") {
107
107
  return {
108
108
  conversationId: null,
109
109
  messageId: null,
110
- strategy: "not_deliverable",
110
+ strategy,
111
111
  createdNewConversation: false,
112
112
  conversationFallbackUsed: false,
113
113
  };
@@ -562,6 +562,21 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
562
562
  body: str(payload.summary, "An activity has completed"),
563
563
  }),
564
564
 
565
+ "activity.failed": (payload) => {
566
+ const jobName = str(payload.jobName, "background job");
567
+ const errorKind = str(payload.errorKind, "exception");
568
+ const rawMessage =
569
+ typeof payload.errorMessage === "string"
570
+ ? payload.errorMessage
571
+ : "no message";
572
+ const truncated =
573
+ rawMessage.length > 200 ? rawMessage.slice(0, 200) + "…" : rawMessage;
574
+ return {
575
+ title: `Background job failed: ${jobName}`,
576
+ body: `${errorKind}: ${truncated}`,
577
+ };
578
+ },
579
+
565
580
  "quick_chat.response_ready": (payload) => ({
566
581
  title: "Response Ready",
567
582
  body: str(payload.preview, "Your quick chat response is ready"),
@@ -126,6 +126,27 @@ export function resolveDestinations(
126
126
  );
127
127
  break;
128
128
  }
129
+ case "platform": {
130
+ // Platform delivery goes through the daemon's VellumPlatformClient —
131
+ // no external binding needed. Include guardianPrincipalId so the
132
+ // adapter can scope guardian-sensitive notifications.
133
+ const platformGuardian = findGuardianForChannel("vellum");
134
+ const platformMeta: Record<string, unknown> = {};
135
+ if (platformGuardian) {
136
+ platformMeta.guardianPrincipalId =
137
+ platformGuardian.contact.principalId;
138
+ }
139
+ result.set("platform", {
140
+ channel: "platform",
141
+ metadata:
142
+ Object.keys(platformMeta).length > 0 ? platformMeta : undefined,
143
+ });
144
+ log.debug(
145
+ { channel: "platform", source: "contacts", hasEndpoint: false },
146
+ "destination resolved",
147
+ );
148
+ break;
149
+ }
129
150
  default: {
130
151
  // Future deliverable channels without a resolver — skip silently.
131
152
  break;
@@ -15,6 +15,7 @@ import { getDeliverableChannels } from "../channels/config.js";
15
15
  import { findGuardianForChannel } from "../contacts/contact-store.js";
16
16
  import { getLogger } from "../util/logger.js";
17
17
  import { type BroadcastFn, VellumAdapter } from "./adapters/macos.js";
18
+ import { PlatformPushAdapter } from "./adapters/platform.js";
18
19
  import { SlackAdapter } from "./adapters/slack.js";
19
20
  import { TelegramAdapter } from "./adapters/telegram.js";
20
21
  import {
@@ -28,6 +29,7 @@ import {
28
29
  runDeterministicChecks,
29
30
  } from "./deterministic-checks.js";
30
31
  import { createEvent, updateEventDedupeKey } from "./events-store.js";
32
+ import { writeHomeFeedItemForSignal } from "./home-feed-side-effect.js";
31
33
  import { dispatchDecision } from "./runtime-dispatch.js";
32
34
  import type {
33
35
  AttentionHints,
@@ -61,7 +63,11 @@ export function registerBroadcastFn(fn: BroadcastFn): void {
61
63
 
62
64
  function getBroadcaster(): NotificationBroadcaster {
63
65
  if (!broadcasterInstance) {
64
- const adapters = [new TelegramAdapter(), new SlackAdapter()];
66
+ const adapters = [
67
+ new TelegramAdapter(),
68
+ new SlackAdapter(),
69
+ new PlatformPushAdapter(),
70
+ ];
65
71
  if (registeredBroadcastFn) {
66
72
  adapters.unshift(new VellumAdapter(registeredBroadcastFn));
67
73
  }
@@ -110,6 +116,16 @@ function getConnectedChannels(): NotificationChannel[] {
110
116
  // always available when the daemon is running).
111
117
  channels.push(channel);
112
118
  break;
119
+ case "platform":
120
+ // Platform push is connected when the daemon has a registered
121
+ // broadcast function — i.e., full daemon mode where platform
122
+ // credentials are also available. Mirrors the vellum gate so
123
+ // the decision engine doesn't route to platform in standalone
124
+ // CLI contexts where VellumPlatformClient.create() returns null.
125
+ if (registeredBroadcastFn) {
126
+ channels.push(channel);
127
+ }
128
+ break;
113
129
  case "telegram": {
114
130
  // A binding-based channel is connected when the guardian has an
115
131
  // active channel entry with a valid delivery endpoint. The
@@ -349,6 +365,17 @@ export async function emitNotificationSignal<TEventName extends string>(
349
365
  : undefined,
350
366
  );
351
367
 
368
+ // Step 5: Mirror background-origin signals into the home activity feed.
369
+ // The helper itself decides whether to write (background filter); we
370
+ // catch and log so a feed-write failure cannot poison the dispatch result.
371
+ await writeHomeFeedItemForSignal(
372
+ signal,
373
+ decision,
374
+ dispatchResult.deliveryResults,
375
+ ).catch((err) => {
376
+ log.warn({ err, signalId }, "writeHomeFeedItemForSignal threw");
377
+ });
378
+
352
379
  log.info(
353
380
  {
354
381
  signalId,