@vellumai/assistant 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -1,38 +1,16 @@
1
+ import { resolveCallSiteConfig } from "../../config/llm-resolver.js";
1
2
  import {
2
3
  getConfig,
3
4
  loadRawConfig,
4
5
  saveRawConfig,
5
6
  } from "../../config/loader.js";
6
- import {
7
- setLlmDefaultField,
8
- setServiceField,
9
- } from "../../config/raw-config-utils.js";
10
- import { VALID_INFERENCE_PROVIDERS } from "../../config/schemas/services.js";
7
+ import { setServiceField } from "../../config/raw-config-utils.js";
11
8
  import { providerForImageModelPrefix } from "../../media/types.js";
12
9
  import type { ProviderCatalogEntry } from "../../providers/model-catalog.js";
13
- import {
14
- isModelInCatalog,
15
- PROVIDER_CATALOG,
16
- } from "../../providers/model-catalog.js";
17
- import { getProviderDefaultModel } from "../../providers/model-intents.js";
18
- import {
19
- getConfiguredProviders,
20
- isProviderAvailable,
21
- } from "../../providers/provider-availability.js";
22
- import { initializeProviders } from "../../providers/registry.js";
23
- import {
24
- conversationEntries,
25
- deleteConversation,
26
- } from "../conversation-store.js";
10
+ import { PROVIDER_CATALOG } from "../../providers/model-catalog.js";
11
+ import { getConfiguredProviders } from "../../providers/provider-availability.js";
27
12
  import { CONFIG_RELOAD_DEBOUNCE_MS, log } from "./shared.js";
28
13
 
29
- /** Reverse lookup: model ID → provider, derived from PROVIDER_CATALOG. */
30
- const MODEL_TO_PROVIDER: Record<string, string> = Object.fromEntries(
31
- PROVIDER_CATALOG.flatMap((provider) =>
32
- provider.models.map(({ id }) => [id, provider.id]),
33
- ),
34
- );
35
-
36
14
  // ---------------------------------------------------------------------------
37
15
  // Shared business logic (transport-agnostic)
38
16
  // ---------------------------------------------------------------------------
