@vellumai/assistant 0.7.2 → 0.8.0

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 (424) hide show
  1. package/ARCHITECTURE.md +45 -29
  2. package/Dockerfile +1 -0
  3. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  4. package/bun.lock +3 -0
  5. package/docs/architecture/memory.md +5 -2
  6. package/knip.json +1 -0
  7. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  8. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  9. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  10. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  11. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  12. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  13. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  14. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  16. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  17. package/openapi.yaml +470 -25
  18. package/package.json +3 -1
  19. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  20. package/src/__tests__/app-control-flow.test.ts +21 -11
  21. package/src/__tests__/approval-cascade.test.ts +8 -16
  22. package/src/__tests__/approval-routes-http.test.ts +6 -0
  23. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  24. package/src/__tests__/assistant-event.test.ts +0 -10
  25. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  26. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  27. package/src/__tests__/auto-analysis-end-to-end.test.ts +48 -0
  28. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  29. package/src/__tests__/call-constants.test.ts +10 -1
  30. package/src/__tests__/call-controller.test.ts +127 -0
  31. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  32. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  33. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  34. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +58 -28
  35. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  36. package/src/__tests__/config-loader-platform-defaults.test.ts +284 -1
  37. package/src/__tests__/config-schema.test.ts +1 -0
  38. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  39. package/src/__tests__/config-watcher.test.ts +140 -69
  40. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  41. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  42. package/src/__tests__/context-search-fanout.test.ts +0 -1
  43. package/src/__tests__/context-search-memory-source.test.ts +6 -33
  44. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  45. package/src/__tests__/context-search-pkb-source.test.ts +12 -7
  46. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  47. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -0
  48. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  49. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  50. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
  51. package/src/__tests__/conversation-agent-loop.test.ts +457 -8
  52. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  53. package/src/__tests__/conversation-error.test.ts +150 -3
  54. package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
  55. package/src/__tests__/conversation-process-callsite.test.ts +38 -0
  56. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
  57. package/src/__tests__/conversation-runtime-assembly.test.ts +74 -0
  58. package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
  59. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  60. package/src/__tests__/conversation-store.test.ts +0 -18
  61. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  62. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  63. package/src/__tests__/conversation-surfaces-data-persist.test.ts +476 -0
  64. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +61 -5
  65. package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
  66. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
  67. package/src/__tests__/credentials-cli.test.ts +7 -0
  68. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  69. package/src/__tests__/date-context.test.ts +164 -2
  70. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  71. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  72. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  73. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  74. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  75. package/src/__tests__/disk-usage.test.ts +150 -0
  76. package/src/__tests__/events-client-registration.test.ts +52 -0
  77. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  78. package/src/__tests__/file-write-tool.test.ts +4 -10
  79. package/src/__tests__/filing-service.test.ts +2 -20
  80. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -26
  81. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  82. package/src/__tests__/heartbeat-service.test.ts +260 -11
  83. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  84. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  85. package/src/__tests__/host-bash-routes.test.ts +178 -13
  86. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  87. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  88. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  89. package/src/__tests__/host-file-proxy.test.ts +268 -6
  90. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  91. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  92. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  93. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  94. package/src/__tests__/injector-chain.test.ts +36 -16
  95. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  96. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  97. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +154 -67
  98. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  99. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  100. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  101. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  102. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  103. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  104. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  105. package/src/__tests__/oauth-cli.test.ts +121 -0
  106. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  107. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  108. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  109. package/src/__tests__/openai-provider.test.ts +45 -8
  110. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  111. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  112. package/src/__tests__/platform.test.ts +2 -1
  113. package/src/__tests__/playbook-execution.test.ts +0 -43
  114. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  115. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  116. package/src/__tests__/provider-tool-name.test.ts +23 -0
  117. package/src/__tests__/relay-server.test.ts +60 -5
  118. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  119. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  120. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  121. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  122. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  123. package/src/__tests__/secret-response-routing.test.ts +7 -5
  124. package/src/__tests__/server-history-render.test.ts +82 -0
  125. package/src/__tests__/skill-include-graph.test.ts +31 -0
  126. package/src/__tests__/skill-load-tool.test.ts +44 -16
  127. package/src/__tests__/skills.test.ts +39 -0
  128. package/src/__tests__/suggestion-routes.test.ts +46 -0
  129. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  130. package/src/__tests__/tool-executor.test.ts +155 -0
  131. package/src/__tests__/twilio-validation.test.ts +2 -2
  132. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  133. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  134. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  135. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  136. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +120 -0
  137. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  138. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +78 -0
  139. package/src/agent/loop.ts +11 -0
  140. package/src/approvals/guardian-request-resolvers.ts +3 -32
  141. package/src/backup/snapshot-lock.ts +2 -27
  142. package/src/bundler/compiler-tools.ts +3 -2
  143. package/src/calls/call-constants.ts +5 -8
  144. package/src/calls/call-controller.ts +130 -67
  145. package/src/calls/call-conversation-messages.ts +46 -10
  146. package/src/calls/relay-server.ts +7 -1
  147. package/src/calls/voice-session-bridge.ts +1 -1
  148. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  149. package/src/cli/commands/bash.ts +35 -108
  150. package/src/cli/commands/contacts.ts +64 -25
  151. package/src/cli/commands/credentials.ts +56 -0
  152. package/src/cli/commands/memory-v2.ts +11 -10
  153. package/src/cli/commands/oauth/__tests__/connect.test.ts +401 -219
  154. package/src/cli/commands/oauth/connect.ts +124 -40
  155. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  156. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  157. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  158. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  159. package/src/cli/commands/platform/index.ts +16 -7
  160. package/src/cli/commands/status.ts +57 -0
  161. package/src/cli/program.ts +4 -2
  162. package/src/config/assistant-feature-flags.ts +13 -3
  163. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  164. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  165. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  166. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  167. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  168. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  169. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  170. package/src/config/env.ts +0 -8
  171. package/src/config/feature-flag-registry.json +13 -5
  172. package/src/config/loader.ts +199 -27
  173. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  174. package/src/config/schemas/call-site-catalog.ts +14 -0
  175. package/src/config/schemas/channels.ts +0 -5
  176. package/src/config/schemas/heartbeat.ts +1 -1
  177. package/src/config/schemas/llm.ts +2 -0
  178. package/src/config/schemas/memory-lifecycle.ts +13 -0
  179. package/src/config/schemas/memory-v2.ts +76 -12
  180. package/src/config/schemas/platform.ts +43 -3
  181. package/src/config/schemas/services.ts +28 -0
  182. package/src/config/seed-inference-profiles.ts +230 -33
  183. package/src/contacts/contact-store.ts +0 -25
  184. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +32 -0
  185. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  186. package/src/daemon/assistant-attachments.ts +4 -4
  187. package/src/daemon/config-watcher.ts +85 -57
  188. package/src/daemon/conversation-agent-loop-handlers.ts +38 -0
  189. package/src/daemon/conversation-agent-loop.ts +183 -43
  190. package/src/daemon/conversation-error.ts +87 -15
  191. package/src/daemon/conversation-lifecycle.ts +22 -10
  192. package/src/daemon/conversation-process.ts +8 -0
  193. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  194. package/src/daemon/conversation-store.ts +2 -2
  195. package/src/daemon/conversation-surfaces.ts +211 -29
  196. package/src/daemon/conversation-tool-setup.ts +66 -19
  197. package/src/daemon/conversation.ts +18 -23
  198. package/src/daemon/date-context.ts +71 -22
  199. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  200. package/src/daemon/disk-pressure-guard.ts +343 -0
  201. package/src/daemon/disk-pressure-policy.ts +163 -0
  202. package/src/daemon/handlers/shared.ts +26 -1
  203. package/src/daemon/handlers/skills.ts +3 -4
  204. package/src/daemon/host-app-control-proxy.ts +137 -41
  205. package/src/daemon/host-bash-proxy.ts +47 -22
  206. package/src/daemon/host-browser-proxy.ts +1 -1
  207. package/src/daemon/host-cu-proxy.ts +50 -4
  208. package/src/daemon/host-file-proxy.ts +44 -8
  209. package/src/daemon/host-transfer-proxy.ts +97 -6
  210. package/src/daemon/lifecycle.ts +167 -101
  211. package/src/daemon/meet-host-supervisor.ts +4 -4
  212. package/src/daemon/meet-manifest-loader.ts +0 -1
  213. package/src/daemon/memory-v2-startup.ts +66 -15
  214. package/src/daemon/message-protocol.ts +3 -0
  215. package/src/daemon/message-types/conversations.ts +4 -0
  216. package/src/daemon/message-types/disk-pressure.ts +9 -0
  217. package/src/daemon/message-types/messages.ts +22 -1
  218. package/src/daemon/profiler-run-store.ts +5 -5
  219. package/src/daemon/tool-setup-types.ts +2 -2
  220. package/src/documents/document-store.ts +119 -0
  221. package/src/filing/filing-service.ts +29 -5
  222. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  223. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  224. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  225. package/src/heartbeat/heartbeat-service.ts +205 -31
  226. package/src/home/feed-scheduler.ts +18 -0
  227. package/src/inbound/platform-callback-registration.ts +8 -15
  228. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  229. package/src/ipc/assistant-server.ts +149 -38
  230. package/src/ipc/gateway-client.ts +37 -3
  231. package/src/ipc/skill-server.ts +99 -42
  232. package/src/live-voice/live-voice-archive.ts +4 -4
  233. package/src/live-voice/protocol.ts +5 -7
  234. package/src/media/image-service.ts +1 -7
  235. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  236. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +34 -51
  237. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  238. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  239. package/src/memory/admin.ts +5 -9
  240. package/src/memory/context-search/agent-runner.ts +19 -2
  241. package/src/memory/context-search/sources/conversations.ts +2 -11
  242. package/src/memory/context-search/sources/memory-v2.ts +1 -16
  243. package/src/memory/context-search/sources/memory.ts +2 -3
  244. package/src/memory/context-search/sources/pkb.ts +2 -3
  245. package/src/memory/context-search/types.ts +0 -1
  246. package/src/memory/conversation-crud.ts +4 -12
  247. package/src/memory/db-init.ts +2 -0
  248. package/src/memory/embedding-runtime-manager.ts +119 -5
  249. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +136 -82
  250. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  251. package/src/memory/graph/conversation-graph-memory.ts +72 -61
  252. package/src/memory/graph/extraction.ts +1 -3
  253. package/src/memory/graph/graph-search.test.ts +11 -67
  254. package/src/memory/graph/graph-search.ts +4 -24
  255. package/src/memory/graph/retriever.test.ts +12 -1
  256. package/src/memory/graph/retriever.ts +10 -15
  257. package/src/memory/graph/tool-handlers.ts +3 -4
  258. package/src/memory/graph/tools.ts +4 -4
  259. package/src/memory/indexer.ts +53 -45
  260. package/src/memory/job-handlers/backfill.ts +2 -11
  261. package/src/memory/job-handlers/cleanup.ts +43 -0
  262. package/src/memory/job-handlers/embedding.ts +6 -8
  263. package/src/memory/job-handlers/summarization.ts +2 -7
  264. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +116 -0
  265. package/src/memory/jobs/embed-concept-page.ts +223 -87
  266. package/src/memory/jobs-store.ts +48 -0
  267. package/src/memory/jobs-worker.ts +85 -43
  268. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  269. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  270. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  271. package/src/memory/migrations/index.ts +1 -0
  272. package/src/memory/pkb/pkb-search.test.ts +7 -0
  273. package/src/memory/pkb/pkb-search.ts +4 -5
  274. package/src/memory/qdrant-client.ts +3 -13
  275. package/src/memory/rerank-local.ts +374 -0
  276. package/src/memory/search/semantic.ts +10 -72
  277. package/src/memory/trace-event-store.ts +1 -17
  278. package/src/memory/v2/__tests__/activation.test.ts +346 -255
  279. package/src/memory/v2/__tests__/consolidation-job.test.ts +61 -40
  280. package/src/memory/v2/__tests__/injection.test.ts +297 -190
  281. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  282. package/src/memory/v2/__tests__/qdrant.test.ts +326 -9
  283. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  284. package/src/memory/v2/__tests__/sim.test.ts +113 -196
  285. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  286. package/src/memory/v2/__tests__/static-context.test.ts +77 -14
  287. package/src/memory/v2/__tests__/sweep-job.test.ts +19 -33
  288. package/src/memory/v2/activation.ts +149 -156
  289. package/src/memory/v2/consolidation-job.ts +69 -20
  290. package/src/memory/v2/injection.ts +75 -68
  291. package/src/memory/v2/page-store.ts +39 -0
  292. package/src/memory/v2/prompts/consolidation.ts +41 -1
  293. package/src/memory/v2/qdrant.ts +306 -46
  294. package/src/memory/v2/reranker.ts +177 -0
  295. package/src/memory/v2/sim.ts +77 -110
  296. package/src/memory/v2/skill-content.ts +4 -3
  297. package/src/memory/v2/skill-store.ts +82 -59
  298. package/src/memory/v2/static-context.ts +26 -8
  299. package/src/memory/v2/sweep-job.ts +5 -6
  300. package/src/memory/v2/types.ts +17 -10
  301. package/src/notifications/copy-composer.ts +47 -0
  302. package/src/notifications/decision-engine.ts +46 -0
  303. package/src/notifications/signal.ts +4 -0
  304. package/src/oauth/AGENTS.md +3 -1
  305. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  306. package/src/oauth/connect-orchestrator.ts +2 -0
  307. package/src/oauth/connection-resolver.test.ts +66 -1
  308. package/src/oauth/connection-resolver.ts +55 -1
  309. package/src/oauth/oauth-connect-state.ts +77 -0
  310. package/src/oauth/seed-providers.ts +58 -1
  311. package/src/permissions/gateway-threshold-reader.ts +116 -8
  312. package/src/permissions/prompter.ts +86 -96
  313. package/src/permissions/secret-prompter.ts +31 -31
  314. package/src/plugins/defaults/injectors.ts +36 -4
  315. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  316. package/src/plugins/types.ts +7 -0
  317. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  318. package/src/proactive-artifact/decision.test.ts +226 -0
  319. package/src/proactive-artifact/decision.ts +165 -0
  320. package/src/proactive-artifact/index.ts +7 -0
  321. package/src/proactive-artifact/job.test.ts +914 -0
  322. package/src/proactive-artifact/job.ts +366 -0
  323. package/src/proactive-artifact/message-copy.ts +58 -0
  324. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  325. package/src/proactive-artifact/trigger-state.ts +119 -0
  326. package/src/prompts/normalize-onboarding.ts +80 -0
  327. package/src/prompts/persona-resolver.ts +101 -9
  328. package/src/prompts/system-prompt.ts +21 -7
  329. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  330. package/src/prompts/templates/SOUL.md +13 -28
  331. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  332. package/src/providers/model-intents.ts +7 -0
  333. package/src/providers/openrouter/client.ts +8 -0
  334. package/src/providers/retry.ts +50 -0
  335. package/src/providers/types.ts +1 -0
  336. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  337. package/src/runtime/agent-wake.ts +238 -100
  338. package/src/runtime/assistant-event-hub.ts +36 -6
  339. package/src/runtime/assistant-event.ts +0 -1
  340. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  341. package/src/runtime/auth/route-policy.ts +15 -1
  342. package/src/runtime/auth/same-actor.ts +216 -0
  343. package/src/runtime/channel-approvals.ts +3 -2
  344. package/src/runtime/channel-retry-sweep.ts +65 -1
  345. package/src/runtime/local-actor-identity.ts +52 -11
  346. package/src/runtime/pending-interactions.ts +27 -15
  347. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  348. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  349. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  350. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  351. package/src/runtime/routes/approval-routes.ts +7 -3
  352. package/src/runtime/routes/client-routes.ts +20 -2
  353. package/src/runtime/routes/consolidation-routes.ts +8 -9
  354. package/src/runtime/routes/contact-routes.ts +0 -25
  355. package/src/runtime/routes/conversation-query-routes.ts +44 -1
  356. package/src/runtime/routes/conversation-routes.ts +35 -26
  357. package/src/runtime/routes/debug-bash-routes.ts +165 -0
  358. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  359. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  360. package/src/runtime/routes/documents-routes.ts +2 -75
  361. package/src/runtime/routes/events-routes.ts +41 -9
  362. package/src/runtime/routes/filing-routes.ts +2 -3
  363. package/src/runtime/routes/host-bash-routes.ts +23 -3
  364. package/src/runtime/routes/host-cu-routes.ts +33 -6
  365. package/src/runtime/routes/host-file-routes.ts +32 -6
  366. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  367. package/src/runtime/routes/identity-routes.ts +7 -138
  368. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  369. package/src/runtime/routes/index.ts +6 -0
  370. package/src/runtime/routes/memory-item-routes.test.ts +37 -17
  371. package/src/runtime/routes/memory-item-routes.ts +5 -6
  372. package/src/runtime/routes/memory-v2-routes.ts +136 -17
  373. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  374. package/src/runtime/verification-outbound-actions.ts +4 -4
  375. package/src/schedule/run-script.ts +37 -5
  376. package/src/schedule/scheduler.ts +20 -1
  377. package/src/security/encrypted-store.ts +2 -0
  378. package/src/security/secure-keys.ts +55 -0
  379. package/src/skills/include-graph.ts +35 -13
  380. package/src/skills/remote-skill-policy.ts +4 -10
  381. package/src/subagent/index.ts +1 -7
  382. package/src/subagent/manager.ts +1 -15
  383. package/src/tasks/task-runner.ts +0 -1
  384. package/src/tasks/task-store.ts +0 -3
  385. package/src/tools/background-tool-registry.ts +17 -3
  386. package/src/tools/document/document-tool.ts +20 -0
  387. package/src/tools/executor.ts +18 -2
  388. package/src/tools/host-filesystem/edit.test.ts +151 -0
  389. package/src/tools/host-filesystem/edit.ts +43 -1
  390. package/src/tools/host-filesystem/read.test.ts +129 -0
  391. package/src/tools/host-filesystem/read.ts +43 -1
  392. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  393. package/src/tools/host-filesystem/transfer.ts +56 -11
  394. package/src/tools/host-filesystem/write.test.ts +134 -0
  395. package/src/tools/host-filesystem/write.ts +43 -1
  396. package/src/tools/host-terminal/host-shell.ts +13 -6
  397. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  398. package/src/tools/memory/register.test.ts +14 -9
  399. package/src/tools/memory/register.ts +1 -2
  400. package/src/tools/permission-checker.ts +15 -0
  401. package/src/tools/provider-tool-name.ts +28 -0
  402. package/src/tools/registry.ts +30 -9
  403. package/src/tools/skills/load.ts +24 -20
  404. package/src/tools/terminal/shell.ts +9 -1
  405. package/src/tools/tool-approval-handler.ts +31 -6
  406. package/src/tools/tool-name-aliases.ts +19 -0
  407. package/src/tools/types.ts +43 -3
  408. package/src/tts/provider-catalog.ts +3 -5
  409. package/src/util/disk-usage.ts +138 -0
  410. package/src/util/platform.ts +21 -11
  411. package/src/util/process-liveness.ts +26 -0
  412. package/src/workspace/heartbeat-service.ts +19 -0
  413. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  414. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  415. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +14 -0
  416. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  417. package/src/workspace/migrations/069-seed-onboarding-threads.ts +28 -0
  418. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  419. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  420. package/src/workspace/migrations/registry.ts +14 -0
  421. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  422. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  423. package/src/memory/v2/skill-qdrant.ts +0 -404
  424. package/src/signals/bash.ts +0 -198
