@vellumai/assistant 0.7.1 → 0.7.3

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 (739) hide show
  1. package/ARCHITECTURE.md +48 -50
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/memory.md +5 -2
  7. package/docs/architecture/security.md +20 -0
  8. package/docs/plugins.md +7 -9
  9. package/knip.json +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  11. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
  12. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  13. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  16. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  17. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  18. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  20. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  21. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  22. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  23. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  24. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  25. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  26. package/openapi.yaml +1020 -40
  27. package/package.json +6 -3
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  29. package/src/__tests__/app-bundler.test.ts +170 -1
  30. package/src/__tests__/app-control-flow.test.ts +384 -0
  31. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  32. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  33. package/src/__tests__/app-executors.test.ts +30 -43
  34. package/src/__tests__/approval-routes-http.test.ts +23 -6
  35. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +157 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
  39. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  40. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  41. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  42. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  43. package/src/__tests__/btw-routes.test.ts +13 -4
  44. package/src/__tests__/call-controller.test.ts +49 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  46. package/src/__tests__/call-domain.test.ts +0 -2
  47. package/src/__tests__/call-routes-http.test.ts +0 -2
  48. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  49. package/src/__tests__/channel-readiness-service.test.ts +62 -2
  50. package/src/__tests__/checker.test.ts +3 -4
  51. package/src/__tests__/config-loader-backfill.test.ts +461 -147
  52. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  53. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  54. package/src/__tests__/config-schema.test.ts +1 -0
  55. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  56. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
  57. package/src/__tests__/config-watcher.test.ts +142 -71
  58. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  59. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  60. package/src/__tests__/context-search-fanout.test.ts +0 -1
  61. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  62. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  63. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  64. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  65. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  66. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  67. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  68. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  70. package/src/__tests__/conversation-error.test.ts +150 -3
  71. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  72. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  74. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  80. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  81. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  82. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  83. package/src/__tests__/conversation-store.test.ts +0 -18
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  85. package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
  86. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  87. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  88. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  89. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  90. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  91. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  92. package/src/__tests__/credentials-cli.test.ts +12 -12
  93. package/src/__tests__/cu-unified-flow.test.ts +351 -23
  94. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  95. package/src/__tests__/date-context.test.ts +164 -2
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  97. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  98. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  99. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  100. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  101. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  102. package/src/__tests__/disk-usage.test.ts +150 -0
  103. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  104. package/src/__tests__/events-client-registration.test.ts +52 -0
  105. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  106. package/src/__tests__/file-write-tool.test.ts +4 -10
  107. package/src/__tests__/filing-service.test.ts +3 -4
  108. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  109. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  110. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  111. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  112. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  113. package/src/__tests__/heartbeat-service.test.ts +968 -2
  114. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  115. package/src/__tests__/host-app-control-proxy.test.ts +772 -0
  116. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +439 -47
  118. package/src/__tests__/host-bash-routes.test.ts +459 -0
  119. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  120. package/src/__tests__/host-browser-routes.test.ts +39 -13
  121. package/src/__tests__/host-cu-proxy.test.ts +248 -52
  122. package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
  123. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  124. package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
  125. package/src/__tests__/host-file-proxy.test.ts +301 -45
  126. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  127. package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
  128. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  129. package/src/__tests__/host-proxy-base.test.ts +312 -0
  130. package/src/__tests__/host-shell-tool.test.ts +22 -4
  131. package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
  132. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  133. package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
  134. package/src/__tests__/http-user-message-parity.test.ts +108 -1
  135. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  136. package/src/__tests__/identity-routes.test.ts +103 -1
  137. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  138. package/src/__tests__/injector-chain.test.ts +18 -6
  139. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  140. package/src/__tests__/inline-command-runner.test.ts +0 -1
  141. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  142. package/src/__tests__/integration-status.test.ts +85 -5
  143. package/src/__tests__/intent-routing.test.ts +0 -1
  144. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  145. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  148. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  149. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  150. package/src/__tests__/mcp-cli.test.ts +338 -2
  151. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  153. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  155. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  156. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  157. package/src/__tests__/oauth-cli.test.ts +0 -2
  158. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  160. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  161. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  162. package/src/__tests__/openai-provider.test.ts +45 -8
  163. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  164. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  165. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  166. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  167. package/src/__tests__/platform.test.ts +2 -1
  168. package/src/__tests__/playbook-execution.test.ts +0 -43
  169. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  170. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
  171. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  172. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  173. package/src/__tests__/provider-tool-name.test.ts +23 -0
  174. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  175. package/src/__tests__/relay-server.test.ts +15 -4
  176. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  177. package/src/__tests__/retry-backoff.test.ts +87 -0
  178. package/src/__tests__/runtime-events-sse.test.ts +2 -2
  179. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  180. package/src/__tests__/schedule-retry.test.ts +715 -0
  181. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  182. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  183. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  184. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  185. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  186. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  187. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  188. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  189. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  190. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  191. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  192. package/src/__tests__/slack-channel-config.test.ts +9 -14
  193. package/src/__tests__/suggestion-routes.test.ts +46 -0
  194. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  195. package/src/__tests__/system-prompt.test.ts +0 -1
  196. package/src/__tests__/telegram-config.test.ts +0 -1
  197. package/src/__tests__/test-preload.ts +8 -0
  198. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  199. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  200. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  201. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  202. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  203. package/src/__tests__/tool-executor.test.ts +0 -1
  204. package/src/__tests__/twilio-config.test.ts +3 -16
  205. package/src/__tests__/twilio-routes.test.ts +3 -5
  206. package/src/__tests__/twilio-validation.test.ts +93 -0
  207. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  208. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  209. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  210. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  211. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  212. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  213. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  214. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  215. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  216. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  217. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  218. package/src/approvals/guardian-decision-primitive.ts +13 -0
  219. package/src/approvals/guardian-request-resolvers.ts +16 -17
  220. package/src/backup/__tests__/paths.test.ts +0 -22
  221. package/src/backup/__tests__/restore.test.ts +51 -151
  222. package/src/backup/paths.ts +2 -18
  223. package/src/backup/restore.ts +107 -231
  224. package/src/backup/snapshot-lock.ts +2 -27
  225. package/src/bundler/app-bundler.ts +51 -3
  226. package/src/bundler/compiler-tools.ts +3 -2
  227. package/src/calls/call-conversation-messages.ts +46 -10
  228. package/src/calls/relay-server.ts +4 -44
  229. package/src/calls/twilio-config.ts +2 -17
  230. package/src/calls/twilio-rest.ts +33 -105
  231. package/src/calls/twilio-routes.ts +11 -12
  232. package/src/channels/types.ts +8 -7
  233. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  234. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  235. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  236. package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
  237. package/src/cli/commands/backup.ts +6 -331
  238. package/src/cli/commands/bash.ts +35 -108
  239. package/src/cli/commands/clients.ts +36 -37
  240. package/src/cli/commands/contacts.ts +137 -25
  241. package/src/cli/commands/conversations.ts +2 -5
  242. package/src/cli/commands/credentials.ts +71 -7
  243. package/src/cli/commands/domain.ts +66 -15
  244. package/src/cli/commands/gateway.ts +183 -0
  245. package/src/cli/commands/keys.ts +9 -6
  246. package/src/cli/commands/mcp.ts +116 -156
  247. package/src/cli/commands/memory-v2.ts +303 -7
  248. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  249. package/src/cli/commands/oauth/connect.ts +127 -1
  250. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
  251. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
  252. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
  253. package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
  254. package/src/cli/commands/platform/disconnect.ts +5 -4
  255. package/src/cli/commands/platform/index.ts +16 -25
  256. package/src/cli/commands/status.ts +57 -0
  257. package/src/cli/lib/daemon-credential-client.ts +110 -28
  258. package/src/cli/program.ts +6 -2
  259. package/src/config/assistant-feature-flags.ts +79 -12
  260. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  261. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  262. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  263. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  264. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  265. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  266. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  267. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  268. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  269. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  270. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  271. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  272. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  273. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  274. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  275. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  276. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  277. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  278. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  279. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  280. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  281. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  282. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  283. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  284. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  285. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  286. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  287. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
  288. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  289. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  290. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  291. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  292. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  293. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  294. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  295. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  296. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  297. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  298. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  299. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  300. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  301. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  302. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  303. package/src/config/bundled-tool-registry.ts +21 -0
  304. package/src/config/env-registry.ts +0 -2
  305. package/src/config/env.ts +19 -20
  306. package/src/config/feature-flag-registry.json +47 -135
  307. package/src/config/loader.ts +197 -104
  308. package/src/config/sanitize-for-transfer.ts +2 -0
  309. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  310. package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
  311. package/src/config/schemas/call-site-catalog.ts +14 -0
  312. package/src/config/schemas/calls.ts +0 -9
  313. package/src/config/schemas/channels.ts +0 -5
  314. package/src/config/schemas/heartbeat.ts +64 -1
  315. package/src/config/schemas/ingress.ts +10 -6
  316. package/src/config/schemas/llm.ts +7 -10
  317. package/src/config/schemas/memory-lifecycle.ts +90 -24
  318. package/src/config/schemas/memory-v2.ts +121 -13
  319. package/src/config/schemas/platform.ts +49 -3
  320. package/src/config/schemas/services.ts +29 -15
  321. package/src/config/schemas/skills.ts +0 -6
  322. package/src/config/seed-inference-profiles.ts +230 -33
  323. package/src/contacts/contact-store.ts +0 -55
  324. package/src/contacts/contacts-write.ts +0 -27
  325. package/src/context/window-manager.ts +1 -2
  326. package/src/credential-execution/feature-gates.ts +10 -10
  327. package/src/credential-execution/process-manager.ts +12 -41
  328. package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
  329. package/src/daemon/assistant-attachments.ts +4 -4
  330. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  331. package/src/daemon/config-watcher.ts +89 -60
  332. package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
  333. package/src/daemon/conversation-agent-loop.ts +202 -61
  334. package/src/daemon/conversation-error.ts +87 -15
  335. package/src/daemon/conversation-lifecycle.ts +9 -4
  336. package/src/daemon/conversation-process.ts +24 -11
  337. package/src/daemon/conversation-runtime-assembly.ts +28 -2
  338. package/src/daemon/conversation-store.ts +2 -2
  339. package/src/daemon/conversation-surfaces.ts +305 -4
  340. package/src/daemon/conversation-tool-setup.ts +66 -62
  341. package/src/daemon/conversation.ts +38 -24
  342. package/src/daemon/date-context.ts +71 -22
  343. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  344. package/src/daemon/disk-pressure-guard.ts +343 -0
  345. package/src/daemon/disk-pressure-policy.ts +163 -0
  346. package/src/daemon/doordash-steps.ts +1 -1
  347. package/src/daemon/handlers/shared.ts +4 -2
  348. package/src/daemon/handlers/skills.ts +3 -4
  349. package/src/daemon/host-app-control-proxy.ts +389 -0
  350. package/src/daemon/host-bash-proxy.ts +117 -82
  351. package/src/daemon/host-browser-proxy.ts +67 -82
  352. package/src/daemon/host-cu-proxy.ts +127 -86
  353. package/src/daemon/host-file-proxy.ts +129 -69
  354. package/src/daemon/host-proxy-base.ts +294 -0
  355. package/src/daemon/host-proxy-preactivation.ts +82 -0
  356. package/src/daemon/host-transfer-proxy.ts +338 -129
  357. package/src/daemon/lifecycle.ts +194 -145
  358. package/src/daemon/meet-host-supervisor.ts +4 -4
  359. package/src/daemon/meet-manifest-loader.ts +0 -1
  360. package/src/daemon/memory-v2-startup.ts +14 -4
  361. package/src/daemon/message-protocol.ts +6 -8
  362. package/src/daemon/message-types/contacts.ts +23 -1
  363. package/src/daemon/message-types/conversations.ts +15 -8
  364. package/src/daemon/message-types/disk-pressure.ts +9 -0
  365. package/src/daemon/message-types/host-app-control.ts +150 -0
  366. package/src/daemon/message-types/host-bash.ts +4 -0
  367. package/src/daemon/message-types/host-cu.ts +2 -0
  368. package/src/daemon/message-types/host-file.ts +4 -0
  369. package/src/daemon/message-types/host-transfer.ts +3 -0
  370. package/src/daemon/message-types/messages.ts +3 -0
  371. package/src/daemon/message-types/schedules.ts +8 -3
  372. package/src/daemon/message-types/skills.ts +2 -2
  373. package/src/daemon/process-message.ts +18 -1
  374. package/src/daemon/profiler-run-store.ts +5 -5
  375. package/src/daemon/shutdown-handlers.ts +0 -3
  376. package/src/daemon/tool-setup-types.ts +51 -0
  377. package/src/daemon/tool-side-effects.ts +1 -1
  378. package/src/documents/document-store.ts +85 -0
  379. package/src/events/tool-audit-listener.ts +2 -1
  380. package/src/filing/filing-service.ts +30 -5
  381. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
  382. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
  383. package/src/heartbeat/heartbeat-run-store.ts +249 -0
  384. package/src/heartbeat/heartbeat-service.ts +459 -54
  385. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  386. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  387. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  388. package/src/home/feed-scheduler.ts +18 -0
  389. package/src/home/post-connect-feed.ts +68 -0
  390. package/src/home/relationship-state-writer.ts +17 -92
  391. package/src/home/suggested-prompts.ts +46 -10
  392. package/src/inbound/platform-callback-registration.ts +8 -15
  393. package/src/inbound/public-ingress-urls.ts +32 -34
  394. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  395. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  396. package/src/ipc/assistant-server.ts +70 -3
  397. package/src/ipc/cli-client.ts +32 -1
  398. package/src/ipc/gateway-client.ts +37 -3
  399. package/src/live-voice/live-voice-archive.ts +4 -4
  400. package/src/live-voice/live-voice-metrics.ts +10 -10
  401. package/src/live-voice/protocol.ts +5 -7
  402. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  403. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  404. package/src/mcp/mcp-auth-state.ts +133 -0
  405. package/src/mcp/mcp-oauth-provider.ts +19 -0
  406. package/src/media/image-service.ts +1 -7
  407. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  408. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  409. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  412. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  413. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  414. package/src/memory/admin.ts +5 -9
  415. package/src/memory/anisotropy.test.ts +247 -0
  416. package/src/memory/anisotropy.ts +443 -0
  417. package/src/memory/auto-analysis-constants.ts +17 -0
  418. package/src/memory/auto-analysis-guard.ts +5 -15
  419. package/src/memory/canonical-guardian-store.ts +7 -7
  420. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  421. package/src/memory/context-search/agent-protocol.ts +6 -6
  422. package/src/memory/context-search/agent-runner.ts +51 -9
  423. package/src/memory/context-search/sources/conversations.ts +2 -11
  424. package/src/memory/context-search/sources/memory-v2.ts +22 -9
  425. package/src/memory/context-search/sources/memory.ts +0 -1
  426. package/src/memory/context-search/types.ts +0 -1
  427. package/src/memory/conversation-crud.ts +5 -13
  428. package/src/memory/conversation-key-store.ts +2 -15
  429. package/src/memory/db-init.ts +6 -0
  430. package/src/memory/embedding-backend.ts +9 -21
  431. package/src/memory/embedding-runtime-manager.ts +119 -5
  432. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
  433. package/src/memory/graph/conversation-graph-memory.ts +43 -78
  434. package/src/memory/graph/extraction.ts +1 -3
  435. package/src/memory/graph/graph-search.test.ts +10 -67
  436. package/src/memory/graph/graph-search.ts +9 -20
  437. package/src/memory/graph/retriever.test.ts +6 -0
  438. package/src/memory/graph/retriever.ts +34 -10
  439. package/src/memory/graph/tools.ts +1 -1
  440. package/src/memory/indexer.ts +54 -45
  441. package/src/memory/job-handlers/backfill.ts +2 -11
  442. package/src/memory/job-handlers/cleanup.ts +43 -0
  443. package/src/memory/job-handlers/embedding.ts +6 -8
  444. package/src/memory/job-handlers/summarization.ts +2 -7
  445. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  446. package/src/memory/jobs/embed-concept-page.ts +28 -2
  447. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  448. package/src/memory/jobs-store.ts +114 -22
  449. package/src/memory/jobs-worker.ts +193 -106
  450. package/src/memory/memory-v2-activation-log-store.ts +33 -15
  451. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  452. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  453. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  454. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  455. package/src/memory/migrations/index.ts +6 -0
  456. package/src/memory/migrations/registry.ts +8 -0
  457. package/src/memory/pkb/pkb-search.test.ts +6 -0
  458. package/src/memory/pkb/pkb-search.ts +7 -0
  459. package/src/memory/qdrant-client.ts +49 -32
  460. package/src/memory/rerank-local.ts +374 -0
  461. package/src/memory/schema/infrastructure.ts +15 -0
  462. package/src/memory/search/semantic.ts +13 -67
  463. package/src/memory/sparse-tokenize.ts +49 -0
  464. package/src/memory/trace-event-store.ts +1 -17
  465. package/src/memory/v2/__tests__/activation.test.ts +387 -344
  466. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  467. package/src/memory/v2/__tests__/injection.test.ts +181 -169
  468. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  469. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  470. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  471. package/src/memory/v2/__tests__/sim.test.ts +154 -188
  472. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  473. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  474. package/src/memory/v2/__tests__/static-context.test.ts +76 -2
  475. package/src/memory/v2/activation.ts +213 -239
  476. package/src/memory/v2/consolidation-job.ts +65 -17
  477. package/src/memory/v2/constants.ts +7 -0
  478. package/src/memory/v2/injection.ts +123 -103
  479. package/src/memory/v2/prompts/consolidation.ts +348 -92
  480. package/src/memory/v2/qdrant.ts +198 -1
  481. package/src/memory/v2/reranker.ts +177 -0
  482. package/src/memory/v2/sim.ts +113 -77
  483. package/src/memory/v2/skill-content.ts +4 -3
  484. package/src/memory/v2/skill-store.ts +91 -53
  485. package/src/memory/v2/sparse-bm25.ts +245 -0
  486. package/src/memory/v2/static-context.ts +28 -5
  487. package/src/memory/v2/types.ts +10 -10
  488. package/src/messaging/providers/gmail/types.ts +0 -49
  489. package/src/messaging/providers/slack/adapter.ts +1 -31
  490. package/src/messaging/providers/slack/types.ts +0 -32
  491. package/src/notifications/README.md +10 -10
  492. package/src/notifications/broadcaster.ts +1 -1
  493. package/src/notifications/copy-composer.ts +13 -0
  494. package/src/notifications/guardian-question-mode.ts +5 -5
  495. package/src/notifications/signal.ts +4 -0
  496. package/src/oauth/AGENTS.md +3 -1
  497. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  498. package/src/oauth/connect-orchestrator.ts +6 -0
  499. package/src/oauth/connection-resolver.test.ts +66 -1
  500. package/src/oauth/connection-resolver.ts +55 -1
  501. package/src/oauth/credential-token-resolver.ts +1 -3
  502. package/src/oauth/manual-token-connection.ts +0 -4
  503. package/src/oauth/oauth-connect-state.ts +77 -0
  504. package/src/oauth/seed-providers.ts +58 -1
  505. package/src/outbound-proxy/index.ts +1 -37
  506. package/src/outbound-proxy/logging.ts +1 -1
  507. package/src/outbound-proxy/policy.ts +6 -5
  508. package/src/outbound-proxy/router.ts +2 -1
  509. package/src/permissions/approval-policy.test.ts +6 -275
  510. package/src/permissions/approval-policy.ts +0 -51
  511. package/src/permissions/checker.test.ts +0 -1
  512. package/src/permissions/checker.ts +3 -17
  513. package/src/permissions/gateway-threshold-reader.ts +2 -0
  514. package/src/permissions/prompter.ts +34 -1
  515. package/src/permissions/secret-prompter.ts +6 -2
  516. package/src/plugins/defaults/injectors.ts +35 -2
  517. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  518. package/src/plugins/types.ts +7 -0
  519. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  520. package/src/proactive-artifact/decision.test.ts +226 -0
  521. package/src/proactive-artifact/decision.ts +165 -0
  522. package/src/proactive-artifact/index.ts +7 -0
  523. package/src/proactive-artifact/job.test.ts +867 -0
  524. package/src/proactive-artifact/job.ts +352 -0
  525. package/src/proactive-artifact/message-copy.ts +41 -0
  526. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  527. package/src/proactive-artifact/trigger-state.ts +119 -0
  528. package/src/prompts/bootstrap-cleanup.ts +27 -0
  529. package/src/prompts/normalize-onboarding.ts +80 -0
  530. package/src/prompts/persona-resolver.ts +101 -9
  531. package/src/prompts/system-prompt.ts +23 -24
  532. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  533. package/src/prompts/templates/SOUL.md +13 -1
  534. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  535. package/src/providers/model-intents.ts +7 -0
  536. package/src/providers/openrouter/client.ts +8 -0
  537. package/src/providers/retry.ts +50 -0
  538. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  539. package/src/providers/types.ts +1 -0
  540. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  541. package/src/runtime/agent-wake.ts +238 -100
  542. package/src/runtime/assistant-event-hub.ts +151 -99
  543. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  544. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  545. package/src/runtime/auth/middleware.ts +0 -96
  546. package/src/runtime/auth/route-policy.ts +32 -0
  547. package/src/runtime/auth/same-actor.ts +216 -0
  548. package/src/runtime/btw-sidechain.ts +2 -3
  549. package/src/runtime/channel-invite-transport.ts +2 -48
  550. package/src/runtime/channel-invite-transports/email.ts +1 -1
  551. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  552. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  553. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  554. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  555. package/src/runtime/channel-invite-types.ts +54 -0
  556. package/src/runtime/channel-readiness-service.ts +32 -13
  557. package/src/runtime/channel-retry-sweep.ts +65 -1
  558. package/src/runtime/guardian-reply-router.ts +10 -0
  559. package/src/runtime/http-server.ts +3 -329
  560. package/src/runtime/http-types.ts +0 -5
  561. package/src/runtime/local-actor-identity.ts +52 -11
  562. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  563. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  564. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  565. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  566. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  567. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  568. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  569. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  570. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  571. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  572. package/src/runtime/migrations/migration-transport.ts +7 -7
  573. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  574. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  575. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  576. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  577. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  578. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  579. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  580. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  581. package/src/runtime/pending-interactions.ts +43 -9
  582. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  583. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  584. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
  585. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  586. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  587. package/src/runtime/routes/approval-interception-types.ts +13 -0
  588. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  589. package/src/runtime/routes/backup-routes.ts +15 -38
  590. package/src/runtime/routes/btw-routes.ts +14 -37
  591. package/src/runtime/routes/client-routes.ts +21 -2
  592. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  593. package/src/runtime/routes/contact-routes.ts +0 -25
  594. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  595. package/src/runtime/routes/conversation-routes.ts +65 -39
  596. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  597. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  598. package/src/runtime/routes/document-pdf-renderer.ts +169 -0
  599. package/src/runtime/routes/documents-routes.ts +32 -75
  600. package/src/runtime/routes/errors.ts +19 -4
  601. package/src/runtime/routes/events-routes.ts +38 -0
  602. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  603. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  604. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  605. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  606. package/src/runtime/routes/host-bash-routes.ts +56 -6
  607. package/src/runtime/routes/host-browser-routes.ts +108 -13
  608. package/src/runtime/routes/host-cu-routes.ts +66 -9
  609. package/src/runtime/routes/host-file-routes.ts +54 -5
  610. package/src/runtime/routes/host-transfer-routes.ts +122 -19
  611. package/src/runtime/routes/http-adapter.ts +1 -0
  612. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  613. package/src/runtime/routes/identity-routes.ts +21 -180
  614. package/src/runtime/routes/inbound-message-handler.ts +78 -21
  615. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  616. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  617. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  618. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  619. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  620. package/src/runtime/routes/index.ts +14 -0
  621. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  622. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  623. package/src/runtime/routes/memory-item-routes.ts +10 -12
  624. package/src/runtime/routes/memory-v2-routes.ts +474 -1
  625. package/src/runtime/routes/migration-routes.ts +96 -0
  626. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  627. package/src/runtime/routes/schedule-routes.ts +7 -0
  628. package/src/runtime/verification-outbound-actions.ts +4 -4
  629. package/src/runtime/verification-templates.ts +4 -7
  630. package/src/schedule/integration-status.ts +66 -2
  631. package/src/schedule/recurrence-engine.ts +4 -1
  632. package/src/schedule/retry-backoff.ts +18 -0
  633. package/src/schedule/retry-policy.ts +82 -0
  634. package/src/schedule/run-script.ts +37 -5
  635. package/src/schedule/schedule-recovery.ts +64 -0
  636. package/src/schedule/schedule-store.ts +106 -2
  637. package/src/schedule/scheduler-types.ts +25 -0
  638. package/src/schedule/scheduler.ts +83 -39
  639. package/src/security/encrypted-store.ts +2 -0
  640. package/src/security/oauth-callback-registry.ts +8 -0
  641. package/src/security/secure-keys.ts +55 -0
  642. package/src/sequence/analytics.ts +5 -5
  643. package/src/sequence/engine.ts +1 -1
  644. package/src/skills/catalog-files.ts +2 -8
  645. package/src/skills/include-graph.ts +5 -5
  646. package/src/skills/remote-skill-policy.ts +10 -16
  647. package/src/skills/skill-file-provider.ts +1 -1
  648. package/src/skills/skill-file-types.ts +13 -0
  649. package/src/skills/skillssh-audit-types.ts +28 -0
  650. package/src/skills/skillssh-registry.ts +8 -21
  651. package/src/subagent/index.ts +1 -7
  652. package/src/subagent/manager.ts +1 -15
  653. package/src/tasks/task-runner.ts +0 -1
  654. package/src/tasks/task-store.ts +0 -3
  655. package/src/telemetry/types.ts +2 -0
  656. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  657. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  658. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  659. package/src/tools/apps/executors.ts +56 -69
  660. package/src/tools/background-tool-registry.ts +17 -3
  661. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  662. package/src/tools/browser/browser-execution.ts +2 -2
  663. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  664. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  665. package/src/tools/browser/cdp-client/factory.ts +23 -24
  666. package/src/tools/browser/cdp-client/index.ts +1 -14
  667. package/src/tools/computer-use/definitions.ts +42 -20
  668. package/src/tools/executor.ts +2 -0
  669. package/src/tools/host-filesystem/edit.test.ts +151 -0
  670. package/src/tools/host-filesystem/edit.ts +68 -0
  671. package/src/tools/host-filesystem/read.test.ts +129 -0
  672. package/src/tools/host-filesystem/read.ts +68 -0
  673. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  674. package/src/tools/host-filesystem/transfer.ts +78 -3
  675. package/src/tools/host-filesystem/write.test.ts +134 -0
  676. package/src/tools/host-filesystem/write.ts +68 -0
  677. package/src/tools/host-terminal/host-shell.ts +66 -1
  678. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  679. package/src/tools/memory/register.test.ts +12 -9
  680. package/src/tools/memory/register.ts +1 -2
  681. package/src/tools/provider-tool-name.ts +28 -0
  682. package/src/tools/registry.ts +30 -9
  683. package/src/tools/schedule/create.ts +6 -0
  684. package/src/tools/schedule/list.ts +2 -0
  685. package/src/tools/schedule/update.ts +10 -0
  686. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  687. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  688. package/src/tools/skills/load.ts +0 -32
  689. package/src/tools/terminal/shell.ts +9 -1
  690. package/src/tools/tool-approval-handler.ts +32 -11
  691. package/src/tools/types.ts +28 -2
  692. package/src/tts/provider-catalog.ts +3 -5
  693. package/src/usage/pricing.ts +1 -1
  694. package/src/util/disk-usage.ts +138 -0
  695. package/src/util/platform.ts +21 -11
  696. package/src/util/process-liveness.ts +26 -0
  697. package/src/workspace/hatched-date.ts +86 -0
  698. package/src/workspace/heartbeat-service.ts +19 -0
  699. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  700. package/src/workspace/migrations/006-services-config.ts +8 -5
  701. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  702. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  703. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  704. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  705. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  706. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  707. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  708. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  709. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  710. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  711. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  712. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  713. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  714. package/src/workspace/migrations/AGENTS.md +1 -1
  715. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  716. package/src/workspace/migrations/registry.ts +8 -0
  717. package/src/workspace/migrations/utils.ts +21 -0
  718. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  719. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  720. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  721. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  722. package/src/__tests__/twilio-rest.test.ts +0 -34
  723. package/src/backup/__tests__/backup-key.test.ts +0 -152
  724. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  725. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  726. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  727. package/src/backup/backup-key.ts +0 -137
  728. package/src/backup/backup-worker.ts +0 -472
  729. package/src/backup/offsite-writer.ts +0 -222
  730. package/src/backup/stream-crypt.ts +0 -263
  731. package/src/daemon/message-types/pairing.ts +0 -58
  732. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  733. package/src/memory/v2/skill-qdrant.ts +0 -395
  734. package/src/outbound-proxy/config.ts +0 -20
  735. package/src/outbound-proxy/health.ts +0 -18
  736. package/src/outbound-proxy/types.ts +0 -150
  737. package/src/runtime/capability-tokens.ts +0 -190
  738. package/src/signals/bash.ts +0 -198
  739. package/src/signals/mcp-reload.ts +0 -18
