@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
@@ -17,8 +17,42 @@ const log = getLogger("web-search");
17
17
 
18
18
  const BRAVE_API_URL = "https://api.search.brave.com/res/v1/web/search";
19
19
  const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
20
+ const TAVILY_API_URL = "https://api.tavily.com/search";
21
+
22
+ type WebSearchProvider = "perplexity" | "brave" | "tavily";
23
+
24
+ /**
25
+ * Arguments passed to every {@link WebSearchAdapter}. The full superset is
26
+ * always supplied; individual adapters ignore the fields they don't use
27
+ * (e.g. Perplexity ignores `count`, `offset`, and `freshness`).
28
+ */
29
+ interface WebSearchAdapterArgs {
30
+ query: string;
31
+ count: number;
32
+ offset: number;
33
+ freshness: string | undefined;
34
+ apiKey: string;
35
+ signal?: AbortSignal;
36
+ }
20
37
 
21
- type WebSearchProvider = "perplexity" | "brave";
38
+ /**
39
+ * One built-in web-search provider. Each adapter owns its HTTP shape,
40
+ * freshness mapping, retry behaviour, and result formatter. Registering a
41
+ * new provider becomes a single entry in {@link WEB_SEARCH_ADAPTERS}.
42
+ */
43
+ interface WebSearchAdapter {
44
+ /** Stable provider identifier (matches config + secret-catalog values). */
45
+ readonly id: WebSearchProvider;
46
+ /** Secret-catalog key used to look up the API key via `getProviderKeyAsync`. */
47
+ readonly secretKey: string;
48
+ /**
49
+ * Position in the fallback chain (lower = earlier). Used when the
50
+ * configured provider has no key and we try other BYOK providers.
51
+ */
52
+ readonly fallbackOrder: number;
53
+ /** Execute one search against the provider's API. */
54
+ execute(args: WebSearchAdapterArgs): Promise<ToolExecutionResult>;
55
+ }
22
56
 