@@ -0,0 +1,206 @@
1
+ import {
2
+ existsSync,
3
+ mkdtempSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import {
11
+ afterAll,
12
+ afterEach,
13
+ beforeAll,
14
+ beforeEach,
15
+ describe,
16
+ expect,
17
+ test,
18
+ } from "bun:test";
19
+
20
+ import { removeSafeStorageReleaseNoteMigration } from "../workspace/migrations/071-remove-safe-storage-release-note.js";
21
+
22
+ const MIGRATION_ID = "071-remove-safe-storage-release-note";
23
+ const SAFE_STORAGE_MARKER =
24
+ "<!-- release-note-id:067-release-notes-safe-storage-limits -->";
25
+ const LATER_MARKER =
26
+ "<!-- release-note-id:068-release-notes-local-timezone -->";
27
+
28
+ const SAFE_STORAGE_RELEASE_NOTE = `${SAFE_STORAGE_MARKER}
29
+ ## Safe storage limits
30
+
31
+ A new storage protection mode is available behind the safe-storage-limits
32
+ rollout flag. When enabled, the assistant watches workspace disk usage and
33
+ enters cleanup mode if the volume reaches the critical 95% threshold.
34
+
35
+ In cleanup mode, background processes pause and remote messages, including
36
+ trusted-contact messages, are blocked until the guardian frees enough space or
37
+ explicitly overrides the lock. The macOS app now shows a storage cleanup banner
38
+ that must be acknowledged before cleanup chat continues, then keeps a status
39
+ banner visible while cleanup mode is active.
40
+ `;
41
+
42
+ let testRoot: string;
43
+ let workspaceDir: string;
44
+
45
+ beforeAll(() => {
46
+ testRoot = mkdtempSync(join(tmpdir(), "migration-071-remove-safe-storage-"));
47
+ });
48
+
49
+ afterAll(() => {
50
+ rmSync(testRoot, { recursive: true, force: true });
51
+ });
52
+
53
+ beforeEach(() => {
54
+ workspaceDir = mkdtempSync(join(testRoot, "ws-"));
55
+ });
56
+
57
+ afterEach(() => {
58
+ rmSync(workspaceDir, { recursive: true, force: true });
59
+ });
60
+
61
+ function updatesPath(): string {
62
+ return join(workspaceDir, "UPDATES.md");
63
+ }
64
+
65
+ describe("workspace migration 071-remove-safe-storage-release-note", () => {
66
+ test("has the correct id and description", () => {
67
+ expect(removeSafeStorageReleaseNoteMigration.id).toBe(MIGRATION_ID);
68
+ expect(removeSafeStorageReleaseNoteMigration.description).toContain(
69
+ "safe storage release note",
70
+ );
71
+ });
72
+
73
+ test("missing UPDATES.md is a no-op", () => {
74
+ expect(existsSync(updatesPath())).toBe(false);
75
+
76
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
77
+
78
+ expect(existsSync(updatesPath())).toBe(false);
79
+ });
80
+
81
+ test("removes UPDATES.md when it only contains the safe-storage bulletin", () => {
82
+ writeFileSync(updatesPath(), SAFE_STORAGE_RELEASE_NOTE, "utf-8");
83
+
84
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
85
+
86
+ expect(existsSync(updatesPath())).toBe(false);
87
+ });
88
+
89
+ test("preserves prior unrelated release notes when removing the safe-storage block", () => {
90
+ const prior = `<!-- release-note-id:066-earlier-note -->
91
+ ## Earlier note
92
+
93
+ This note should stay.
94
+ `;
95
+ writeFileSync(
96
+ updatesPath(),
97
+ `${prior}\n${SAFE_STORAGE_RELEASE_NOTE}`,
98
+ "utf-8",
99
+ );
100
+
101
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
102
+
103
+ const content = readFileSync(updatesPath(), "utf-8");
104
+ expect(content).toContain("## Earlier note");
105
+ expect(content).toContain("This note should stay.");
106
+ expect(content).not.toContain(SAFE_STORAGE_MARKER);
107
+ expect(content).not.toContain("Safe storage limits");
108
+ });
109
+
110
+ test("preserves a later release-note block after safe storage", () => {
111
+ const later = `${LATER_MARKER}
112
+ ## Local timezone grounding
113
+
114
+ This later note should stay.
115
+ `;
116
+ writeFileSync(
117
+ updatesPath(),
118
+ `${SAFE_STORAGE_RELEASE_NOTE}\n${later}`,
119
+ "utf-8",
120
+ );
121
+
122
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
123
+
124
+ const content = readFileSync(updatesPath(), "utf-8");
125
+ expect(content.startsWith(LATER_MARKER)).toBe(true);
126
+ expect(content).toContain("## Local timezone grounding");
127
+ expect(content).toContain("This later note should stay.");
128
+ expect(content).not.toContain(SAFE_STORAGE_MARKER);
129
+ expect(content).not.toContain("Safe storage limits");
130
+ });
131
+
132
+ test("fallback preserves a later release-note block after a partial safe-storage block", () => {
133
+ const partialSafeStorage = `${SAFE_STORAGE_MARKER}
134
+ ## Safe storage limits
135
+
136
+ Partially written note.
137
+ `;
138
+ const later = `${LATER_MARKER}
139
+ ## Local timezone grounding
140
+
141
+ This later note should stay.
142
+ `;
143
+ writeFileSync(updatesPath(), `${partialSafeStorage}\n${later}`, "utf-8");
144
+
145
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
146
+
147
+ const content = readFileSync(updatesPath(), "utf-8");
148
+ expect(content.startsWith(LATER_MARKER)).toBe(true);
149
+ expect(content).toContain("## Local timezone grounding");
150
+ expect(content).not.toContain(SAFE_STORAGE_MARKER);
151
+ expect(content).not.toContain("Partially written note.");
152
+ });
153
+
154
+ test("content without the safe-storage marker is byte-identical", () => {
155
+ const original =
156
+ "## Existing note\r\n\r\nNo safe storage marker appears here.\r\n";
157
+ writeFileSync(updatesPath(), original, "utf-8");
158
+
159
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
160
+
161
+ expect(readFileSync(updatesPath(), "utf-8")).toBe(original);
162
+ });
163
+
164
+ test("preserves CRLF in unrelated content when removing the safe-storage block", () => {
165
+ const prior =
166
+ "<!-- release-note-id:066-earlier-note -->\r\n## Earlier note\r\n\r\nThis note should keep CRLF.\r\n";
167
+ writeFileSync(
168
+ updatesPath(),
169
+ `${prior}\r\n${SAFE_STORAGE_RELEASE_NOTE}`,
170
+ "utf-8",
171
+ );
172
+
173
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
174
+
175
+ expect(readFileSync(updatesPath(), "utf-8")).toBe(prior);
176
+ });
177
+
178
+ test("running twice is idempotent", () => {
179
+ const prior = `<!-- release-note-id:066-earlier-note -->
180
+ ## Earlier note
181
+
182
+ This note should stay.
183
+ `;
184
+ const later = `${LATER_MARKER}
185
+ ## Local timezone grounding
186
+
187
+ This later note should stay.
188
+ `;
189
+ writeFileSync(
190
+ updatesPath(),
191
+ `${prior}\n${SAFE_STORAGE_RELEASE_NOTE}\n${later}`,
192
+ "utf-8",
193
+ );
194
+
195
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
196
+ const afterFirst = readFileSync(updatesPath(), "utf-8");
197
+
198
+ removeSafeStorageReleaseNoteMigration.run(workspaceDir);
199
+ const afterSecond = readFileSync(updatesPath(), "utf-8");
200
+
201
+ expect(afterSecond).toBe(afterFirst);
202
+ expect(afterSecond).toContain("## Earlier note");
203
+ expect(afterSecond).toContain("## Local timezone grounding");
204
+ expect(afterSecond).not.toContain(SAFE_STORAGE_MARKER);
205
+ });
206
+ });
@@ -0,0 +1,78 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+
12
+ import { releaseNotesSafeStorageLimitsMigration } from "../workspace/migrations/067-release-notes-safe-storage-limits.js";
13
+
14
+ const MIGRATION_ID = "067-release-notes-safe-storage-limits";
15
+
16
+ let workspaceDir: string;
17
+
18
+ function freshWorkspace(): void {
19
+ workspaceDir = join(
20
+ tmpdir(),
21
+ `vellum-migration-067-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
22
+ );
23
+ mkdirSync(workspaceDir, { recursive: true });
24
+ }
25
+
26
+ function updatesPath(): string {
27
+ return join(workspaceDir, "UPDATES.md");
28
+ }
29
+
30
+ beforeEach(() => {
31
+ freshWorkspace();
32
+ });
33
+
34
+ afterEach(() => {
35
+ if (existsSync(workspaceDir)) {
36
+ rmSync(workspaceDir, { recursive: true, force: true });
37
+ }
38
+ });
39
+
40
+ describe("workspace migration 067-release-notes-safe-storage-limits", () => {
41
+ test("has the correct id", () => {
42
+ expect(releaseNotesSafeStorageLimitsMigration.id).toBe(MIGRATION_ID);
43
+ });
44
+
45
+ test("does not create UPDATES.md when file is absent", () => {
46
+ expect(existsSync(updatesPath())).toBe(false);
47
+
48
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
49
+
50
+ expect(existsSync(updatesPath())).toBe(false);
51
+ });
52
+
53
+ test("leaves existing UPDATES.md byte-identical", () => {
54
+ const existing = "## Prior\n\nExisting release note.\n";
55
+ writeFileSync(updatesPath(), existing, "utf-8");
56
+
57
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
58
+
59
+ expect(readFileSync(updatesPath(), "utf-8")).toBe(existing);
60
+ });
61
+
62
+ test("is idempotent when run twice in an empty workspace", () => {
63
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
64
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
65
+
66
+ expect(existsSync(updatesPath())).toBe(false);
67
+ });
68
+
69
+ test("is idempotent when run twice with existing UPDATES.md", () => {
70
+ const existing = "## Prior\n\nExisting release note.\n";
71
+ writeFileSync(updatesPath(), existing, "utf-8");
72
+
73
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
74
+ releaseNotesSafeStorageLimitsMigration.run(workspaceDir);
75
+
76
+ expect(readFileSync(updatesPath(), "utf-8")).toBe(existing);
77
+ });
78
+ });
package/src/agent/loop.ts CHANGED
@@ -96,6 +96,11 @@ export type AgentEvent =
96
96
  matchedTrustRuleId?: string;
97
97
  isContainerized?: boolean;
98
98
  riskScopeOptions?: Array<{ pattern: string; label: string }>;
99
+ riskAllowlistOptions?: Array<{
100
+ label: string;
101
+ description: string;
102
+ pattern: string;
103
+ }>;
99
104
  riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
100
105
  approvalMode?: string;
101
106
  approvalReason?: string;
@@ -282,6 +287,11 @@ export type LoopToolExecutor = (
282
287
  matchedTrustRuleId?: string;
283
288
  isContainerized?: boolean;
284
289
  riskScopeOptions?: Array<{ pattern: string; label: string }>;
290
+ riskAllowlistOptions?: Array<{
291
+ label: string;
292
+ description: string;
293
+ pattern: string;
294
+ }>;
285
295
  riskDirectoryScopeOptions?: Array<{ scope: string; label: string }>;
286
296
  approvalMode?: string;
287
297
  approvalReason?: string;
@@ -1001,6 +1011,7 @@ export class AgentLoop {
1001
1011
  matchedTrustRuleId: result.matchedTrustRuleId,
1002
1012
  isContainerized: result.isContainerized,
1003
1013
  riskScopeOptions: result.riskScopeOptions,
1014
+ riskAllowlistOptions: result.riskAllowlistOptions,
1004
1015
  riskDirectoryScopeOptions: result.riskDirectoryScopeOptions,
1005
1016
  approvalMode: result.approvalMode,
1006
1017
  approvalReason: result.approvalReason,
@@ -13,7 +13,6 @@
13
13
 
14
14
  import { answerCall } from "../calls/call-domain.js";
15
15
  import { findContactChannel } from "../contacts/contact-store.js";
16
- import { upsertContactChannel } from "../contacts/contacts-write.js";
17
16
  import { findConversation } from "../daemon/conversation-store.js";
18
17
  import { emitFeedEvent } from "../home/emit-feed-event.js";
19
18
  import {
@@ -187,28 +186,15 @@ const pendingInteractionResolver: GuardianRequestResolver = {
187
186
  return { ok: false, reason: "pending_interaction_not_found" };
188
187
  }
189
188
 
190
- // Resolve the interaction: remove from tracker and get the session.
191
- const resolved = pendingInteractions.resolve(request.id);
192
- if (!resolved) {
193
- // Race condition: interaction was consumed between get() and resolve().
194
- log.warn(
195
- {
196
- event: "resolver_tool_approval_resolve_race",
197
- requestId: request.id,
198
- },
199
- "Tool approval resolver: pending interaction consumed between lookup and resolve",
200
- );
201
- return { ok: false, reason: "pending_interaction_race" };
202
- }
203
-
204
189
  // Map action to the permission system's UserDecision type and notify session.
190
+ // resolveConfirmation() owns pendingInteractions deregistration.
205
191
  const userDecision: UserDecision =
206
192
  decision.action === "reject" ? "deny" : "allow";
207
- const conversation = findConversation(resolved.conversationId);
193
+ const conversation = findConversation(interaction.conversationId);
208
194
  if (!conversation) {
209
195
  return {
210
196
  ok: false,
211
- reason: `conversation_not_found: ${resolved.conversationId}`,
197
+ reason: `conversation_not_found: ${interaction.conversationId}`,
212
198
  };
213
199
  }
214
200
  conversation.handleConfirmationResponse(
@@ -510,21 +496,6 @@ const accessRequestResolver: GuardianRequestResolver = {
510
496
  // a verification session. The caller is already on the line and the
511
497
  // relay server's in-call wait loop will detect the approved status.
512
498
  if (channel === "phone") {
513
- try {
514
- upsertContactChannel({
515
- sourceChannel: "phone",
516
- externalUserId: requesterExternalUserId,
517
- externalChatId: requesterChatId,
518
- status: "active",
519
- policy: "allow",
520
- });
521
- } catch (err) {
522
- log.error(
523
- { err, requesterExternalUserId },
524
- "Access request resolver: failed to activate voice caller as trusted contact",
525
- );
526
- }
527
-
528
499
  log.info(
529
500
  {
530
501
  event: "resolver_access_request_voice_approved",
@@ -32,10 +32,10 @@ import {
32
32
  writeSync,
33
33
  } from "node:fs";
34
34
  import { dirname, join } from "node:path";
35
- import { kill } from "node:process";
36
35
  import { setTimeout as sleep } from "node:timers/promises";
37
36
 
38
37
  import { getLogger } from "../util/logger.js";
38
+ import { isProcessAlive } from "../util/process-liveness.js";
39
39
  import { getLocalBackupsDir } from "./paths.js";
40
40
 
41
41
  const log = getLogger("snapshot-lock");
@@ -88,29 +88,6 @@ export function getSnapshotLockPath(): string {
88
88
  return join(dirname(getLocalBackupsDir()), ".snapshot.lock");
89
89
  }
90
90
 
91
- /**
92
- * Check whether a PID refers to a live process. Uses `kill(pid, 0)`, which
93
- * does not send any signal — it just probes for existence and permission.
94
- *
95
- * Returns `false` for obviously invalid PIDs (<= 0) and for any error that
96
- * indicates the process is gone. Returns `true` for ESRCH-negative results
97
- * (meaning a process exists) and for EPERM (process exists but is owned by
98
- * another user — still a live process, still should not be taken over).
99
- */
100
- function isProcessAlive(pid: number): boolean {
101
- if (!Number.isInteger(pid) || pid <= 0) return false;
102
- try {
103
- kill(pid, 0);
104
- return true;
105
- } catch (err) {
106
- const code = (err as NodeJS.ErrnoException).code;
107
- // EPERM means the PID exists but we cannot signal it — treat as alive so
108
- // we don't accidentally take over another user's lock.
109
- if (code === "EPERM") return true;
110
- return false;
111
- }
112
- }
113
-
114
91
  /**
115
92
  * Try to atomically create the lock file with mode `0o600` and the current
116
93
  * PID as its contents. Returns `true` on success, `false` if the file
@@ -348,9 +325,7 @@ export async function acquireSnapshotLock(
348
325
  }
349
326
 
350
327
  if (isProcessAlive(holder.pid)) {
351
- throw new Error(
352
- `snapshot in progress (locked by pid ${holder.pid})`,
353
- );
328
+ throw new Error(`snapshot in progress (locked by pid ${holder.pid})`);
354
329
  }
355
330
 
356
331
  // --- Step 3: stale takeover via rename-aside ---
@@ -15,10 +15,11 @@ import {
15
15
  rmSync,
16
16
  writeFileSync,
17
17
  } from "node:fs";
18
- import { arch, homedir, platform } from "node:os";
18
+ import { arch, platform } from "node:os";
19
19
  import { join } from "node:path";
20
20
 
21
21
  import { getLogger } from "../util/logger.js";
22
+ import { getWorkspaceDir } from "../util/platform.js";
22
23
  import { PromiseGuard } from "../util/promise-guard.js";
23
24
 
24
25
  const log = getLogger("compiler-tools");
@@ -44,7 +45,7 @@ interface VersionManifest {
44
45
  }
45
46
 
46
47
  function getToolsDir(): string {
47
- return join(homedir(), ".vellum", "workspace", "compiler-tools");
48
+ return join(getWorkspaceDir(), "compiler-tools");
48
49
  }
49
50
 
50
51
  const installGuard = new PromiseGuard<void>();
@@ -1,14 +1,7 @@
1
1
  import { getConfig } from "../config/loader.js";
2
2
 
3
3
  // Emergency/high-risk numbers that should never be called
4
- const DENIED_NUMBERS = new Set([
5
- "911",
6
- "112",
7
- "999",
8
- "000",
9
- "110",
10
- "119",
11
- ]);
4
+ const DENIED_NUMBERS = new Set(["911", "112", "999", "000", "110", "119"]);
12
5
 
13
6
  /**
14
7
  * Check whether a phone number is a denied emergency number.
@@ -75,3 +68,7 @@ export function getGuardianWaitUpdateSteadyMaxIntervalMs(): number {
75
68
  export function getSilenceTimeoutMs(): number {
76
69
  return 30 * 1000; // 30 seconds
77
70
  }
71
+
72
+ export function getEndCallListenWindowMs(): number {
73
+ return 15 * 1000;
74
+ }