@@ -12,12 +12,6 @@
12
12
  * creates a socket-based CesTransport. The CES sidecar manages its own
13
13
  * lifecycle; the process manager only manages the transport connection.
14
14
  *
15
- * Feature-flag gate: Managed sidecar mode is controlled by the
16
- * `ces-managed-sidecar` feature flag (checked via the required
17
- * AssistantConfig). When the flag is off, the process manager skips
18
- * managed discovery even in containerized environments, ensuring
19
- * rollback safety.
20
- *
21
15
  * Managed env contract:
22
16
  * - CES_BOOTSTRAP_SOCKET — Path to the bootstrap Unix socket (shared emptyDir)
23
17
  * - /assistant-data-ro — Assistant data mounted read-only into the CES sidecar
@@ -42,7 +36,6 @@ import {
42
36
  type LocalSourceDiscoverySuccess,
43
37
  type ManagedDiscoverySuccess,
44
38
  } from "./executable-discovery.js";
45
- import { isCesManagedSidecarEnabled } from "./feature-gates.js";
46
39
 
47
40
  const log = getLogger("ces-process-manager");
48
41
 
@@ -71,10 +64,8 @@ export const CES_PRIVATE_DATA_DIR = "/ces-data";
71
64
 
72
65
  export interface CesProcessManagerConfig {
73
66
  /**
74
- * Assistant configuration for feature-flag checks.
75
- * The managed sidecar path is gated behind the `ces-managed-sidecar`
76
- * feature flag via this config. When omitted (e.g. CLI / admin
77
- * callers), managed mode is allowed unconditionally.
67
+ * Assistant configuration.
68
+ * Reserved for future feature-flag checks or config-driven behavior.
78
69
  */
79
70
  assistantConfig?: AssistantConfig;
80
71
  }