@@ -85,10 +63,11 @@ export function projectProviderForWire(
85
63
  /** Return current model configuration. */
86
64
  export async function getModelInfo(): Promise<ModelInfo> {
87
65
  const config = getConfig();
88
- const provider = config.llm.default.provider;
66
+ const resolved = resolveCallSiteConfig("mainAgent", config.llm);
67
+ const provider = resolved.provider;
89
68
 
90
69
  return {
91
- model: config.llm.default.model,
70
+ model: resolved.model,
92
71
  provider,
93
72
  configuredProviders: await getConfiguredProviders(),
94
73
  availableModels: PROVIDER_CATALOG.find(
@@ -99,7 +78,7 @@ export async function getModelInfo(): Promise<ModelInfo> {
99
78
  }
100
79
 
101
80
  /**
102
- * Minimal interface for the side-effects needed by setModel / setImageGenModel.
81
+ * Minimal interface for the side-effects needed by setImageGenModel.
103
82
  * Keeps the business logic decoupled from transport-specific server context.
104
83
  */
105
84
  export interface ModelSetContext {
@@ -109,103 +88,6 @@ export interface ModelSetContext {
109
88
  debounceTimers: { schedule(key: string, fn: () => void, ms: number): void };
110
89
  }
111
90
 
112
- /**
113
- * Set the active model. Returns the resulting ModelInfo, or throws on failure.
114
- * The caller is responsible for sending the response to the client.
115
- *
116
- * When `explicitProvider` is supplied, it takes precedence over automatic
117
- * provider inference from the model ID. If the provider changes and the
118
- * current model doesn't belong to the new provider's catalog, the model
119
- * is auto-reset to the provider's default.
120
- */
121
- export async function setModel(
122
- modelId: string,
123
- ctx: ModelSetContext,
124
- explicitProvider?: string,
125
- ): Promise<ModelInfo> {
126
- const validProviders = new Set<string>(VALID_INFERENCE_PROVIDERS);
127
-
128
- // Validate explicit provider against allowlist
129
- if (explicitProvider && !validProviders.has(explicitProvider)) {
130
- throw new Error(
131
- `Invalid provider "${explicitProvider}". Valid providers: ${[...validProviders].join(", ")}`,
132
- );
133
- }
134
-
135
- // Resolve provider: explicit > MODEL_TO_PROVIDER lookup > current
136
- const current = getConfig();
137
- const resolvedProvider =
138
- explicitProvider ??
139
- MODEL_TO_PROVIDER[modelId] ??
140
- current.llm.default.provider;
141
-
142
- // Auto-reset model when provider changes and current modelId doesn't
143
- // belong to the new provider's catalog.
144
- if (
145
- resolvedProvider !== current.llm.default.provider &&
146
- !isModelInCatalog(resolvedProvider, modelId)
147
- ) {
148
- modelId = getProviderDefaultModel(resolvedProvider);
149
- }
150
-
151
- // No-op guard: skip expensive reinitialization when nothing changed
152
- if (
153
- modelId === current.llm.default.model &&
154
- resolvedProvider === current.llm.default.provider
155
- ) {
156
- return await getModelInfo();
157
- }
158
-
159
- // Validate provider availability (secure key, env var, or managed proxy) before switching
160
- if (!(await isProviderAvailable(resolvedProvider))) {
161
- // Return current model_info so the client resyncs its optimistic state
162
- return await getModelInfo();
163
- }
164
-
165
- // Use raw config to avoid persisting env-var API keys to disk
166
- const raw = loadRawConfig();
167
- setLlmDefaultField(raw, "model", modelId);
168
- setLlmDefaultField(raw, "provider", resolvedProvider);
169
-
170
- // Suppress the file watcher callback — setModel already does
171
- // the full reload sequence; a redundant watcher-triggered reload
172
- // would incorrectly evict sessions created after this method returns.
173
- const wasSuppressed = ctx.suppressConfigReload;
174
- ctx.setSuppressConfigReload(true);
175
- try {
176
- saveRawConfig(raw);
177
- } catch (err) {
178
- ctx.setSuppressConfigReload(wasSuppressed);
179
- throw err;
180
- }
181
- ctx.debounceTimers.schedule(
182
- "__suppress_reset__",
183
- () => {
184
- ctx.setSuppressConfigReload(false);
185
- },
186
- CONFIG_RELOAD_DEBOUNCE_MS,
187
- );
188
-
189
- // Re-initialize provider with the new model so LLM calls use it
190
- const config = getConfig();
191
- await initializeProviders(config);
192
-
193
- // Evict idle conversations immediately; mark busy ones as stale so they
194
- // get recreated with the new provider once they finish processing.
195
- for (const [id, conversation] of conversationEntries()) {
196
- if (!conversation.isProcessing()) {
197
- conversation.dispose();
198
- deleteConversation(id);
199
- } else {
200
- conversation.markStale();
201
- }
202
- }
203
-
204
- ctx.updateConfigFingerprint();
205
-
206
- return await getModelInfo();
207
- }
208
-
209
91
  /**
210
92
  * Set the image generation model. Throws on failure.
211
93
  */
@@ -54,6 +54,7 @@ const SLACK_INJECTION_TEMPLATES = [
54
54
  /** Ensure the bot token credential has injection templates for the proxy. */
55
55
  function ensureBotTokenInjectionTemplates(): void {
56
56
  upsertCredentialMetadata("slack_channel", "bot_token", {
57
+ allowedTools: ["bash"],
57
58
  allowedDomains: ["slack.com"],
58
59
  injectionTemplates: SLACK_INJECTION_TEMPLATES,
59
60
  });
@@ -62,6 +63,7 @@ function ensureBotTokenInjectionTemplates(): void {
62
63
  /** Ensure the user token credential has injection templates for the proxy. */
63
64
  function ensureUserTokenInjectionTemplates(): void {
64
65
  upsertCredentialMetadata("slack_channel", "user_token", {
66
+ allowedTools: ["bash"],
65
67
  allowedDomains: ["slack.com"],
66
68
  injectionTemplates: SLACK_INJECTION_TEMPLATES,
67
69
  });
@@ -209,7 +211,9 @@ export async function setSlackChannelConfig(
209
211
  botToken,
210
212
  );
211
213
  if (!stored) {
212
- return currentErrorSnapshot("Failed to store bot token in secure storage");
214
+ return currentErrorSnapshot(
215
+ "Failed to store bot token in secure storage",
216
+ );
213
217
  }
214
218
 
215
219
  ensureBotTokenInjectionTemplates();
@@ -262,8 +266,7 @@ export async function setSlackChannelConfig(
262
266
  data.team_id !== metadata.teamId
263
267
  ) {
264
268
  shouldClear = true;
265
- clearReason =
266
- "User token from a different workspace was removed.";
269
+ clearReason = "User token from a different workspace was removed.";
267
270
  }
268
271
  } catch (err) {
269
272
  // Transient failure (DNS error, network blip, connection reset,
@@ -310,7 +313,9 @@ export async function setSlackChannelConfig(
310
313
  appToken,
311
314
  );
312
315
  if (!stored) {
313
- return currentErrorSnapshot("Failed to store app token in secure storage");
316
+ return currentErrorSnapshot(
317
+ "Failed to store app token in secure storage",
318
+ );
314
319
  }
315
320
 
316
321
  upsertCredentialMetadata("slack_channel", "app_token", {});
@@ -344,9 +349,7 @@ export async function setSlackChannelConfig(
344
349
  userTeamId = data.team_id;
345
350
  } catch (err) {
346
351
  const message = err instanceof Error ? err.message : String(err);
347
- return currentErrorSnapshot(
348
- `Failed to validate user token: ${message}`,
349
- );
352
+ return currentErrorSnapshot(`Failed to validate user token: ${message}`);
350
353
  }
351
354
 
352
355
  // Cross-check: if a bot token has already been configured, the user token
@@ -59,7 +59,9 @@ export async function setVercelConfig(
59
59
  }
60
60
 
61
61
  upsertCredentialMetadata("vercel", "api_token", {
62
- allowedTools: ["deploy", "publish_page"],
62
+ allowedTools: ["publish_page", "unpublish_page"],
63
+ allowedDomains: [],
64
+ injectionTemplates: null,
63
65
  });
64
66
 
65
67
  log.info("Vercel API token stored successfully");
@@ -63,6 +63,20 @@ export interface HistoryToolCall {
63
63
  approvalReason?: string;
64
64
  /** Snapshot of the auto-approve threshold at execution time. */
65
65
  riskThreshold?: string;
66
+ /**
67
+ * Display-only regex ladder for the rule editor (narrowest → broadest).
68
+ * Persisted on tool_use blocks by `annotatePersistedAssistantMessage` so
69
+ * historical chips render the same ladder as live tool_result events.
70
+ */
71
+ riskScopeOptions?: Array<{ pattern: string; label: string }>;
72
+ /** Minimatch save patterns for the rule editor (narrowest → broadest). */
73
+ riskAllowlistOptions?: Array<{
74
+ label: string;
75
+ description: string;
76
+ pattern: string;
77
+ }>;
78
+ /** Directory scope ladder for the rule editor. */
79
+ riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
66
80
  }
67
81
 
68
82
  export interface HistorySurface {
@@ -368,6 +382,18 @@ export function renderHistoryContent(content: unknown): RenderedHistoryContent {
368
382
  entry.approvalReason = block._approvalReason;
369
383
  if (typeof block._riskThreshold === "string")
370
384
  entry.riskThreshold = block._riskThreshold;
385
+ // Read back the 3 risk-option arrays persisted by
386
+ // `annotatePersistedAssistantMessage`. Validate the array shape only
387
+ // — element shapes are best-effort (we trust our own writer).
388
+ if (Array.isArray(block._riskScopeOptions))
389
+ entry.riskScopeOptions =
390
+ block._riskScopeOptions as HistoryToolCall["riskScopeOptions"];
391
+ if (Array.isArray(block._riskAllowlistOptions))
392
+ entry.riskAllowlistOptions =
393
+ block._riskAllowlistOptions as HistoryToolCall["riskAllowlistOptions"];
394
+ if (Array.isArray(block._riskDirectoryScopeOptions))
395
+ entry.riskDirectoryScopeOptions =
396
+ block._riskDirectoryScopeOptions as HistoryToolCall["riskDirectoryScopeOptions"];
371
397
  toolCalls.push(entry);
372
398
  if (id) pendingToolUses.set(id, entry);
373
399
  contentOrder.push(`tool:${toolCalls.length - 1}`);
@@ -691,6 +691,65 @@ export async function getSkill(
691
691
  return { skill: detail };
692
692
  }
693
693
 
694
+ export function getSkillLocalDetail(
695
+ skillId: string,
696
+ ): {
697
+ ok: true;
698
+ id: string;
699
+ name: string;
700
+ description: string;
701
+ emoji: string | null;
702
+ source: string;
703
+ state: string;
704
+ directoryPath: string;
705
+ featureFlag: string | null;
706
+ includes: string[] | null;
707
+ activationHints: string[] | null;
708
+ avoidWhen: string[] | null;
709
+ toolManifest: { valid: boolean; toolCount: number; toolNames: string[] } | null;
710
+ installMeta: Record<string, unknown> | null;
711
+ config: { enabled: boolean; envKeys: string[]; configKeys: string[] } | null;
712
+ } | { ok: false; error: string; status: 404 | 500 } {
713
+ try {
714
+ const catalog = loadSkillCatalog();
715
+ const config = getConfig();
716
+ const resolved = resolveSkillStates(catalog, config);
717
+ const match = resolved.find((r) => r.summary.id === skillId);
718
+ if (!match) {
719
+ return { ok: false, error: `Skill "${skillId}" not found. Run 'assistant skills list' to see available skills.`, status: 404 };
720
+ }
721
+ const { summary, state, configEntry } = match;
722
+ const installMeta = readInstallMeta(summary.directoryPath);
723
+ return {
724
+ ok: true,
725
+ id: summary.id,
726
+ name: summary.displayName,
727
+ description: summary.description,
728
+ emoji: summary.emoji ?? null,
729
+ source: summary.source,
730
+ state,
731
+ directoryPath: summary.directoryPath,
732
+ featureFlag: summary.featureFlag ?? null,
733
+ includes: summary.includes ?? null,
734
+ activationHints: summary.activationHints ?? null,
735
+ avoidWhen: summary.avoidWhen ?? null,
736
+ toolManifest: summary.toolManifest
737
+ ? { valid: summary.toolManifest.valid, toolCount: summary.toolManifest.toolCount, toolNames: summary.toolManifest.toolNames }
738
+ : null,
739
+ installMeta: installMeta ? (installMeta as unknown as Record<string, unknown>) : null,
740
+ config: configEntry
741
+ ? {
742
+ enabled: configEntry.enabled !== false,
743
+ envKeys: configEntry.env ? Object.keys(configEntry.env) : [],
744
+ configKeys: configEntry.config ? Object.keys(configEntry.config) : [],
745
+ }
746
+ : null,
747
+ };
748
+ } catch (err) {
749
+ return { ok: false, error: err instanceof Error ? err.message : String(err), status: 500 };
750
+ }
751
+ }
752
+
694
753
  // ─── Skill file listing ──────────────────────────────────────────────────────
695
754
 
696
755
  // `SkillFileEntry` lives in `../../skills/catalog-files.ts` to keep a single
@@ -1017,6 +1076,8 @@ export async function installSkill(spec: {
1017
1076
  slug: string;
1018
1077
  version?: string;
1019
1078
  origin?: "clawhub" | "skillssh";
1079
+ catalogOnly?: boolean;
1080
+ overwrite?: boolean;
1020
1081
  contactId?: string;
1021
1082
  }): Promise<
1022
1083
  { success: true; skillId: string } | { success: false; error: string }
@@ -1078,10 +1139,14 @@ export async function installSkill(spec: {
1078
1139
  const vellumCatalog = await getCatalog();
1079
1140
  const catalogEntry = vellumCatalog.find((s) => s.id === spec.slug);
1080
1141
  if (catalogEntry) {
1142
+ // Default `overwrite` to true at the handler boundary to preserve
1143
+ // pre-existing HTTP API behaviour. CLI callers always pass an
1144
+ // explicit boolean (`opts.overwrite ?? false`) so the CLI surface
1145
+ // still defaults to non-destructive installs.
1081
1146
  await installSkillLocally(
1082
1147
  spec.slug,
1083
1148
  catalogEntry,
1084
- true,
1149
+ spec.overwrite ?? true,
1085
1150
  spec.contactId,
1086
1151
  );
1087
1152
 
@@ -1090,13 +1155,19 @@ export async function installSkill(spec: {
1090
1155
  return { success: true, skillId: spec.slug };
1091
1156
  }
1092
1157
  } catch (err) {
1093
- // If catalog lookup/install fails, fall through to community registries
1158
+ if (spec.catalogOnly) {
1159
+ return { success: false, error: `Failed to install catalog skill "${spec.slug}"` };
1160
+ }
1094
1161
  log.warn(
1095
1162
  { err, skillId: spec.slug },
1096
1163
  "Vellum catalog install failed, falling back to community registry",
1097
1164
  );
1098
1165
  }
1099
1166
 
1167
+ if (spec.catalogOnly) {
1168
+ return { success: false, error: `Skill "${spec.slug}" not found in the Vellum catalog` };
1169
+ }
1170
+
1100
1171
  // skills.sh install path: route here when origin is explicitly "skillssh"
1101
1172
  // or when the slug looks like a skills.sh multi-segment format (owner/repo/skill)
1102
1173
  if (
@@ -1104,11 +1175,14 @@ export async function installSkill(spec: {
1104
1175
  (spec.origin !== "clawhub" && looksLikeSkillsShSlug(spec.slug))
1105
1176
  ) {
1106
1177
  const resolved = resolveSkillSource(spec.slug);
1178
+ // Default `overwrite` to true at the handler boundary to preserve
1179
+ // pre-existing HTTP API behaviour (same rationale as the catalog
1180
+ // install path above).
1107
1181
  await installExternalSkill(
1108
1182
  resolved.owner,
1109
1183
  resolved.repo,
1110
1184
  resolved.skillSlug,
1111
- true /* overwrite */,
1185
+ spec.overwrite ?? true,
1112
1186
  resolved.ref ?? spec.version,
1113
1187
  spec.contactId,
1114
1188
  );
@@ -1209,6 +1283,10 @@ export async function uninstallSkill(
1209
1283
  state: "uninstalled",
1210
1284
  });
1211
1285
 
1286
+ // Without this, an uninstalled skill remains queryable in v2 until the
1287
+ // next incidental seed event (enable/disable/install).
1288
+ maybeSeedMemoryV2Skills(getConfig());
1289
+
1212
1290
  return { success: true };
1213
1291
  } catch (err) {
1214
1292
  const message = err instanceof Error ? err.message : String(err);
@@ -1250,6 +1328,7 @@ export async function checkSkillUpdates(): Promise<
1250
1328
 
1251
1329
  export async function searchSkills(
1252
1330
  query: string,
1331
+ limit: number = 25,
1253
1332
  ): Promise<
1254
1333
  | { success: true; skills: SlimSkillResponse[] }
1255
1334
  | { success: false; error: string }
@@ -1290,8 +1369,8 @@ export async function searchSkills(
1290
1369
 
1291
1370
  // Search both community registries in parallel (non-fatal on failure)
1292
1371
  const [clawhubResult, skillsshResult] = await Promise.allSettled([
1293
- clawhubSearch(query),
1294
- searchSkillsRegistry(query, 25),
1372
+ clawhubSearch(query, { limit }),
1373
+ searchSkillsRegistry(query, limit),
1295
1374
  ]);
1296
1375
 
1297
1376
  let clawhubSkills: SlimSkillResponse[] = [];
@@ -68,11 +68,14 @@ export function repairHistory(messages: Message[]): RepairResult {
68
68
  }
69
69
  }
70
70
 
71
- // Ensure every server_tool_use has a paired web_search_tool_result
72
- // in the same assistant message (handles interrupted streams).
73
- // Synthetic results are inserted IMMEDIATELY AFTER their corresponding
74
- // server_tool_use block not appended to the end so that
75
- // ensureToolPairing's split at tool_use boundaries cannot separate them.
71
+ // Pair server-side tool blocks within the same assistant message.
72
+ // Server tools (e.g. web_search) emit server_tool_use + matching
73
+ // web_search_tool_result. Either side can go missing the synthetic
74
+ // result is inserted IMMEDIATELY AFTER the orphan server_tool_use (not
75
+ // appended to the end) so ensureToolPairing's split at tool_use
76
+ // boundaries cannot separate the pair. An orphan
77
+ // web_search_tool_result (no preceding server_tool_use) is downgraded
78
+ // to text — Anthropic rejects the request otherwise.
76
79
  const serverToolIds = new Set(
77
80
  cleanedContent
78
81
  .filter(
@@ -91,11 +94,35 @@ export function repairHistory(messages: Message[]): RepairResult {
91
94
  orphanedServerIds.add(id);
92
95
  }
93
96
  }
97
+ const orphanedWebSearchResultIds = new Set<string>();
98
+ for (const id of matchedServerIds) {
99
+ if (!serverToolIds.has(id)) {
100
+ orphanedWebSearchResultIds.add(id);
101
+ }
102
+ }
94
103
 
95
104
  let repairedContent: ContentBlock[];
96
- if (orphanedServerIds.size > 0) {
105
+ if (orphanedServerIds.size > 0 || orphanedWebSearchResultIds.size > 0) {
97
106
  repairedContent = [];
98
107
  for (const block of cleanedContent) {
108
+ if (
109
+ block.type === "web_search_tool_result" &&
110
+ orphanedWebSearchResultIds.has(
111
+ (block as { tool_use_id: string }).tool_use_id,
112
+ )
113
+ ) {
114
+ repairedContent.push(
115
+ downgradeResult(
116
+ block as {
117
+ type: "web_search_tool_result";
118
+ tool_use_id: string;
119
+ content: unknown;
120
+ },
121
+ ),
122
+ );
123
+ stats.orphanToolResultsDowngraded++;
124
+ continue;
125
+ }
99
126
  repairedContent.push(block);
100
127
  if (
101
128
  block.type === "server_tool_use" &&
@@ -15,9 +15,11 @@
15
15
  * session at a time, and that session is bound to a specific target app.
16
16
  * The lock is module-level (`activeAppControlSession`) because the session
17
17
  * targets the user's actual desktop application, which is a host-wide
18
- * resource. It is acquired on a successful `app_control_start` (storing
19
- * `(conversationId, app)`) and released when the owning proxy's
20
- * `dispose()` fires.
18
+ * resource. It is acquired optimistically when `app_control_start` is
19
+ * dispatched (storing `(conversationId, app)`) so that the synchronous
20
+ * guard and the asynchronous host round-trip cannot race; it is released
21
+ * when the host returns a non-running state, the dispatch fails, or the
22
+ * owning proxy's `dispose()` fires.
21
23
  *
22
24
  * `app_control_start` is the only tool that can acquire the lock — the
23
25
  * user's medium-risk approval at start time is the consent boundary. All
@@ -144,12 +146,12 @@ function checkNonStartAuthorization(
144
146
  // except `stop`, and `stop` short-circuits in conversation-surfaces and
145
147
  // does not reach this method in production. A stop reaching here would
146
148
  // be a defensive bug — surface it explicitly rather than dispatch.
147
- const requestedApp = (input as { app?: string }).app;
148
- if (requestedApp == null) {
149
+ const requestedApp = (input as { app?: unknown }).app;
150
+ if (typeof requestedApp !== "string") {
149
151
  return {
150
152
  content:
151
- "Tool input missing required 'app' field; cannot validate against " +
152
- "the active app-control session.",
153
+ "Tool input missing required string 'app' field; cannot validate " +
154
+ "against the active app-control session.",
153
155
  isError: true,
154
156
  };
155
157
  }
@@ -222,6 +224,8 @@ export class HostAppControlProxy extends HostProxyBase<
222
224
  input: HostAppControlInput,
223
225
  conversationId: string,
224
226
  signal: AbortSignal,
227
+ sourceActorPrincipalId?: string,
228
+ targetClientId?: string,
225
229
  ): Promise<ToolExecutionResult> {
226
230
  if (signal.aborted) {
227
231
  return { content: "Aborted", isError: true };
@@ -235,7 +239,7 @@ export class HostAppControlProxy extends HostProxyBase<
235
239
  if (input.tool === "start") {
236
240
  if (
237
241
  activeAppControlSession != null &&
238
- activeAppControlSession.conversationId !== conversationId
242
+ activeAppControlSession.conversationId !== this.conversationId
239
243
  ) {
240
244
  return {
241
245
  content:
@@ -245,8 +249,21 @@ export class HostAppControlProxy extends HostProxyBase<
245
249
  isError: true,
246
250
  };
247
251
  }
252
+ // Acquire optimistically to close the TOCTOU window between this
253
+ // synchronous guard and the asynchronous `dispatchRequest` below. Two
254
+ // concurrent starts from different conversations would otherwise both
255
+ // see `activeAppControlSession == null` and both pass the guard. The
256
+ // lock is released below if dispatch fails or the host returns a
257
+ // non-running state.
258
+ activeAppControlSession = {
259
+ conversationId: this.conversationId,
260
+ app: input.app,
261
+ };
248
262
  } else {
249
- const sessionError = checkNonStartAuthorization(input, conversationId);
263
+ const sessionError = checkNonStartAuthorization(
264
+ input,
265
+ this.conversationId,
266
+ );
250
267
  if (sessionError != null) {
251
268
  return sessionError;
252
269
  }
@@ -258,9 +275,14 @@ export class HostAppControlProxy extends HostProxyBase<
258
275
  input,
259
276
  conversationId,
260
277
  signal,
278
+ undefined,
279
+ targetClientId,
261
280
  );
262
281
  return this.handleSuccess(input, payload);
263
282
  } catch (err) {
283
+ if (input.tool === "start") {
284
+ this.releaseSessionIfHeld();
285
+ }
264
286
  if (err instanceof HostProxyRequestError) {
265
287
  if (err.reason === "timeout") {
266
288
  log.warn({ toolName }, "Host app-control proxy request timed out");
@@ -279,6 +301,12 @@ export class HostAppControlProxy extends HostProxyBase<
279
301
  }
280
302
  }
281
303
 
304
+ private releaseSessionIfHeld(): void {
305
+ if (activeAppControlSession?.conversationId === this.conversationId) {
306
+ activeAppControlSession = undefined;
307
+ }
308
+ }
309
+
282
310
  // ---------------------------------------------------------------------------
283
311
  // Result handling
284
312
  // ---------------------------------------------------------------------------
@@ -304,13 +332,12 @@ export class HostAppControlProxy extends HostProxyBase<
304
332
  }
305
333
  }
306
334
 
307
- // Store the exact `app` form for validation against subsequent
308
- // non-start tool calls.
309
- if (input.tool === "start" && payload.state === "running") {
310
- activeAppControlSession = {
311
- conversationId: this.conversationId,
312
- app: input.app,
313
- };
335
+ // The optimistic lock acquired in `request()` for `start` stays held
336
+ // only when the host confirms the session is running. Non-running
337
+ // outcomes (missing/minimized) release it so a retry or another
338
+ // conversation can acquire.
339
+ if (input.tool === "start" && payload.state !== "running") {
340
+ this.releaseSessionIfHeld();
314
341
  }
315
342
 
316
343
  return this.formatResult(payload, stuck);
@@ -382,8 +409,6 @@ export class HostAppControlProxy extends HostProxyBase<
382
409
  */
383
410
  override dispose(): void {
384
411
  super.dispose();
385
- if (activeAppControlSession?.conversationId === this.conversationId) {
386
- activeAppControlSession = undefined;
387
- }
412
+ this.releaseSessionIfHeld();
388
413
  }
389
414
  }