23
57
  interface BraveSearchResult {
24
58
  title: string;
@@ -42,6 +76,20 @@ interface PerplexityResponse {
42
76
  citations?: string[];
43
77
  }
44
78
 
79
+ interface TavilySearchResult {
80
+ title?: string;
81
+ url?: string;
82
+ content?: string;
83
+ score?: number;
84
+ raw_content?: string | null;
85
+ favicon?: string;
86
+ }
87
+
88
+ interface TavilySearchResponse {
89
+ query?: string;
90
+ results?: TavilySearchResult[];
91
+ }
92
+
45
93
  function getWebSearchProvider(): WebSearchProvider {
46
94
  const config = getConfig();
47
95
  const configured = config.services["web-search"].provider ?? "perplexity";
@@ -54,12 +102,16 @@ function getWebSearchProvider(): WebSearchProvider {
54
102
  async function getApiKey(
55
103
  provider: WebSearchProvider,
56
104
  ): Promise<string | undefined> {
57
- if (provider === "brave") {
58
- return (await getProviderKeyAsync("brave")) ?? undefined;
59
- }
105
+ const adapter = WEB_SEARCH_ADAPTERS[provider];
106
+ return (await getProviderKeyAsync(adapter.secretKey)) ?? undefined;
107
+ }
60
108
 
61
- // Perplexity
62
- return (await getProviderKeyAsync("perplexity")) ?? undefined;
109
+ function fallbackProvidersFor(
110
+ provider: WebSearchProvider,
111
+ ): readonly WebSearchProvider[] {
112
+ return WEB_SEARCH_FALLBACK_ORDER.filter(
113
+ (candidate) => candidate !== provider,
114
+ );
63
115
  }
64
116
 
65
117
  const CITATION_INSTRUCTION =
@@ -118,6 +170,54 @@ function formatPerplexityResults(
118
170
  return lines.join("\n");
119
171
  }
120
172
 
173
+ function formatTavilyResults(
174
+ data: TavilySearchResponse,
175
+ query: string,
176
+ ): string {
177
+ const results = data.results ?? [];
178
+
179
+ if (results.length === 0) {
180
+ return `No results found for "${query}".`;
181
+ }
182
+
183
+ const lines: string[] = [`Web search results for "${query}":\n`];
184
+
185
+ for (let i = 0; i < results.length; i++) {
186
+ const r = results[i];
187
+ const title = r.title?.trim() || r.url?.trim() || "Untitled result";
188
+ lines.push(`${i + 1}. ${title}`);
189
+ if (r.url) {
190
+ lines.push(` URL: ${r.url}`);
191
+ }
192
+ if (r.content) {
193
+ lines.push(` ${r.content}`);
194
+ }
195
+ if (typeof r.score === "number") {
196
+ lines.push(` Score: ${r.score.toFixed(3)}`);
197
+ }
198
+ lines.push("");
199
+ }
200
+
201
+ return lines.join("\n");
202
+ }
203
+
204
+ function tavilyTimeRangeForFreshness(
205
+ freshness: string | undefined,
206
+ ): "day" | "week" | "month" | "year" | undefined {
207
+ switch (freshness) {
208
+ case "pd":
209
+ return "day";
210
+ case "pw":
211
+ return "week";
212
+ case "pm":
213
+ return "month";
214
+ case "py":
215
+ return "year";
216
+ default:
217
+ return undefined;
218
+ }
219
+ }
220
+
121
221
  async function executeBraveSearch(
122
222
  query: string,
123
223
  count: number,
@@ -281,6 +381,147 @@ async function executePerplexitySearch(
281
381
  };
282
382
  }
283
383
 
384
+ async function executeTavilySearch(
385
+ query: string,
386
+ count: number,
387
+ freshness: string | undefined,
388
+ apiKey: string,
389
+ signal?: AbortSignal,
390
+ ): Promise<ToolExecutionResult> {
391
+ const timeRange = tavilyTimeRangeForFreshness(freshness);
392
+ const body: Record<string, unknown> = {
393
+ query,
394
+ search_depth: "advanced",
395
+ max_results: count,
396
+ };
397
+ if (timeRange) {
398
+ body.time_range = timeRange;
399
+ }
400
+
401
+ for (let attempt = 0; attempt <= DEFAULT_MAX_RETRIES; attempt++) {
402
+ const response = await fetch(TAVILY_API_URL, {
403
+ method: "POST",
404
+ headers: {
405
+ "Content-Type": "application/json",
406
+ Authorization: `Bearer ${apiKey}`,
407
+ "X-Client-Source": "vellum-assistant",
408
+ },
409
+ body: JSON.stringify(body),
410
+ signal,
411
+ });
412
+
413
+ if (response.ok) {
414
+ const data = (await response.json()) as TavilySearchResponse;
415
+ return {
416
+ content:
417
+ wrapUntrustedContent(formatTavilyResults(data, query), {
418
+ source: "search",
419
+ sourceDetail: "tavily",
420
+ }) + CITATION_INSTRUCTION,
421
+ isError: false,
422
+ };
423
+ }
424
+
425
+ await response.text();
426
+
427
+ if (response.status === 401 || response.status === 403) {
428
+ return {
429
+ content: "Error: Invalid or expired Tavily API key",
430
+ isError: true,
431
+ };
432
+ }
433
+
434
+ if (response.status === 429 && attempt < DEFAULT_MAX_RETRIES) {
435
+ const delayMs = getHttpRetryDelay(
436
+ response,
437
+ attempt,
438
+ DEFAULT_BASE_DELAY_MS,
439
+ );
440
+ log.warn(
441
+ { attempt: attempt + 1, delayMs },
442
+ "Tavily Search rate limited, retrying",
443
+ );
444
+ await sleep(delayMs);
445
+ continue;
446
+ }
447
+
448
+ log.warn({ status: response.status }, "Tavily Search API error");
449
+ if (response.status === 429) {
450
+ return {
451
+ content:
452
+ "Error: Tavily Search rate limit exceeded after retries. Try again shortly.",
453
+ isError: true,
454
+ };
455
+ }
456
+ return {
457
+ content: `Error: Tavily Search API returned status ${response.status}`,
458
+ isError: true,
459
+ };
460
+ }
461
+
462
+ return {
463
+ content:
464
+ "Error: Tavily Search rate limit exceeded after retries. Try again shortly.",
465
+ isError: true,
466
+ };
467
+ }
468
+
469
+ // ----------------------------------------------------------------------------
470
+ // Adapter registry
471
+ //
472
+ // Each built-in provider exposes a {@link WebSearchAdapter} wrapping its
473
+ // existing execute function. Adding a new provider means adding one adapter
474
+ // const and one entry to `WEB_SEARCH_ADAPTERS` — the dispatcher, fallback
475
+ // chain, and api-key lookup all derive from this table.
476
+ // ----------------------------------------------------------------------------
477
+
478
+ const perplexitySearchAdapter: WebSearchAdapter = {
479
+ id: "perplexity",
480
+ secretKey: "perplexity",
481
+ fallbackOrder: 1,
482
+ execute: ({ query, apiKey, signal }) =>
483
+ executePerplexitySearch(query, apiKey, signal),
484
+ };
485
+
486
+ const braveSearchAdapter: WebSearchAdapter = {
487
+ id: "brave",
488
+ secretKey: "brave",
489
+ fallbackOrder: 2,
490
+ execute: ({ query, count, offset, freshness, apiKey, signal }) =>
491
+ executeBraveSearch(query, count, offset, freshness, apiKey, signal),
492
+ };
493
+
494
+ const tavilySearchAdapter: WebSearchAdapter = {
495
+ id: "tavily",
496
+ secretKey: "tavily",
497
+ fallbackOrder: 3,
498
+ execute: ({ query, count, freshness, apiKey, signal }) =>
499
+ executeTavilySearch(query, count, freshness, apiKey, signal),
500
+ };
501
+
502
+ /**
503
+ * All built-in web-search adapters keyed by provider id. The
504
+ * `Record<WebSearchProvider, ...>` shape forces TypeScript to flag any
505
+ * provider added to the union without a corresponding adapter.
506
+ */
507
+ const WEB_SEARCH_ADAPTERS: Record<WebSearchProvider, WebSearchAdapter> = {
508
+ perplexity: perplexitySearchAdapter,
509
+ brave: braveSearchAdapter,
510
+ tavily: tavilySearchAdapter,
511
+ };
512
+
513
+ /**
514
+ * Fallback chain derived from {@link WEB_SEARCH_ADAPTERS}. Sorted by each
515
+ * adapter's `fallbackOrder` (lower first). Used when the configured provider
516
+ * has no API key and we try other BYOK providers before giving up.
517
+ */
518
+ const WEB_SEARCH_FALLBACK_ORDER: readonly WebSearchProvider[] = Object.values(
519
+ WEB_SEARCH_ADAPTERS,
520
+ )
521
+ .slice()
522
+ .sort((a, b) => a.fallbackOrder - b.fallbackOrder)
523
+ .map((adapter) => adapter.id);
524
+
284
525
  class WebSearchTool implements Tool {
285
526
  name = "web_search";
286
527
  description =
@@ -302,7 +543,7 @@ class WebSearchTool implements Tool {
302
543
  count: {
303
544
  type: "number",
304
545
  description:
305
- "Number of results to return (1-20, default 10). Only used with Brave provider.",
546
+ "Number of results to return (1-20, default 10). Used with Brave and Tavily providers.",
306
547
  },
307
548
  offset: {
308
549
  type: "number",
@@ -312,7 +553,7 @@ class WebSearchTool implements Tool {
312
553
  freshness: {
313
554
  type: "string",
314
555
  description:
315
- 'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Only used with Brave provider.',
556
+ 'Filter by recency: "pd" (past day), "pw" (past week), "pm" (past month), "py" (past year). Used with Brave and Tavily providers.',
316
557
  },
317
558
  },
318
559
  required: ["query"],
@@ -335,22 +576,27 @@ class WebSearchTool implements Tool {
335
576
  let provider = getWebSearchProvider();
336
577
  let apiKey = await getApiKey(provider);
337
578
 
338
- // Fallback: if the configured provider has no key, try the other provider
579
+ // Fallback: if the configured provider has no key, try other BYOK search
580
+ // providers in a stable order. This preserves existing installs that only
581
+ // configured one search-provider key while still allowing new providers to
582
+ // be selected explicitly.
339
583
  if (!apiKey) {
340
- const fallback: WebSearchProvider =
341
- provider === "perplexity" ? "brave" : "perplexity";
342
- const fallbackKey = await getApiKey(fallback);
343
- if (fallbackKey) {
584
+ for (const fallback of fallbackProvidersFor(provider)) {
585
+ const fallbackKey = await getApiKey(fallback);
586
+ if (!fallbackKey) continue;
344
587
  log.info(
345
588
  { from: provider, to: fallback },
346
589
  "Configured web search provider has no API key, falling back",
347
590
  );
348
591
  provider = fallback;
349
592
  apiKey = fallbackKey;
350
- } else {
593
+ break;
594
+ }
595
+
596
+ if (!apiKey) {
351
597
  return {
352
598
  content:
353
- "Error: No web search API key configured. Set it via `keys set perplexity <key>` or `keys set brave <key>`, or configure it from the Settings page under API Keys.",
599
+ "Error: No web search API key configured. Set it via `keys set perplexity <key>`, `keys set brave <key>`, or `keys set tavily <key>`, or configure it from the Settings page under API Keys.",
354
600
  isError: true,
355
601
  };
356
602
  }
@@ -359,28 +605,25 @@ class WebSearchTool implements Tool {
359
605
  try {
360
606
  log.debug({ query, provider }, "Executing web search");
361
607
 
362
- if (provider === "brave") {
363
- const count =
364
- typeof input.count === "number"
365
- ? Math.min(20, Math.max(1, Math.round(input.count)))
366
- : 10;
367
- const offset =
368
- typeof input.offset === "number"
369
- ? Math.min(9, Math.max(0, Math.round(input.offset)))
370
- : 0;
371
- const freshness =
372
- typeof input.freshness === "string" ? input.freshness : undefined;
373
- return await executeBraveSearch(
374
- query,
375
- count,
376
- offset,
377
- freshness,
378
- apiKey,
379
- context.signal,
380
- );
381
- }
382
-
383
- return await executePerplexitySearch(query, apiKey, context.signal);
608
+ const count =
609
+ typeof input.count === "number"
610
+ ? Math.min(20, Math.max(1, Math.round(input.count)))
611
+ : 10;
612
+ const offset =
613
+ typeof input.offset === "number"
614
+ ? Math.min(9, Math.max(0, Math.round(input.offset)))
615
+ : 0;
616
+ const freshness =
617
+ typeof input.freshness === "string" ? input.freshness : undefined;
618
+
619
+ return await WEB_SEARCH_ADAPTERS[provider].execute({
620
+ query,
621
+ count,
622
+ offset,
623
+ freshness,
624
+ apiKey,
625
+ signal: context.signal,
626
+ });
384
627
  } catch (err) {
385
628
  const msg = err instanceof Error ? err.message : String(err);
386
629
  log.error({ err }, "Web search failed");
@@ -9,7 +9,11 @@ import {
9
9
  } from "../permissions/checker.js";
10
10
  import { getAutoApproveThreshold } from "../permissions/gateway-threshold-reader.js";
11
11
  import type { PermissionPrompter } from "../permissions/prompter.js";
12
- import type { ApprovalMode, ApprovalReason, RiskThreshold } from "../permissions/types.js";
12
+ import type {
13
+ ApprovalMode,
14
+ ApprovalReason,
15
+ RiskThreshold,
16
+ } from "../permissions/types.js";
13
17
  import { RiskLevel } from "../permissions/types.js";
14
18
  import { getLogger } from "../util/logger.js";
15
19
  import { buildPolicyContext } from "./policy-context.js";
@@ -32,6 +36,11 @@ export type PermissionDecision =
32
36
  riskLevel: string;
33
37
  riskReason: string;
34
38
  riskScopeOptions: Array<{ pattern: string; label: string }>;
39
+ riskAllowlistOptions?: Array<{
40
+ label: string;
41
+ description: string;
42
+ pattern: string;
43
+ }>;
35
44
  riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
36
45
  isContainerized?: boolean;
37
46
  };
@@ -51,6 +60,11 @@ export type PermissionDecision =
51
60
  riskLevel: string;
52
61
  riskReason: string;
53
62
  riskScopeOptions: Array<{ pattern: string; label: string }>;
63
+ riskAllowlistOptions?: Array<{
64
+ label: string;
65
+ description: string;
66
+ pattern: string;
67
+ }>;
54
68
  riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
55
69
  isContainerized?: boolean;
56
70
  };
@@ -111,7 +125,12 @@ export class PermissionChecker {
111
125
  ? {
112
126
  riskLevel: cachedAssessment.riskLevel,
113
127
  riskReason: cachedAssessment.reason,
128
+ // Display ladder (regex patterns — internal only, not for save).
114
129
  riskScopeOptions: cachedAssessment.scopeOptions,
130
+ // Save ladder (Minimatch globs — what the gateway matches against).
131
+ // Populated for classifiers that produce allowlist options
132
+ // (bash, file, skill); undefined otherwise.
133
+ riskAllowlistOptions: cachedAssessment.allowlistOptions,
115
134
  riskDirectoryScopeOptions: cachedAssessment.directoryScopeOptions,
116
135
  isContainerized: getIsContainerized(),
117
136
  }
@@ -145,9 +164,11 @@ export class PermissionChecker {
145
164
  );
146
165
  const riskThreshold = conversationThreshold as RiskThreshold;
147
166
 
148
- // Some callers force prompting for side-effect tools even when a
149
- // trust/allow rule would auto-allow. Deny decisions are preserved -
150
- // only allow prompt promotion happens here.
167
+ // Non-interactive callers (e.g. non-guardian phone voice) force
168
+ // prompting for side-effect tools even when a trust/allow rule would
169
+ // auto-allow, so their auto-deny handler always sees a
170
+ // confirmation_request. Deny decisions are preserved — only
171
+ // allow → prompt promotion happens here.
151
172
  if (
152
173
  context.forcePromptSideEffects &&
153
174
  result.decision === "allow" &&
@@ -185,7 +206,9 @@ export class PermissionChecker {
185
206
  reason: result.reason,
186
207
  durationMs,
187
208
  });
188
- const provenance = mapApprovalProvenance("denied", { matchedTrustRuleId });
209
+ const provenance = mapApprovalProvenance("denied", {
210
+ matchedTrustRuleId,
211
+ });
189
212
  return {
190
213
  allowed: false,
191
214
  decision: "denied",
@@ -19,7 +19,7 @@ import {
19
19
  import {
20
20
  collectAllMissing,
21
21
  indexCatalogById,
22
- validateIncludes,
22
+ validateIncludeCycles,
23
23
  } from "../../skills/include-graph.js";
24
24
  import { renderInlineCommands } from "../../skills/inline-command-render.js";
25
25
  import { parseToolManifestFile } from "../../skills/tool-manifest.js";
@@ -204,6 +204,7 @@ export class SkillLoadTool implements Tool {
204
204
 
205
205
  // Load catalog for include validation and child metadata output
206
206
  let catalogIndex: Map<string, SkillSummary> | undefined;
207
+ let missingIncludedSkillIds: string[] = [];
207
208
  if (skill.includes && skill.includes.length > 0) {
208
209
  let catalog = loadSkillCatalog();
209
210
  catalogIndex = indexCatalogById(catalog);
@@ -260,19 +261,13 @@ export class SkillLoadTool implements Tool {
260
261
  catalogIndex = indexCatalogById(catalog);
261
262
  }
262
263
 
263
- // Validate (fail-closed - catches genuinely missing deps + cycles)
264
- const validation = validateIncludes(skill.id, catalogIndex);
264
+ missingIncludedSkillIds = [...collectAllMissing(skill.id, catalogIndex)];
265
+
266
+ // Validate cycles fail closed. Missing includes are advisory: the parent
267
+ // skill should still load so the assistant can decide whether to search
268
+ // for and install the suggested dependency.
269
+ const validation = validateIncludeCycles(skill.id, catalogIndex);
265
270
  if (!validation.ok) {
266
- if (validation.error === "missing") {
267
- return {
268
- content: `Error: skill "${skill.id}" includes "${
269
- validation.missingChildId
270
- }" which was not found (referenced by "${
271
- validation.parentId
272
- }" via path: ${validation.path.join(" → ")})`,
273
- isError: true,
274
- };
275
- }
276
271
  if (validation.error === "cycle") {
277
272
  return {
278
273
  content: `Error: skill "${
@@ -283,10 +278,6 @@ export class SkillLoadTool implements Tool {
283
278
  isError: true,
284
279
  };
285
280
  }
286
- return {
287
- content: `Error: skill "${skill.id}" has an invalid include graph`,
288
- isError: true,
289
- };
290
281
  }
291
282
  }
292
283
 
@@ -444,13 +435,25 @@ export class SkillLoadTool implements Tool {
444
435
  }
445
436
  }
446
437
  }
447
- immediateChildrenSection = `Included Skills (immediate):\n${childLines.join(
448
- "\n",
449
- )}`;
438
+ immediateChildrenSection =
439
+ childLines.length > 0
440
+ ? `Included Skills (immediate):\n${childLines.join("\n")}`
441
+ : "Included Skills (immediate): none";
450
442
  } else {
451
443
  immediateChildrenSection = "Included Skills (immediate): none";
452
444
  }
453
445
 
446
+ const missingIncludesSection =
447
+ missingIncludedSkillIds.length > 0
448
+ ? [
449
+ "Suggested Included Skills (not loaded):",
450
+ ...missingIncludedSkillIds.map(
451
+ (id) =>
452
+ ` - ${id}: not installed or unavailable. If this task needs it, search for and install this skill, then load it.`,
453
+ ),
454
+ ].join("\n")
455
+ : undefined;
456
+
454
457
  let versionHash: string | undefined;
455
458
  try {
456
459
  versionHash = computeSkillVersionHash(skill.directoryPath);
@@ -512,6 +515,7 @@ export class SkillLoadTool implements Tool {
512
515
  : []),
513
516
  ...includedBodies.flatMap((b) => [b, ""]),
514
517
  immediateChildrenSection,
518
+ ...(missingIncludesSection ? [missingIncludesSection] : []),
515
519
  "",
516
520
  `<loaded_skill id="${skill.id}"${versionAttr} />`,
517
521
  ...includeMarkers,
@@ -71,9 +71,9 @@ export async function executeSubagentSpawn(
71
71
 
72
72
  // The subagent runs as its own background conversation, so the agent
73
73
  // loop's background-skip rule would zero out any inherited profile.
74
- // Pass the parent's profile explicitly via `SubagentConfig` so the
75
- // PR 6 plumbing in `SubagentManager.spawn` forwards it back into the
76
- // subagent's `runAgentLoop` call as `options.overrideProfile`.
74
+ // Pass the parent's profile explicitly via `SubagentConfig` so
75
+ // `SubagentManager.spawn` forwards it back into the subagent's
76
+ // `runAgentLoop` call as `options.overrideProfile`.
77
77
  //
78
78
  // Prefer the per-turn `context.overrideProfile` (populated by
79
79
  // `runAgentLoopImpl` from its resolved `turnOverrideProfile`) over a
@@ -17,7 +17,9 @@ import {
17
17
  registerBackgroundTool,
18
18
  removeBackgroundTool,
19
19
  } from "../background-tool-registry.js";
20
+ import { getCredentialMetadataById } from "../credentials/metadata-store.js";
20
21
  import { resolveCredentialRef } from "../credentials/resolve.js";
22
+ import { isToolAllowed } from "../credentials/tool-policy.js";
21
23
  import {
22
24
  getOrStartSession,
23
25
  getSessionEnv,
@@ -214,6 +216,48 @@ class ShellTool implements Tool {
214
216
  },
215
217
  "Credential refs resolved",
216
218
  );
219
+
220
+ // -------------------------------------------------------------------
221
+ // Tool policy enforcement — deny any credential that does not
222
+ // explicitly allow "bash" in its allowedTools metadata. This check
223
+ // runs after resolution/dedup and before proxy session creation so
224
+ // that a denied credential never reaches getOrStartSession.
225
+ // -------------------------------------------------------------------
226
+ const deniedCredentials: { credentialId: string; reason: string }[] = [];
227
+ for (const credId of credentialIds) {
228
+ const meta = getCredentialMetadataById(credId);
229
+ if (!meta) {
230
+ // Should not happen — we just resolved these IDs — but fail-closed.
231
+ deniedCredentials.push({
232
+ credentialId: credId,
233
+ reason: "metadata not found",
234
+ });
235
+ continue;
236
+ }
237
+ if (!isToolAllowed("bash", meta.allowedTools)) {
238
+ const tools = meta.allowedTools ?? [];
239
+ deniedCredentials.push({
240
+ credentialId: credId,
241
+ reason:
242
+ tools.length === 0
243
+ ? `credential ${meta.service}/${meta.field} has no allowed tools`
244
+ : `credential ${meta.service}/${meta.field} allows [${tools.join(", ")}] but not bash`,
245
+ });
246
+ }
247
+ }
248
+ if (deniedCredentials.length > 0) {
249
+ log.warn(
250
+ { denied: deniedCredentials },
251
+ "Credential tool policy denied for proxied bash",
252
+ );
253
+ const reasons = deniedCredentials
254
+ .map((d) => `${d.credentialId}: ${d.reason}`)
255
+ .join("; ");
256
+ return {
257
+ content: `Error: credential tool policy denied — ${reasons}. Each credential must include "bash" in its allowed tools to be used in a proxied shell session.`,
258
+ isError: true,
259
+ };
260
+ }
217
261
  } else {
218
262
  credentialIds.push(...rawCredentialRefs);
219
263
  }
@@ -0,0 +1,19 @@
1
+ const TOOL_NAME_ALIASES = new Map<string, string>([
2
+ ["create_app", "app_create"],
3
+ ]);
4
+
5
+ /**
6
+ * Resolve high-confidence compatibility aliases before active-tool gating.
7
+ * Keep this list narrow: aliases should only cover observed model drift where
8
+ * the canonical target is active for the turn.
9
+ */
10
+ export function resolveToolNameAlias(
11
+ name: string,
12
+ allowedToolNames?: ReadonlySet<string>,
13
+ ): string {
14
+ if (allowedToolNames?.has(name)) return name;
15
+ const canonical = TOOL_NAME_ALIASES.get(name);
16
+ if (!canonical) return name;
17
+ if (allowedToolNames && !allowedToolNames.has(canonical)) return name;
18
+ return canonical;
19
+ }
@@ -115,8 +115,26 @@ export interface ToolExecutionResult {
115
115
  riskThreshold?: string;
116
116
  /** Whether the daemon is running in a containerized (Docker) environment. */
117
117
  isContainerized?: boolean;
118
- /** Scope options ladder for the rule editor (narrowest to broadest). */
118
+ /**
119
+ * Display-only ladder of scope option labels for the rule editor
120
+ * (narrowest to broadest). The `pattern` field here is a regex-style
121
+ * descriptor used internally by the daemon and is NOT a valid trust
122
+ * rule pattern. Use `riskAllowlistOptions` for the pattern that gets
123
+ * saved as a trust rule.
124
+ */
119
125
  riskScopeOptions?: Array<{ pattern: string; label: string }>;
126
+ /**
127
+ * Allowlist options for the rule editor save path (narrowest to
128
+ * broadest). Each `pattern` is a Minimatch-glob compatible string
129
+ * (e.g. raw command for exact match, `action:<program>` for command
130
+ * wildcards) — what the gateway actually matches against. Mirrors
131
+ * the `allowlistOptions` field on `ConfirmationRequest` SSE events.
132
+ */
133
+ riskAllowlistOptions?: Array<{
134
+ label: string;
135
+ description: string;
136
+ pattern: string;
137
+ }>;
120
138
  /** Directory scope ladder for the rule editor (narrowest to broadest). */
121
139
  riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
122
140
  /**