@@ -88,10 +79,6 @@ export interface CesProcessManager {
88
79
  * Start the CES process (local) or connect to the sidecar (managed).
89
80
  * Returns a CesTransport ready for use with createCesClient().
90
81
  *
91
- * When the `ces-managed-sidecar` feature flag is off, managed mode
92
- * is skipped even in containerized environments — the process manager
93
- * falls back to local discovery.
94
- *
95
82
  * Throws if CES is unavailable.
96
83
  */
97
84
  start(): Promise<CesTransport>;
@@ -118,7 +105,7 @@ export interface CesProcessManager {
118
105
  // ---------------------------------------------------------------------------
119
106
 
120
107
  export function createCesProcessManager(
121
- config: CesProcessManagerConfig,
108
+ _config: CesProcessManagerConfig,
122
109
  ): CesProcessManager {
123
110
  let childProcess: Subprocess | null = null;
124
111
  let managedSocket: Socket | null = null;
@@ -131,31 +118,15 @@ export function createCesProcessManager(
131
118
  throw new Error("CES process manager is already running");
132
119
  }
133
120
 
134
- // Feature-flag gate: when the managed sidecar flag is off, skip
135
- // managed discovery entirely. This ensures rollback safety —
136
- // disabling the flag leaves existing non-agent platform consumers
137
- // intact.
138
- const managedAllowed = config.assistantConfig
139
- ? isCesManagedSidecarEnabled(config.assistantConfig)
140
- : true; // No config → allow managed mode unconditionally (CLI/admin callers)
141
-
142
- if (managedAllowed) {
143
- discoveryResult = await discoverCes();
144
- if (discoveryResult.mode === "unavailable") {
145
- // The managed sidecar bootstrap socket is not present — this happens
146
- // when the flag is enabled by default but the instance pre-dates the
147
- // socket volume mount (e.g. existing Docker configs without the
148
- // ces-bootstrap volume). Warn and fall back to local discovery so
149
- // these deployments don't fail on upgrade.
150
- log.warn(
151
- { reason: discoveryResult.reason },
152
- "CES managed sidecar bootstrap socket unavailable — falling back to local CES discovery",
153
- );
154
- discoveryResult = discoverLocalCes();
155
- }
156
- } else {
157
- log.info(
158
- "CES managed sidecar feature flag is off — skipping managed discovery, falling back to local",
121
+ discoveryResult = await discoverCes();
122
+ if (discoveryResult.mode === "unavailable") {
123
+ // The managed sidecar bootstrap socket is not present — this happens
124
+ // when the instance pre-dates the socket volume mount (e.g. existing
125
+ // Docker configs without the ces-bootstrap volume). Warn and fall
126
+ // back to local discovery so these deployments don't fail on upgrade.
127
+ log.warn(
128
+ { reason: discoveryResult.reason },
129
+ "CES managed sidecar bootstrap socket unavailable — falling back to local CES discovery",
159
130
  );
160
131
  discoveryResult = discoverLocalCes();
161
132
  }
@@ -18,17 +18,45 @@
18
18
  * first and is authoritative for structural support, so host_bash and
19
19
  * host_file_* are filtered out for chrome-extension regardless of the
20
20
  * hasNoClient flag.
21
+ *
22
+ * Cross-client exception: tools whose capabilities are in
23
+ * CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file) are allowed for
24
+ * non-host-proxy interfaces (e.g. "web") when at least one capable client
25
+ * is connected via the event hub. host_browser is excluded (chrome-extension
26
+ * is its own executor; web turns have no CDP target model).
21
27
  */
22
28
 
23
- import { describe, expect, test } from "bun:test";
29
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
30
+
31
+ // ── Module-level mocks ─────────────────────────────────────────────
32
+
33
+ // Control how many capable clients the hub reports per capability.
34
+ const mockClientCountByCapability = new Map<string, number>();
24
35
 
25
- import type { SkillProjectionCache } from "../conversation-skill-tools.js";
26
- import {
36
+ mock.module("../../runtime/assistant-event-hub.js", () => ({
37
+ assistantEventHub: {
38
+ listClientsByCapability: (cap: string) => {
39
+ const count = mockClientCountByCapability.get(cap) ?? 0;
40
+ return Array.from({ length: count }, (_, i) => ({
41
+ clientId: `mock-${cap}-client-${i}`,
42
+ capabilities: [cap],
43
+ }));
44
+ },
45
+ },
46
+ broadcastMessage: () => {},
47
+ }));
48
+
49
+ // Dynamic imports after mock.module calls so the stubs take effect
50
+ // before the modules under test are loaded.
51
+ const {
27
52
  HOST_TOOL_NAMES,
28
53
  HOST_TOOL_TO_CAPABILITY,
29
54
  isToolActiveForContext,
30
- type SkillProjectionContext,
31
- } from "../conversation-tool-setup.js";
55
+ } = await import("../conversation-tool-setup.js");
56
+ type SkillProjectionContext =
57
+ import("../conversation-tool-setup.js").SkillProjectionContext;
58
+ type SkillProjectionCache =
59
+ import("../conversation-skill-tools.js").SkillProjectionCache;
32
60
 
33
61
  function makeCtx(
34
62
  overrides: Partial<SkillProjectionContext> = {},
@@ -42,6 +70,10 @@ function makeCtx(
42
70
  };
43
71
  }
44
72
 
73
+ beforeEach(() => {
74
+ mockClientCountByCapability.clear();
75
+ });
76
+
45
77
  describe("isToolActiveForContext — host tool capability gating", () => {
46
78
  // macOS transport: SSE-based interactive approval required.
47
79
  test("host_bash is active for macOS with a connected client", () => {
@@ -176,6 +208,156 @@ describe("isToolActiveForContext — host tool capability gating", () => {
176
208
  });
177
209
  });
178
210
 
211
+ describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)", () => {
212
+ test("host_bash is active for web transport when a host_bash-capable client is connected", () => {
213
+ // Cross-client path: a web turn should see host_bash when a macOS client
214
+ // with host_bash capability is connected via the event hub.
215
+ mockClientCountByCapability.set("host_bash", 1);
216
+ expect(
217
+ isToolActiveForContext(
218
+ "host_bash",
219
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
220
+ ),
221
+ ).toBe(true);
222
+ });
223
+
224
+ test("host_bash is NOT active for web transport when no capable client is connected", () => {
225
+ // No cross-client fallback: hub has no host_bash-capable subscribers.
226
+ mockClientCountByCapability.set("host_bash", 0);
227
+ expect(
228
+ isToolActiveForContext(
229
+ "host_bash",
230
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
231
+ ),
232
+ ).toBe(false);
233
+ });
234
+
235
+ test("host_file_read is NOT active for web transport when only a host_bash client is connected", () => {
236
+ // The cross-client exception is per-capability: a host_bash-capable
237
+ // client in the hub does not satisfy host_file's exposure check, since
238
+ // listClientsByCapability is queried with the tool's actual capability.
239
+ mockClientCountByCapability.set("host_bash", 1);
240
+ expect(
241
+ isToolActiveForContext(
242
+ "host_file_read",
243
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
244
+ ),
245
+ ).toBe(false);
246
+ });
247
+
248
+ test("host_bash for macos transport is unaffected by the cross-client exception", () => {
249
+ // macos natively supports host_bash via host proxy — the supportsHostProxy
250
+ // check passes, so the cross-client branch is never reached.
251
+ mockClientCountByCapability.set("host_bash", 0);
252
+ expect(
253
+ isToolActiveForContext(
254
+ "host_bash",
255
+ makeCtx({ hasNoClient: false, transportInterface: "macos" }),
256
+ ),
257
+ ).toBe(true);
258
+ });
259
+
260
+ test("host_bash for macos with no client is still denied (security invariant unaffected)", () => {
261
+ // Even with a capable client in the hub, the macos SSE path takes
262
+ // precedence — it passes the supportsHostProxy check, bypasses the
263
+ // cross-client branch, and reaches the hasNoClient gate.
264
+ mockClientCountByCapability.set("host_bash", 1);
265
+ expect(
266
+ isToolActiveForContext(
267
+ "host_bash",
268
+ makeCtx({ hasNoClient: true, transportInterface: "macos" }),
269
+ ),
270
+ ).toBe(false);
271
+ });
272
+
273
+ test("host_bash is NOT active for chrome-extension even when a capable client is connected", () => {
274
+ // Security boundary: chrome-extension only gets host_browser. The
275
+ // cross-client exception explicitly excludes chrome-extension transport
276
+ // regardless of how many host_bash-capable clients are in the hub.
277
+ mockClientCountByCapability.set("host_bash", 1);
278
+ expect(
279
+ isToolActiveForContext(
280
+ "host_bash",
281
+ makeCtx({ hasNoClient: false, transportInterface: "chrome-extension" }),
282
+ ),
283
+ ).toBe(false);
284
+ });
285
+
286
+ test("host_bash is NOT active for web transport when hasNoClient is true (no approval UI)", () => {
287
+ // hasNoClient gate: no interactive approval UI available for this turn.
288
+ // Cross-client exception must not bypass this gate.
289
+ mockClientCountByCapability.set("host_bash", 1);
290
+ expect(
291
+ isToolActiveForContext(
292
+ "host_bash",
293
+ makeCtx({ hasNoClient: true, transportInterface: "web" }),
294
+ ),
295
+ ).toBe(false);
296
+ });
297
+ });
298
+
299
+ describe("isToolActiveForContext — cross-client exposure for host_file_*", () => {
300
+ const HOST_FILE_TOOLS = [
301
+ "host_file_read",
302
+ "host_file_write",
303
+ "host_file_edit",
304
+ "host_file_transfer",
305
+ ] as const;
306
+
307
+ for (const tool of HOST_FILE_TOOLS) {
308
+ test(`${tool} is exposed for web transport when a host_file client is connected`, () => {
309
+ mockClientCountByCapability.set("host_file", 1);
310
+ expect(
311
+ isToolActiveForContext(
312
+ tool,
313
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
314
+ ),
315
+ ).toBe(true);
316
+ });
317
+
318
+ test(`${tool} is NOT exposed for web when no host_file client is connected`, () => {
319
+ mockClientCountByCapability.set("host_file", 0);
320
+ expect(
321
+ isToolActiveForContext(
322
+ tool,
323
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
324
+ ),
325
+ ).toBe(false);
326
+ });
327
+
328
+ test(`${tool} is NOT exposed for chrome-extension (security boundary)`, () => {
329
+ mockClientCountByCapability.set("host_file", 1);
330
+ expect(
331
+ isToolActiveForContext(
332
+ tool,
333
+ makeCtx({ hasNoClient: true, transportInterface: "chrome-extension" }),
334
+ ),
335
+ ).toBe(false);
336
+ });
337
+
338
+ test(`${tool} is NOT exposed when hasNoClient is true (no approval UI)`, () => {
339
+ mockClientCountByCapability.set("host_file", 1);
340
+ expect(
341
+ isToolActiveForContext(
342
+ tool,
343
+ makeCtx({ hasNoClient: true, transportInterface: "web" }),
344
+ ),
345
+ ).toBe(false);
346
+ });
347
+ }
348
+
349
+ test("listClientsByCapability is queried with the actual capability, not host_bash (regression guard for D5 latent bug)", () => {
350
+ mockClientCountByCapability.set("host_bash", 0);
351
+ mockClientCountByCapability.set("host_file", 1);
352
+ expect(
353
+ isToolActiveForContext(
354
+ "host_file_transfer",
355
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
356
+ ),
357
+ ).toBe(true);
358
+ });
359
+ });
360
+
179
361
  describe("HOST_TOOL_NAMES derivation", () => {
180
362
  test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
181
363
  // Sanity check: every tool in the names set has a capability mapping.
@@ -125,7 +125,7 @@ export function classifyKind(mimeType: string): "image" | "video" | "document" {
125
125
  // Validation / cap enforcement
126
126
  // ---------------------------------------------------------------------------
127
127
 
128
- export interface ValidatedDrafts {
128
+ interface ValidatedDrafts {
129
129
  accepted: AssistantAttachmentDraft[];
130
130
  warnings: string[];
131
131
  }
@@ -171,13 +171,13 @@ export interface DirectiveRequest {
171
171
  mimeType: string | undefined;
172
172
  }
173
173
 
174
- export interface DirectiveParseResult {
174
+ interface DirectiveParseResult {
175
175
  cleanText: string;
176
176
  directiveRequests: DirectiveRequest[];
177
177
  parseWarnings: string[];
178
178
  }
179
179
 
180
- export interface DirectiveDisplayDrainResult {
180
+ interface DirectiveDisplayDrainResult {
181
181
  emitText: string;
182
182
  bufferedRemainder: string;
183
183
  }
@@ -362,7 +362,7 @@ export function drainDirectiveDisplayBuffer(
362
362
  // Sandbox file resolution
363
363
  // ---------------------------------------------------------------------------
364
364
 
365
- export interface ResolveResult {
365
+ interface ResolveResult {
366
366
  draft: AssistantAttachmentDraft | null;
367
367
  warning: string | null;
368
368
  }
@@ -0,0 +1,45 @@
1
+ import { getMessages, type MessageRow } from "../memory/conversation-crud.js";
2
+ import { cleanupBootstrapFiles } from "../prompts/bootstrap-cleanup.js";
3
+ import { getLogger } from "../util/logger.js";
4
+
5
+ export const BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD = 4;
6
+
7
+ const log = getLogger("bootstrap-turn-cleanup");
8
+
9
+ function isWakeUpGreetingMessage(content: string): boolean {
10
+ return content.toLowerCase().includes("wake up, my friend");
11
+ }
12
+
13
+ export function countBootstrapUserTurns(
14
+ messages: Pick<MessageRow, "role" | "content">[],
15
+ ): number {
16
+ return messages.filter(
17
+ (message) =>
18
+ message.role === "user" && !isWakeUpGreetingMessage(message.content),
19
+ ).length;
20
+ }
21
+
22
+ export function shouldCleanupBootstrapAfterTurn(
23
+ messages: Pick<MessageRow, "role" | "content">[],
24
+ threshold = BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD,
25
+ ): boolean {
26
+ return countBootstrapUserTurns(messages) >= threshold;
27
+ }
28
+
29
+ export function cleanupBootstrapAfterTurnThreshold(
30
+ conversationId: string,
31
+ ): boolean {
32
+ let messages: MessageRow[];
33
+ try {
34
+ messages = getMessages(conversationId);
35
+ } catch (err) {
36
+ log.warn({ err, conversationId }, "Failed to inspect bootstrap turn count");
37
+ return false;
38
+ }
39
+
40
+ if (!shouldCleanupBootstrapAfterTurn(messages)) return false;
41
+
42
+ return cleanupBootstrapFiles(
43
+ `first conversation reached ${BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD} user turns`,
44
+ );
45
+ }
@@ -8,7 +8,9 @@ import {
8
8
  type FSWatcher,
9
9
  mkdirSync,
10
10
  readdirSync,
11
+ unwatchFile,
11
12
  watch,
13
+ watchFile,
12
14
  } from "node:fs";
13
15
  import { join } from "node:path";
14
16
 
@@ -17,11 +19,9 @@ import type { MemoryCleanupConfig } from "../config/schemas/memory-lifecycle.js"
17
19
  import { resetCleanupScheduleThrottle } from "../memory/cleanup-schedule-state.js";
18
20
  import { clearEmbeddingBackendCache } from "../memory/embedding-backend.js";
19
21
  import { initializeProviders } from "../providers/registry.js";
20
- import { handleBashSignal } from "../signals/bash.js";
21
22
  import { handleCancelSignal } from "../signals/cancel.js";
22
23
  import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
23
24
  import { handleEmitEventSignal } from "../signals/emit-event.js";
24
- import { handleMcpReloadSignal } from "../signals/mcp-reload.js";
25
25
  import { handleUserMessageSignal } from "../signals/user-message.js";
26
26
  import { DebouncerMap } from "../util/debounce.js";
27
27
  import { getLogger } from "../util/logger.js";
@@ -33,6 +33,7 @@ import {
33
33
  getWorkspaceDir,
34
34
  getWorkspaceSkillsDir,
35
35
  } from "../util/platform.js";
36
+ import { reloadMcpServers } from "./mcp-reload-service.js";
36
37
 
37
38
  const log = getLogger("config-watcher");
38
39
 
@@ -47,19 +48,44 @@ function attachWatcherErrorHandler(watcher: FSWatcher, dir: string): void {
47
48
  });
48
49
  }
49
50
 
51
+ /**
52
+ * Poll interval for `fs.watchFile()`. Use the stat-polling watcher
53
+ * because Bun's per-file `fs.watch()` doesn't detect renames on Linux
54
+ * (seemingly works on macOS). See https://github.com/oven-sh/bun/issues/15010.
55
+ */
56
+ const WATCH_FILE_POLL_MS = 2_000;
57
+
50
58
  export class ConfigWatcher {
51
59
  private watchers: FSWatcher[] = [];
52
- private debounceTimers = new DebouncerMap({
53
- defaultDelayMs: 200,
54
- maxEntries: 1000,
55
- protectedKeyPrefix: "__",
56
- });
60
+ private watchedFiles: Set<string> = new Set();
61
+ private stopped = false;
62
+ private debounceTimers: DebouncerMap;
57
63
  private suppressReload = false;
58
64
  lastFingerprint = "";
65
+ private lastConfig: ReturnType<typeof getConfig> | null = null;
59
66
  private lastRefreshTime = 0;
60
67
 
61
68
  static readonly REFRESH_INTERVAL_MS = 30_000;
62
69
 
70
+ /**
71
+ * @param pollIntervalMs Per-file stat poll interval (passed to
72
+ * `fs.watchFile`). Default `WATCH_FILE_POLL_MS` (2s); tests pass a
73
+ * smaller value for fast turnaround.
74
+ * @param debounceMs Debounce window applied to any detected file
75
+ * change before invoking its handler. Default 200ms; tests pass a
76
+ * smaller value to avoid sleeping unnecessarily.
77
+ */
78
+ constructor(
79
+ private readonly pollIntervalMs: number = WATCH_FILE_POLL_MS,
80
+ debounceMs = 200,
81
+ ) {
82
+ this.debounceTimers = new DebouncerMap({
83
+ defaultDelayMs: debounceMs,
84
+ maxEntries: 1000,
85
+ protectedKeyPrefix: "__",
86
+ });
87
+ }
88
+
63
89
  /** Expose the debounce timers so handlers can schedule debounced work. */
64
90
  get timers(): DebouncerMap {
65
91
  return this.debounceTimers;
@@ -88,12 +114,15 @@ export class ConfigWatcher {
88
114
 
89
115
  /** Initialize the config fingerprint (call after first config load). */
90
116
  initFingerprint(config: ReturnType<typeof getConfig>): void {
117
+ this.lastConfig = config;
91
118
  this.lastFingerprint = this.configFingerprint(config);
92
119
  }
93
120
 
94
121
  /** Update the fingerprint to match the current config. */
95
122
  updateFingerprint(): void {
96
- this.lastFingerprint = this.configFingerprint(getConfig());
123
+ const config = getConfig();
124
+ this.lastConfig = config;
125
+ this.lastFingerprint = this.configFingerprint(config);
97
126
  this.lastRefreshTime = Date.now();
98
127
  }
99
128
 
@@ -103,7 +132,7 @@ export class ConfigWatcher {
103
132
  * Returns true if config actually changed.
104
133
  */
105
134
  async refreshConfigFromSources(): Promise<boolean> {
106
- const prevCleanup = safeGetCleanupConfig();
135
+ const prevCleanup = this.lastConfig?.memory?.cleanup;
107
136
  invalidateConfigCache();
108
137
  const config = getConfig();
109
138
  const fingerprint = this.configFingerprint(config);
@@ -120,6 +149,7 @@ export class ConfigWatcher {
120
149
  }
121
150
  const isFirstInit = this.lastFingerprint === "";
122
151
  await initializeProviders(config);
152
+ this.lastConfig = config;
123
153
  this.lastFingerprint = fingerprint;
124
154
  return !isFirstInit;
125
155
  }
@@ -136,22 +166,29 @@ export class ConfigWatcher {
136
166
  onAvatarChanged?: () => void,
137
167
  onConfigChanged?: () => void,
138
168
  ): void {
169
+ // Reset the stopped flag so a stop()→start() cycle on the same
170
+ // instance resumes hot-reload instead of silently bailing in every
171
+ // watchFile callback. This matters because getConfigWatcher() is a
172
+ // module-level singleton — a daemon restart path that reuses it
173
+ // would otherwise be permanently mute.
174
+ this.stopped = false;
139
175
  const workspaceDir = getWorkspaceDir();
140
176
 
141
177
  const workspaceHandlers: Record<string, () => void> = {
142
178
  "config.json": async () => {
143
179
  if (this.suppressReload) return;
144
180
  try {
145
- const prevConfig = getConfig();
146
- const prevMcpFingerprint = JSON.stringify(prevConfig.mcp ?? {});
181
+ const prevMcpFingerprint = JSON.stringify(this.lastConfig?.mcp ?? {});
147
182
  const changed = await this.refreshConfigFromSources();
148
183
  if (changed) {
149
184
  onConversationEvict();
150
185
  onConfigChanged?.();
151
- const newConfig = getConfig();
186
+ const newConfig = this.lastConfig ?? getConfig();
152
187
  const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
153
188
  if (newMcpFingerprint !== prevMcpFingerprint) {
154
- handleMcpReloadSignal();
189
+ reloadMcpServers().catch((err: unknown) => {
190
+ log.error({ err }, "MCP reload after config change failed");
191
+ });
155
192
  }
156
193
  }
157
194
  } catch (err) {
@@ -168,37 +205,11 @@ export class ConfigWatcher {
168
205
  },
169
206
  };
170
207
 
171
- const watchDir = (
172
- dir: string,
173
- handlers: Record<string, () => void>,
174
- label: string,
175
- ): void => {
176
- try {
177
- const watcher = watch(dir, (_eventType, filename) => {
178
- if (!filename) return;
179
- const file = String(filename);
180
- if (!handlers[file]) return;
181
- this.debounceTimers.schedule(`file:${file}`, () => {
182
- log.info({ file }, "File changed, reloading");
183
- handlers[file]();
184
- });
185
- });
186
- attachWatcherErrorHandler(watcher, dir);
187
- this.watchers.push(watcher);
188
- log.info({ dir }, `Watching ${label}`);
189
- } catch (err) {
190
- log.warn(
191
- { err, dir },
192
- `Failed to watch ${label}. Hot-reload will be unavailable.`,
193
- );
194
- }
195
- };
196
-
197
- watchDir(
198
- workspaceDir,
199
- workspaceHandlers,
200
- "workspace directory for config/prompt changes",
201
- );
208
+ // Per-file watches; don't watch the workspace directory itself because
209
+ // it contains socket files.
210
+ for (const [filename, handler] of Object.entries(workspaceHandlers)) {
211
+ this.watchFile(join(workspaceDir, filename), handler, filename);
212
+ }
202
213
 
203
214
  if (onSoundsConfigChanged) {
204
215
  this.startSoundsWatcher(onSoundsConfigChanged);
@@ -213,13 +224,46 @@ export class ConfigWatcher {
213
224
  }
214
225
 
215
226
  stop(): void {
227
+ this.stopped = true;
216
228
  this.debounceTimers.cancelAll();
229
+ for (const filePath of this.watchedFiles) {
230
+ unwatchFile(filePath);
231
+ }
232
+ this.watchedFiles.clear();
217
233
  for (const watcher of this.watchers) {
218
234
  watcher.close();
219
235
  }
220
236
  this.watchers = [];
221
237
  }
222
238
 
239
+ private watchFile(
240
+ filePath: string,
241
+ handler: () => void,
242
+ label: string,
243
+ ): void {
244
+ // Match the defensive pattern used by every other startXWatcher in
245
+ // this file: log the failure and continue. Per AGENTS.md, the daemon
246
+ // must never block startup — a watchFile() throw on some platform
247
+ // edge case must not propagate up to DaemonServer.start().
248
+ try {
249
+ watchFile(filePath, { interval: this.pollIntervalMs }, (curr, prev) => {
250
+ if (this.stopped) return;
251
+ if (curr.ino === prev.ino && curr.mtimeMs === prev.mtimeMs) return;
252
+ this.debounceTimers.schedule(`file:${filePath}`, () => {
253
+ log.info({ file: filePath }, "File changed, reloading");
254
+ handler();
255
+ });
256
+ });
257
+ this.watchedFiles.add(filePath);
258
+ log.info({ file: filePath }, `Watching ${label}`);
259
+ } catch (err) {
260
+ log.warn(
261
+ { err, file: filePath },
262
+ `Failed to watch ${label}. Hot-reload will be unavailable until restart.`,
263
+ );
264
+ }
265
+ }
266
+
223
267
  private startSoundsWatcher(onSoundsConfigChanged: () => void): void {
224
268
  const soundsDir = getSoundsDir();
225
269
  try {
@@ -331,7 +375,6 @@ export class ConfigWatcher {
331
375
 
332
376
  const exactSignalHandlers: Record<string, () => void | Promise<void>> = {
333
377
  cancel: handleCancelSignal,
334
- "mcp-reload": handleMcpReloadSignal,
335
378
  "conversation-undo": handleConversationUndoSignal,
336
379
  "emit-event": handleEmitEventSignal,
337
380
  };
@@ -340,7 +383,6 @@ export class ConfigWatcher {
340
383
  string,
341
384
  (filename: string) => void | Promise<void>
342
385
  > = {
343
- "bash.": handleBashSignal,
344
386
  "user-message.": handleUserMessageSignal,
345
387
  };
346
388
 
@@ -485,20 +527,6 @@ export class ConfigWatcher {
485
527
  }
486
528
  }
487
529
 
488
- /**
489
- * Snapshot the current cleanup config so we can compare it against the
490
- * post-reload value. Tolerant of config-load failures — if the config can't
491
- * be read (e.g. first-load), returns undefined so the comparison below
492
- * treats it as "no previous value".
493
- */
494
- function safeGetCleanupConfig(): MemoryCleanupConfig | undefined {
495
- try {
496
- return getConfig().memory?.cleanup;
497
- } catch {
498
- return undefined;
499
- }
500
- }
501
-
502
530
  /**
503
531
  * Return true if any cleanup field the user can change via the UI differs
504
532
  * between the previous and next config snapshots. Used to decide whether to
@@ -529,6 +557,7 @@ export function cleanupSettingsChanged(
529
557
  return (
530
558
  prev.llmRequestLogRetentionMs !== next.llmRequestLogRetentionMs ||
531
559
  prev.conversationRetentionDays !== next.conversationRetentionDays ||
560
+ prev.traceEventRetentionDays !== next.traceEventRetentionDays ||
532
561
  prev.enabled !== next.enabled
533
562
  );
534
563
  }