@vellumai/assistant 0.11.2 → 0.11.3-staging.2

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 (720) hide show
  1. package/ARCHITECTURE.md +58 -3
  2. package/docs/trusted-contact-access.md +9 -5
  3. package/docs/vellum-doctor.md +195 -0
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  7. package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
  8. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
  9. package/node_modules/@vellumai/environments/package.json +2 -1
  10. package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
  11. package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
  12. package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
  13. package/node_modules/@vellumai/environments/src/index.ts +17 -6
  14. package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
  15. package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
  16. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  17. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  18. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  19. package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
  20. package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
  21. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
  22. package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
  23. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
  24. package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
  25. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
  26. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
  27. package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
  28. package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
  29. package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
  30. package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
  31. package/openapi.yaml +589 -30
  32. package/package.json +1 -1
  33. package/src/__tests__/agent-image-optimize.test.ts +4 -4
  34. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
  35. package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
  36. package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
  37. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
  38. package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
  39. package/src/__tests__/answered-question-persistence.test.ts +240 -0
  40. package/src/__tests__/anthropic-provider.test.ts +165 -30
  41. package/src/__tests__/app-control-flow.test.ts +9 -8
  42. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  43. package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
  44. package/src/__tests__/attachments-store.test.ts +130 -68
  45. package/src/__tests__/attachments.test.ts +36 -36
  46. package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
  47. package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
  48. package/src/__tests__/canned-reply-release.test.ts +86 -0
  49. package/src/__tests__/channel-guardian.test.ts +59 -29
  50. package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
  51. package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
  52. package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
  53. package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
  54. package/src/__tests__/consult-deadline.test.ts +65 -0
  55. package/src/__tests__/conversation-agent-loop.test.ts +438 -2
  56. package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
  57. package/src/__tests__/conversation-disk-view.test.ts +4 -4
  58. package/src/__tests__/conversation-error.test.ts +22 -3
  59. package/src/__tests__/conversation-fork-crud.test.ts +5 -1
  60. package/src/__tests__/conversation-fork-referential.test.ts +352 -0
  61. package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
  62. package/src/__tests__/conversation-group-tools.test.ts +32 -2
  63. package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
  64. package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
  65. package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
  66. package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
  67. package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
  68. package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
  69. package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
  70. package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
  71. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
  72. package/src/__tests__/conversation-queue.test.ts +433 -1
  73. package/src/__tests__/conversation-retry-route.test.ts +3 -1
  74. package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
  75. package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
  76. package/src/__tests__/conversation-store.test.ts +26 -10
  77. package/src/__tests__/conversation-summarize-route.test.ts +1 -1
  78. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
  79. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
  81. package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
  82. package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
  83. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
  84. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  85. package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
  86. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
  87. package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
  88. package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
  89. package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
  90. package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
  91. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
  92. package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
  93. package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
  94. package/src/__tests__/credential-prompt-route.test.ts +57 -7
  95. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  96. package/src/__tests__/cu-unified-flow.test.ts +89 -28
  97. package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
  98. package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
  99. package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
  100. package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
  101. package/src/__tests__/disk-pressure-guard.test.ts +55 -55
  102. package/src/__tests__/disk-pressure-routes.test.ts +10 -10
  103. package/src/__tests__/disk-pressure-tools.test.ts +2 -2
  104. package/src/__tests__/disk-usage.test.ts +35 -20
  105. package/src/__tests__/document-sync-tags.test.ts +379 -0
  106. package/src/__tests__/document-update-default-surface.test.ts +28 -0
  107. package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
  108. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
  109. package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
  110. package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
  111. package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
  112. package/src/__tests__/file-list-tool.test.ts +12 -10
  113. package/src/__tests__/file-ops-service.test.ts +151 -44
  114. package/src/__tests__/file-read-container-boundary.test.ts +137 -0
  115. package/src/__tests__/file-read-tool.test.ts +21 -9
  116. package/src/__tests__/file-url-path-guard.test.ts +83 -0
  117. package/src/__tests__/filesystem-tools.test.ts +82 -66
  118. package/src/__tests__/guardian-outbound-http.test.ts +8 -8
  119. package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
  120. package/src/__tests__/helpers/hub-clients.ts +42 -0
  121. package/src/__tests__/helpers/mock-conversation.ts +46 -0
  122. package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
  123. package/src/__tests__/history-repair.test.ts +112 -12
  124. package/src/__tests__/host-bash-proxy.test.ts +10 -5
  125. package/src/__tests__/host-bash-routes.test.ts +67 -0
  126. package/src/__tests__/host-browser-proxy.test.ts +2 -2
  127. package/src/__tests__/host-cu-proxy.test.ts +3 -7
  128. package/src/__tests__/host-file-proxy.test.ts +3 -7
  129. package/src/__tests__/host-file-read-tool.test.ts +5 -1
  130. package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
  131. package/src/__tests__/http-conversation-lineage.test.ts +2 -5
  132. package/src/__tests__/http-user-message-parity.test.ts +44 -0
  133. package/src/__tests__/identity-routes.test.ts +13 -13
  134. package/src/__tests__/image-conversion.test.ts +29 -26
  135. package/src/__tests__/image-source-path-reinject.test.ts +2 -2
  136. package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
  137. package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
  138. package/src/__tests__/introduction-card-resolver.test.ts +6 -1
  139. package/src/__tests__/list-messages-attachments.test.ts +56 -32
  140. package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
  141. package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
  142. package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
  143. package/src/__tests__/list-messages-page-latest.test.ts +61 -61
  144. package/src/__tests__/list-messages-provider-error.test.ts +6 -6
  145. package/src/__tests__/list-messages-queued.test.ts +49 -6
  146. package/src/__tests__/list-messages-system-card.test.ts +4 -4
  147. package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
  148. package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
  149. package/src/__tests__/llm-usage-store.test.ts +55 -0
  150. package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
  151. package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
  152. package/src/__tests__/media-stream-server-integration.test.ts +36 -0
  153. package/src/__tests__/migration-export-http.test.ts +1 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +1 -1
  155. package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
  156. package/src/__tests__/migration-validate-http.test.ts +1 -1
  157. package/src/__tests__/mtime-cache.test.ts +65 -3
  158. package/src/__tests__/notification-platform-adapter.test.ts +104 -0
  159. package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
  160. package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
  161. package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
  162. package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
  163. package/src/__tests__/oauth-providers-routes.test.ts +1 -0
  164. package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
  165. package/src/__tests__/path-policy.test.ts +164 -1
  166. package/src/__tests__/persist-media-references.test.ts +2 -2
  167. package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
  168. package/src/__tests__/persist-unsendable-image.test.ts +23 -23
  169. package/src/__tests__/persona-resolver.test.ts +154 -0
  170. package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
  171. package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
  172. package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
  173. package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
  174. package/src/__tests__/profiler-routes.test.ts +13 -13
  175. package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
  176. package/src/__tests__/proxy-approval-callback.test.ts +3 -3
  177. package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
  178. package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
  179. package/src/__tests__/resolve-trust-class.test.ts +20 -0
  180. package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
  181. package/src/__tests__/run-due-schedules.test.ts +174 -0
  182. package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
  183. package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
  184. package/src/__tests__/schedule-routes.test.ts +730 -8
  185. package/src/__tests__/schedule-store.test.ts +540 -0
  186. package/src/__tests__/schedule-tools.test.ts +103 -0
  187. package/src/__tests__/scheduler-wake.test.ts +5 -0
  188. package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
  189. package/src/__tests__/secure-keys.test.ts +91 -0
  190. package/src/__tests__/server-history-render.test.ts +97 -7
  191. package/src/__tests__/size-guard.test.ts +8 -8
  192. package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
  193. package/src/__tests__/skill-tool-factory.test.ts +247 -0
  194. package/src/__tests__/skills-install-staging.test.ts +15 -6
  195. package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
  196. package/src/__tests__/slack-inbound-verification.test.ts +4 -1
  197. package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
  198. package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
  199. package/src/__tests__/starter-task-flow.test.ts +5 -4
  200. package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
  201. package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
  202. package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
  203. package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
  204. package/src/__tests__/subagent-disposal.test.ts +10 -0
  205. package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
  206. package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
  207. package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
  208. package/src/__tests__/subagent-manager-notify.test.ts +148 -0
  209. package/src/__tests__/subagent-notify-parent.test.ts +1 -1
  210. package/src/__tests__/subagent-persistence.test.ts +141 -0
  211. package/src/__tests__/subagent-role-registry.test.ts +172 -63
  212. package/src/__tests__/subagent-role-resolution.test.ts +88 -0
  213. package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
  214. package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
  215. package/src/__tests__/subagent-terminal-message.test.ts +88 -1
  216. package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
  217. package/src/__tests__/subagent-tools.test.ts +1901 -108
  218. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  219. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  220. package/src/__tests__/system-prompt.test.ts +82 -7
  221. package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
  222. package/src/__tests__/tool-result-spool.test.ts +74 -18
  223. package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
  224. package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
  225. package/src/__tests__/tools-audio-read.test.ts +10 -10
  226. package/src/__tests__/tools-get-route.test.ts +85 -12
  227. package/src/__tests__/tools-list-cli.test.ts +171 -0
  228. package/src/__tests__/top-level-renderer.test.ts +54 -1
  229. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
  230. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
  231. package/src/__tests__/turn-tail-chain.test.ts +135 -0
  232. package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
  233. package/src/__tests__/ui-visual-surface.test.ts +5 -4
  234. package/src/__tests__/ui-work-result-surface.test.ts +5 -4
  235. package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
  236. package/src/__tests__/usage-routes.test.ts +62 -0
  237. package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
  238. package/src/__tests__/visible-app-context.test.ts +20 -4
  239. package/src/__tests__/web-search-history.test.ts +96 -0
  240. package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
  241. package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
  242. package/src/acp/failure-error.ts +3 -5
  243. package/src/agent/attachments.ts +26 -24
  244. package/src/agent/history-repair/history-repair.ts +27 -26
  245. package/src/agent/image-optimize.ts +6 -6
  246. package/src/agent/loop.ts +40 -22
  247. package/src/agent/message-types.ts +3 -3
  248. package/src/api/constants/document-tools.ts +55 -0
  249. package/src/api/events/question-answered.ts +53 -0
  250. package/src/api/events/tool-result.ts +7 -0
  251. package/src/api/index.ts +13 -0
  252. package/src/api/responses/conversation-message.ts +11 -0
  253. package/src/api/surfaces-oauth-connect.test.ts +96 -0
  254. package/src/api/surfaces.ts +36 -8
  255. package/src/approvals/guardian-channel-delivery.ts +83 -0
  256. package/src/approvals/guardian-expiry-notifier.ts +13 -11
  257. package/src/approvals/guardian-request-resolvers.ts +222 -135
  258. package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
  259. package/src/calls/media-stream-server.ts +9 -1
  260. package/src/calls/voice-session-bridge.ts +38 -0
  261. package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
  262. package/src/channels/config.ts +7 -2
  263. package/src/channels/gateway-verification-sessions.ts +7 -2
  264. package/src/channels/types.ts +7 -1
  265. package/src/cli/commands/__tests__/cache.test.ts +7 -4
  266. package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
  267. package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
  268. package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
  269. package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
  270. package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
  271. package/src/cli/commands/__tests__/plugins.test.ts +692 -0
  272. package/src/cli/commands/__tests__/schedules.test.ts +136 -37
  273. package/src/cli/commands/conversations.ts +7 -3
  274. package/src/cli/commands/credentials.help.ts +7 -0
  275. package/src/cli/commands/inference-profiles.ts +9 -3
  276. package/src/cli/commands/inference.help.ts +16 -2
  277. package/src/cli/commands/mcp.help.ts +4 -2
  278. package/src/cli/commands/memory/memory-retrospective.ts +18 -0
  279. package/src/cli/commands/notifications.ts +3 -6
  280. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
  281. package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
  282. package/src/cli/commands/oauth/connect.test.ts +26 -1
  283. package/src/cli/commands/oauth/connect.ts +4 -1
  284. package/src/cli/commands/oauth/index.help.ts +3 -1
  285. package/src/cli/commands/oauth/providers.ts +3 -0
  286. package/src/cli/commands/plugins.help.ts +25 -2
  287. package/src/cli/commands/plugins.ts +289 -10
  288. package/src/cli/commands/schedules.help.ts +14 -12
  289. package/src/cli/commands/schedules.ts +19 -5
  290. package/src/cli/commands/tools.help.ts +4 -2
  291. package/src/cli/commands/tools.ts +38 -0
  292. package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
  293. package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
  294. package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
  295. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
  296. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
  297. package/src/cli/lib/install-from-github.ts +61 -0
  298. package/src/cli/lib/install-from-platform.ts +13 -2
  299. package/src/cli/lib/plugin-surfaces.ts +124 -4
  300. package/src/cli/lib/upgrade-plugin.ts +18 -0
  301. package/src/cli.ts +1 -1
  302. package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
  303. package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
  304. package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
  305. package/src/config/__tests__/profile-tool-support.test.ts +131 -0
  306. package/src/config/bundled-skills/AGENTS.md +1 -1
  307. package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
  308. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
  309. package/src/config/bundled-skills/schedule/SKILL.md +5 -1
  310. package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
  311. package/src/config/bundled-skills/settings/TOOLS.json +2 -2
  312. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
  313. package/src/config/bundled-skills/subagent/SKILL.md +53 -22
  314. package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
  315. package/src/config/bundled-skills/visualize/SKILL.md +1 -1
  316. package/src/config/default-profile-catalog.ts +6 -2
  317. package/src/config/feature-flag-registry.json +25 -17
  318. package/src/config/llm-resolver.ts +45 -15
  319. package/src/config/loader.ts +70 -1
  320. package/src/config/profile-tool-support.ts +110 -0
  321. package/src/config/sanitize-for-transfer.ts +11 -0
  322. package/src/config/schema.ts +4 -0
  323. package/src/config/schemas/__tests__/stt.test.ts +20 -5
  324. package/src/config/schemas/channels.ts +13 -0
  325. package/src/config/schemas/memory-retrospective.ts +25 -0
  326. package/src/config/schemas/plugin-updates.ts +55 -0
  327. package/src/config/schemas/services.ts +8 -4
  328. package/src/config/schemas/stt.ts +17 -5
  329. package/src/config/schemas/timeouts.ts +1 -1
  330. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
  331. package/src/contacts/guardian-delivery-reader.ts +29 -2
  332. package/src/context/compactor.ts +4 -4
  333. package/src/context/post-turn-tool-result-truncation.ts +32 -16
  334. package/src/context/strip-injections.ts +42 -0
  335. package/src/context/tool-result-spool.ts +32 -18
  336. package/src/credential-execution/ces-runtime.ts +3 -0
  337. package/src/credential-execution/client.ts +22 -1
  338. package/src/credential-execution/process-manager.test.ts +99 -0
  339. package/src/credential-execution/process-manager.ts +62 -16
  340. package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
  341. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
  342. package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
  343. package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
  344. package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
  345. package/src/daemon/channel-ui-capability.ts +4 -4
  346. package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
  347. package/src/daemon/conversation-agent-loop.ts +318 -148
  348. package/src/daemon/conversation-attachments.ts +1 -1
  349. package/src/daemon/conversation-error.ts +8 -1
  350. package/src/daemon/conversation-initial-prompt.ts +16 -38
  351. package/src/daemon/conversation-lifecycle.ts +154 -32
  352. package/src/daemon/conversation-messaging.ts +106 -43
  353. package/src/daemon/conversation-process.ts +131 -33
  354. package/src/daemon/conversation-queue-manager.ts +10 -0
  355. package/src/daemon/conversation-runtime-assembly.ts +9 -4
  356. package/src/daemon/conversation-store.ts +52 -3
  357. package/src/daemon/conversation-surface-state.ts +9 -0
  358. package/src/daemon/conversation-surfaces.ts +403 -210
  359. package/src/daemon/conversation-tool-setup.ts +56 -7
  360. package/src/daemon/conversation-turn-finalize.ts +134 -89
  361. package/src/daemon/conversation.ts +111 -27
  362. package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
  363. package/src/daemon/disk-pressure-guard.ts +3 -3
  364. package/src/daemon/doordash-steps.ts +5 -5
  365. package/src/daemon/external-plugins-bootstrap.ts +7 -1
  366. package/src/daemon/handlers/config-channels.ts +48 -5
  367. package/src/daemon/handlers/conversation-history.ts +1 -1
  368. package/src/daemon/handlers/conversations.ts +62 -17
  369. package/src/daemon/handlers/shared.ts +12 -0
  370. package/src/daemon/handlers/skills.ts +11 -1
  371. package/src/daemon/identity-helpers.ts +38 -10
  372. package/src/daemon/install-assistant-command.ts +322 -0
  373. package/src/daemon/lifecycle.ts +14 -3
  374. package/src/daemon/message-types/conversations.ts +6 -7
  375. package/src/daemon/message-types/sync.ts +1 -0
  376. package/src/daemon/persist-media-references.ts +23 -14
  377. package/src/daemon/process-message.ts +6 -6
  378. package/src/daemon/tool-setup-types.ts +19 -122
  379. package/src/daemon/tool-side-effects.ts +17 -94
  380. package/src/daemon/trust-context-types.ts +39 -0
  381. package/src/daemon/trust-context.ts +14 -6
  382. package/src/daemon/turn-tail-chain.ts +73 -0
  383. package/src/daemon/web-search-history.ts +47 -33
  384. package/src/heartbeat/heartbeat-service.ts +6 -6
  385. package/src/ipc/__tests__/socket-path.test.ts +21 -0
  386. package/src/ipc/assistant-server.ts +17 -10
  387. package/src/ipc/cli-client.ts +10 -1
  388. package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
  389. package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
  390. package/src/ipc/socket-cleanup.ts +9 -7
  391. package/src/ipc/socket-path.ts +4 -96
  392. package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
  393. package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
  394. package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
  395. package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
  396. package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
  397. package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
  398. package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
  399. package/src/live-voice/__tests__/protocol.test.ts +52 -0
  400. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
  401. package/src/live-voice/live-voice-archive.ts +13 -13
  402. package/src/live-voice/live-voice-connection.ts +7 -1
  403. package/src/live-voice/live-voice-photo.ts +169 -0
  404. package/src/live-voice/live-voice-session.ts +108 -4
  405. package/src/live-voice/protocol.ts +89 -1
  406. package/src/mcp/client.ts +10 -0
  407. package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
  408. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
  409. package/src/messaging/providers/callback-routing.ts +1 -0
  410. package/src/messaging/providers/discord/api.ts +312 -0
  411. package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
  412. package/src/messaging/providers/discord/render.test.ts +204 -0
  413. package/src/messaging/providers/discord/render.ts +195 -0
  414. package/src/messaging/providers/discord/send.test.ts +179 -0
  415. package/src/messaging/providers/discord/send.ts +212 -0
  416. package/src/messaging/providers/discord/transport.ts +81 -0
  417. package/src/messaging/providers/index.ts +3 -1
  418. package/src/messaging/providers/retry-policy.test.ts +247 -0
  419. package/src/messaging/providers/retry-policy.ts +206 -0
  420. package/src/messaging/providers/slack/mention-source.test.ts +285 -0
  421. package/src/messaging/providers/slack/mention-source.ts +287 -0
  422. package/src/messaging/providers/telegram-bot/api.ts +47 -130
  423. package/src/messaging/providers/whatsapp/api.ts +47 -136
  424. package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
  425. package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
  426. package/src/monitoring/db-integrity-sample.ts +6 -1
  427. package/src/monitoring/plugin-auto-update.ts +359 -0
  428. package/src/monitoring/resource-sampler.ts +21 -5
  429. package/src/monitoring/worker.ts +13 -0
  430. package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
  431. package/src/notifications/__tests__/broadcaster.test.ts +37 -1
  432. package/src/notifications/__tests__/copy-composer.test.ts +165 -0
  433. package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
  434. package/src/notifications/__tests__/notification-utils.test.ts +249 -0
  435. package/src/notifications/adapters/platform.ts +31 -2
  436. package/src/notifications/assistant-reply-producer.ts +79 -32
  437. package/src/notifications/broadcaster.ts +30 -10
  438. package/src/notifications/copy-composer.ts +69 -0
  439. package/src/notifications/emit-signal.ts +82 -15
  440. package/src/notifications/events-store.ts +10 -2
  441. package/src/notifications/home-feed-side-effect.ts +6 -3
  442. package/src/notifications/notification-utils.ts +173 -5
  443. package/src/notifications/signal.ts +12 -0
  444. package/src/oauth/AGENTS.md +4 -2
  445. package/src/oauth/byo-connection.ts +6 -1
  446. package/src/oauth/credential-token-resolver.ts +3 -10
  447. package/src/oauth/manual-token-connection.ts +29 -64
  448. package/src/oauth/manual-token-providers.ts +62 -0
  449. package/src/oauth/provider-serializer.ts +13 -0
  450. package/src/oauth/seed-providers.ts +62 -11
  451. package/src/onboarding/onboarding-events-store.ts +91 -1
  452. package/src/permissions/question-prompter.test.ts +4 -0
  453. package/src/permissions/question-prompter.ts +21 -4
  454. package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
  455. package/src/persistence/attachments-store.ts +15 -15
  456. package/src/persistence/conversation-attention-store.ts +30 -10
  457. package/src/persistence/conversation-bootstrap.ts +17 -0
  458. package/src/persistence/conversation-crud.ts +363 -97
  459. package/src/persistence/conversation-group-migration.ts +1 -1
  460. package/src/persistence/conversation-key-store.ts +38 -10
  461. package/src/persistence/conversation-lineage.ts +226 -0
  462. package/src/persistence/conversation-plugin-facade.ts +28 -3
  463. package/src/persistence/conversation-queries.ts +207 -33
  464. package/src/persistence/conversation-types.ts +107 -1
  465. package/src/persistence/jobs-store.ts +32 -8
  466. package/src/persistence/llm-usage-store.ts +22 -0
  467. package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
  468. package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
  469. package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
  470. package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
  471. package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
  472. package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
  473. package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
  474. package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
  475. package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
  476. package/src/persistence/schema/conversations.ts +32 -0
  477. package/src/persistence/schema/infrastructure.ts +3 -0
  478. package/src/persistence/steps.ts +30 -0
  479. package/src/persistence/subagent-store.ts +148 -6
  480. package/src/platform/managed-speech.test.ts +20 -0
  481. package/src/platform/managed-speech.ts +9 -0
  482. package/src/plugin-api/index.ts +8 -0
  483. package/src/plugin-api/webhook-url.ts +151 -0
  484. package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
  485. package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
  486. package/src/plugins/collect-source-versions.ts +4 -27
  487. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
  488. package/src/plugins/defaults/exploration-drift/package.json +1 -1
  489. package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
  490. package/src/plugins/defaults/image-recovery/recover.ts +67 -57
  491. package/src/plugins/defaults/index.ts +1 -1
  492. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
  493. package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
  494. package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
  495. package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
  496. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
  497. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
  498. package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
  499. package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
  500. package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
  501. package/src/plugins/defaults/memory/job-handlers.ts +87 -5
  502. package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
  503. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
  504. package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
  505. package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
  506. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
  507. package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
  508. package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
  509. package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
  510. package/src/plugins/defaults/memory/v2/router.ts +8 -0
  511. package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
  512. package/src/plugins/external-plugin-loader.ts +17 -8
  513. package/src/plugins/installed-plugin-dirs.ts +101 -0
  514. package/src/plugins/mtime-cache.ts +34 -22
  515. package/src/plugins/types.ts +69 -8
  516. package/src/prompts/persona-resolver.ts +6 -2
  517. package/src/prompts/system-prompt.ts +72 -17
  518. package/src/providers/__tests__/inference.test.ts +40 -0
  519. package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
  520. package/src/providers/__tests__/retry-callsite.test.ts +67 -0
  521. package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
  522. package/src/providers/anthropic/client.ts +112 -95
  523. package/src/providers/connection-resolution.ts +35 -1
  524. package/src/providers/gemini/client.ts +5 -5
  525. package/src/providers/inference/adapter-factory.ts +16 -10
  526. package/src/providers/inference/auth.ts +16 -0
  527. package/src/providers/inference/connection-availability.ts +164 -12
  528. package/src/providers/inference/connections.ts +25 -1
  529. package/src/providers/media-resolve.ts +21 -11
  530. package/src/providers/model-catalog.ts +15 -0
  531. package/src/providers/openai/chat-completions-provider.ts +4 -4
  532. package/src/providers/openai/responses-provider.ts +12 -25
  533. package/src/providers/registry.ts +9 -4
  534. package/src/providers/retry.ts +25 -0
  535. package/src/providers/server-tool-pairing.ts +134 -0
  536. package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
  537. package/src/providers/speech-to-text/deepgram.ts +1 -0
  538. package/src/providers/speech-to-text/resolve.ts +80 -10
  539. package/src/providers/speech-to-text/vellum-managed.ts +7 -1
  540. package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
  541. package/src/providers/types.ts +26 -6
  542. package/src/providers/vellum-model-routing.ts +6 -7
  543. package/src/runtime/AGENTS.md +2 -0
  544. package/src/runtime/__tests__/agent-wake.test.ts +16 -16
  545. package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
  546. package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
  547. package/src/runtime/agent-wake.ts +63 -24
  548. package/src/runtime/assistant-event-hub.ts +87 -12
  549. package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
  550. package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
  551. package/src/runtime/auth/same-actor.ts +56 -8
  552. package/src/runtime/auth/scopes.ts +12 -0
  553. package/src/runtime/auth/types.ts +2 -0
  554. package/src/runtime/background-job-runner.ts +5 -27
  555. package/src/runtime/channel-readiness-service.ts +59 -3
  556. package/src/runtime/channel-readiness-types.ts +18 -0
  557. package/src/runtime/desktop-presence.ts +69 -0
  558. package/src/runtime/http-server.ts +12 -0
  559. package/src/runtime/local-actor-identity.ts +11 -9
  560. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  561. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  562. package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
  563. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
  564. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
  565. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
  566. package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
  567. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
  568. package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
  569. package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
  570. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
  571. package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
  572. package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
  573. package/src/runtime/routes/archive-utils.ts +16 -12
  574. package/src/runtime/routes/attachment-routes.ts +13 -6
  575. package/src/runtime/routes/canned-reply-release.ts +54 -0
  576. package/src/runtime/routes/channel-verification-routes.ts +2 -27
  577. package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
  578. package/src/runtime/routes/client-routes.ts +114 -2
  579. package/src/runtime/routes/conversation-cli-routes.ts +10 -12
  580. package/src/runtime/routes/conversation-list-routes.ts +59 -10
  581. package/src/runtime/routes/conversation-management-routes.ts +47 -18
  582. package/src/runtime/routes/conversation-query-routes.ts +32 -53
  583. package/src/runtime/routes/conversation-routes.ts +360 -293
  584. package/src/runtime/routes/credential-prompt-routes.ts +23 -2
  585. package/src/runtime/routes/debug-routes.ts +4 -1
  586. package/src/runtime/routes/default-provider-routes.ts +7 -11
  587. package/src/runtime/routes/documents-routes.ts +44 -1
  588. package/src/runtime/routes/events-routes.ts +28 -1
  589. package/src/runtime/routes/host-app-control-routes.ts +2 -0
  590. package/src/runtime/routes/host-bash-routes.ts +2 -0
  591. package/src/runtime/routes/host-browser-routes.ts +2 -0
  592. package/src/runtime/routes/host-cu-routes.ts +2 -0
  593. package/src/runtime/routes/host-file-routes.ts +2 -0
  594. package/src/runtime/routes/host-transfer-routes.ts +4 -0
  595. package/src/runtime/routes/identity-routes.ts +6 -6
  596. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  597. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
  598. package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
  599. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
  600. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
  601. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
  602. package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
  603. package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
  604. package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
  605. package/src/runtime/routes/inference-profiles-routes.ts +152 -73
  606. package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
  607. package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
  608. package/src/runtime/routes/log-export-routes.ts +1 -1
  609. package/src/runtime/routes/notification-routes.ts +0 -14
  610. package/src/runtime/routes/oauth-providers.ts +1 -0
  611. package/src/runtime/routes/plugins-routes.ts +106 -1
  612. package/src/runtime/routes/profiler-routes.ts +4 -2
  613. package/src/runtime/routes/question-routes.ts +28 -10
  614. package/src/runtime/routes/retrospective-routes.ts +9 -3
  615. package/src/runtime/routes/schedule-routes.ts +210 -12
  616. package/src/runtime/routes/secret-routes.ts +40 -23
  617. package/src/runtime/routes/settings-routes.ts +41 -13
  618. package/src/runtime/routes/skills-routes.ts +79 -0
  619. package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
  620. package/src/runtime/routes/wake-conversation-routes.ts +23 -0
  621. package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
  622. package/src/runtime/services/conversation-serializer.ts +24 -9
  623. package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
  624. package/src/runtime/sync/resource-sync-events.ts +79 -1
  625. package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
  626. package/src/runtime/sync/worker-daemon-notify.ts +44 -6
  627. package/src/runtime/verification-outbound-actions.ts +250 -222
  628. package/src/runtime/verification-templates.ts +41 -30
  629. package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
  630. package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
  631. package/src/schedule/inference-profile.ts +64 -3
  632. package/src/schedule/plugin-schedule-declarations.ts +518 -0
  633. package/src/schedule/plugin-schedule-reconciler.ts +605 -0
  634. package/src/schedule/plugin-schedules-gate.ts +23 -0
  635. package/src/schedule/schedule-store.ts +520 -26
  636. package/src/schedule/scheduler.ts +38 -0
  637. package/src/security/credential-backend.ts +51 -4
  638. package/src/security/encrypted-store.ts +64 -42
  639. package/src/security/secure-keys.ts +55 -7
  640. package/src/skills/catalog-install.ts +20 -7
  641. package/src/skills/inline-command-runner.ts +2 -7
  642. package/src/skills/skill-history.test.ts +269 -0
  643. package/src/skills/skill-history.ts +250 -0
  644. package/src/skills/skillssh-registry.ts +1 -1
  645. package/src/stt/daemon-batch-transcriber.ts +8 -6
  646. package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
  647. package/src/subagent/consult-prompt.ts +3 -1
  648. package/src/subagent/consult-transcript.ts +1 -1
  649. package/src/subagent/manager.ts +304 -44
  650. package/src/subagent/progress-events.ts +35 -0
  651. package/src/subagent/role-resolution.ts +88 -0
  652. package/src/subagent/types.ts +302 -67
  653. package/src/subagent/validate-allowlists.ts +3 -4
  654. package/src/telegram/__tests__/webhook-health.test.ts +73 -1
  655. package/src/telegram/webhook-health.ts +101 -3
  656. package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
  657. package/src/telemetry/activation-funnel.ts +6 -1
  658. package/src/telemetry/live-voice-funnel.ts +75 -0
  659. package/src/telemetry/telemetry-event-sources.ts +6 -0
  660. package/src/telemetry/telemetry-wire-source.json +1 -1
  661. package/src/telemetry/telemetry-wire.generated.ts +2 -0
  662. package/src/telemetry/types.ts +23 -4
  663. package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
  664. package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
  665. package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
  666. package/src/tools/ask-question/ask-question-tool.ts +56 -2
  667. package/src/tools/browser/browser-execution.ts +1 -1
  668. package/src/tools/calls/call-start.ts +8 -5
  669. package/src/tools/conversation-groups/move_to_group.ts +10 -12
  670. package/src/tools/document/document-tool.ts +11 -4
  671. package/src/tools/execution-timeout.ts +9 -2
  672. package/src/tools/executor.ts +7 -6
  673. package/src/tools/filesystem/edit.ts +1 -1
  674. package/src/tools/filesystem/list.ts +1 -1
  675. package/src/tools/filesystem/read.ts +7 -13
  676. package/src/tools/filesystem/search.ts +23 -21
  677. package/src/tools/filesystem/write.ts +4 -1
  678. package/src/tools/host-filesystem/edit.ts +7 -2
  679. package/src/tools/host-filesystem/read.ts +21 -8
  680. package/src/tools/host-filesystem/write.ts +10 -2
  681. package/src/tools/host-terminal/host-shell.ts +2 -2
  682. package/src/tools/mcp/mcp-tool-factory.ts +25 -1
  683. package/src/tools/permission-checker.ts +8 -3
  684. package/src/tools/schedule/delete.ts +13 -1
  685. package/src/tools/schedule/list.ts +14 -3
  686. package/src/tools/schedule/update.ts +56 -33
  687. package/src/tools/shared/filesystem/audio-read.ts +6 -4
  688. package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
  689. package/src/tools/shared/filesystem/image-read.ts +12 -12
  690. package/src/tools/shared/filesystem/path-policy.ts +70 -5
  691. package/src/tools/shared/filesystem/size-guard.ts +6 -6
  692. package/src/tools/shared/input-misuse.ts +72 -0
  693. package/src/tools/skills/scaffold-managed.ts +82 -0
  694. package/src/tools/skills/skill-tool-factory.ts +14 -1
  695. package/src/tools/subagent/consult-deadline.ts +12 -7
  696. package/src/tools/subagent/message.ts +3 -1
  697. package/src/tools/subagent/read.ts +66 -4
  698. package/src/tools/subagent/spawn.ts +500 -78
  699. package/src/tools/tool-approval-handler.ts +45 -4
  700. package/src/tools/types.ts +22 -3
  701. package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
  702. package/src/tools/ui-surface/visual-validation.ts +2 -0
  703. package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
  704. package/src/usage/subagent-attribution.ts +108 -0
  705. package/src/util/__tests__/sqlite-retry.test.ts +112 -0
  706. package/src/util/abort-reasons.ts +16 -0
  707. package/src/util/ansi.ts +44 -0
  708. package/src/util/disk-usage.ts +17 -13
  709. package/src/util/image-conversion.ts +20 -13
  710. package/src/util/schedule-source-key.ts +23 -0
  711. package/src/util/worker-process.ts +7 -1
  712. package/src/workspace/git-service.ts +33 -9
  713. package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
  714. package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
  715. package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
  716. package/src/workspace/migrations/registry.ts +4 -0
  717. package/src/workspace/top-level-renderer.ts +15 -2
  718. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
  719. package/src/daemon/install-symlink.ts +0 -207
  720. package/src/notifications/deferred-emit.ts +0 -147
@@ -7,7 +7,7 @@ let diskSample: DiskUsageInfo | null = null;
7
7
  let diskSampleError: unknown = null;
8
8
 
9
9
  mock.module("../util/disk-usage.js", () => ({
10
- getDiskUsageInfo: () => {
10
+ getDiskUsageInfo: async () => {
11
11
  if (diskSampleError) {
12
12
  throw diskSampleError;
13
13
  }
@@ -84,10 +84,10 @@ afterEach(() => {
84
84
  });
85
85
 
86
86
  describe("disk pressure guard", () => {
87
- test("locks when sampled usage reaches the threshold", () => {
87
+ test("locks when sampled usage reaches the threshold", async () => {
88
88
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT);
89
89
 
90
- const status = evaluateDiskPressureNow();
90
+ const status = await evaluateDiskPressureNow();
91
91
 
92
92
  expect(status.enabled).toBe(true);
93
93
  expect(status.state).toBe("critical");
@@ -103,9 +103,9 @@ describe("disk pressure guard", () => {
103
103
  expect(status.blockedCapabilities.length).toBeGreaterThan(0);
104
104
  });
105
105
 
106
- test("acknowledges an active lock without overriding it", () => {
106
+ test("acknowledges an active lock without overriding it", async () => {
107
107
  setDiskUsage(99);
108
- evaluateDiskPressureNow();
108
+ await evaluateDiskPressureNow();
109
109
 
110
110
  const result = acknowledgeDiskPressureLock();
111
111
 
@@ -115,14 +115,14 @@ describe("disk pressure guard", () => {
115
115
  expect(result.status.effectivelyLocked).toBe(true);
116
116
  });
117
117
 
118
- test("unlocks and clears acknowledgement and override when usage falls below threshold", () => {
118
+ test("unlocks and clears acknowledgement and override when usage falls below threshold", async () => {
119
119
  setDiskUsage(99);
120
- evaluateDiskPressureNow();
120
+ await evaluateDiskPressureNow();
121
121
  acknowledgeDiskPressureLock();
122
122
  overrideDiskPressureLock(DISK_PRESSURE_OVERRIDE_CONFIRMATION);
123
123
 
124
124
  setDiskUsage(20);
125
- const status = evaluateDiskPressureNow();
125
+ const status = await evaluateDiskPressureNow();
126
126
 
127
127
  expect(status.state).toBe("ok");
128
128
  expect(status.locked).toBe(false);
@@ -133,25 +133,25 @@ describe("disk pressure guard", () => {
133
133
  expect(status.blockedCapabilities).toEqual([]);
134
134
  });
135
135
 
136
- test("does not lock within the deadband until usage reaches the critical threshold", () => {
136
+ test("does not lock within the deadband until usage reaches the critical threshold", async () => {
137
137
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
138
138
 
139
- const status = evaluateDiskPressureNow();
139
+ const status = await evaluateDiskPressureNow();
140
140
 
141
141
  expect(status.state).toBe("warning");
142
142
  expect(status.locked).toBe(false);
143
143
  expect(status.effectivelyLocked).toBe(false);
144
144
  });
145
145
 
146
- test("stays locked while usage stays within the hysteresis deadband", () => {
146
+ test("stays locked while usage stays within the hysteresis deadband", async () => {
147
147
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
148
- const locked = evaluateDiskPressureNow();
148
+ const locked = await evaluateDiskPressureNow();
149
149
  expect(locked.locked).toBe(true);
150
150
  const { lockId } = locked;
151
151
 
152
152
  // Below critical (95) but above clear (90): must hold, not flap.
153
153
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
154
- const status = evaluateDiskPressureNow();
154
+ const status = await evaluateDiskPressureNow();
155
155
 
156
156
  expect(status.state).toBe("critical");
157
157
  expect(status.locked).toBe(true);
@@ -160,29 +160,29 @@ describe("disk pressure guard", () => {
160
160
  expect(status.lockId).toBe(lockId);
161
161
  });
162
162
 
163
- test("preserves acknowledgement across a dip within the deadband", () => {
163
+ test("preserves acknowledgement across a dip within the deadband", async () => {
164
164
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
165
- evaluateDiskPressureNow();
165
+ await evaluateDiskPressureNow();
166
166
  acknowledgeDiskPressureLock();
167
167
 
168
168
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
169
- const status = evaluateDiskPressureNow();
169
+ const status = await evaluateDiskPressureNow();
170
170
 
171
171
  expect(status.locked).toBe(true);
172
172
  expect(status.acknowledged).toBe(true);
173
173
  });
174
174
 
175
- test("clears the lock only once usage falls below the clear threshold", () => {
175
+ test("clears the lock only once usage falls below the clear threshold", async () => {
176
176
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
177
- evaluateDiskPressureNow();
177
+ await evaluateDiskPressureNow();
178
178
 
179
179
  // Still within the deadband: locked.
180
180
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT + 2);
181
- expect(evaluateDiskPressureNow().locked).toBe(true);
181
+ expect((await evaluateDiskPressureNow()).locked).toBe(true);
182
182
 
183
183
  // Below the clear threshold: released.
184
184
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT - 2);
185
- const status = evaluateDiskPressureNow();
185
+ const status = await evaluateDiskPressureNow();
186
186
 
187
187
  expect(status.locked).toBe(false);
188
188
  expect(status.effectivelyLocked).toBe(false);
@@ -190,9 +190,9 @@ describe("disk pressure guard", () => {
190
190
  expect(status.blockedCapabilities).toEqual([]);
191
191
  });
192
192
 
193
- test("overrides an active lock only with the exact confirmation after trimming whitespace", () => {
193
+ test("overrides an active lock only with the exact confirmation after trimming whitespace", async () => {
194
194
  setDiskUsage(99);
195
- evaluateDiskPressureNow();
195
+ await evaluateDiskPressureNow();
196
196
 
197
197
  const invalid = overrideDiskPressureLock("I accept the risks");
198
198
  expectRejected(invalid, "invalid_confirmation");
@@ -208,9 +208,9 @@ describe("disk pressure guard", () => {
208
208
  expect(valid.status.effectivelyLocked).toBe(false);
209
209
  });
210
210
 
211
- test("rejects acknowledgement when no lock is active", () => {
211
+ test("rejects acknowledgement when no lock is active", async () => {
212
212
  setDiskUsage(10);
213
- evaluateDiskPressureNow();
213
+ await evaluateDiskPressureNow();
214
214
 
215
215
  const result = acknowledgeDiskPressureLock();
216
216
 
@@ -218,9 +218,9 @@ describe("disk pressure guard", () => {
218
218
  expect(result.status.locked).toBe(false);
219
219
  });
220
220
 
221
- test("rejects override when no lock is active", () => {
221
+ test("rejects override when no lock is active", async () => {
222
222
  setDiskUsage(10);
223
- evaluateDiskPressureNow();
223
+ await evaluateDiskPressureNow();
224
224
 
225
225
  const result = overrideDiskPressureLock(
226
226
  DISK_PRESSURE_OVERRIDE_CONFIRMATION,
@@ -230,9 +230,9 @@ describe("disk pressure guard", () => {
230
230
  expect(result.status.locked).toBe(false);
231
231
  });
232
232
 
233
- test("rejects repeated override while preserving the existing override", () => {
233
+ test("rejects repeated override while preserving the existing override", async () => {
234
234
  setDiskUsage(99);
235
- evaluateDiskPressureNow();
235
+ await evaluateDiskPressureNow();
236
236
  const first = overrideDiskPressureLock(DISK_PRESSURE_OVERRIDE_CONFIRMATION);
237
237
  expect(first.ok).toBe(true);
238
238
 
@@ -245,13 +245,13 @@ describe("disk pressure guard", () => {
245
245
  expect(second.status.effectivelyLocked).toBe(false);
246
246
  });
247
247
 
248
- test("sample failures degrade open and do not preserve a prior lock", () => {
248
+ test("sample failures degrade open and do not preserve a prior lock", async () => {
249
249
  setDiskUsage(99);
250
- evaluateDiskPressureNow();
250
+ await evaluateDiskPressureNow();
251
251
  expect(getDiskPressureStatus().locked).toBe(true);
252
252
 
253
253
  diskSampleError = new Error("sample failed");
254
- const status = evaluateDiskPressureNow();
254
+ const status = await evaluateDiskPressureNow();
255
255
 
256
256
  expect(status.enabled).toBe(true);
257
257
  expect(status.state).toBe("unknown");
@@ -278,71 +278,71 @@ describe("disk pressure guard", () => {
278
278
  expect(__getDiskPressureGuardTimerForTests()).toBeNull();
279
279
  });
280
280
 
281
- test("does not enter warning until usage reaches the warning threshold", () => {
281
+ test("does not enter warning until usage reaches the warning threshold", async () => {
282
282
  // Below 80% and never previously in a pressure state.
283
283
  setDiskUsage(DISK_PRESSURE_WARNING_THRESHOLD_PERCENT - 2);
284
284
 
285
- const status = evaluateDiskPressureNow();
285
+ const status = await evaluateDiskPressureNow();
286
286
 
287
287
  expect(status.state).toBe("ok");
288
288
  });
289
289
 
290
- test("holds the warning state across a dip within the warning clear deadband", () => {
290
+ test("holds the warning state across a dip within the warning clear deadband", async () => {
291
291
  setDiskUsage(DISK_PRESSURE_WARNING_THRESHOLD_PERCENT + 2);
292
- expect(evaluateDiskPressureNow().state).toBe("warning");
292
+ expect((await evaluateDiskPressureNow()).state).toBe("warning");
293
293
 
294
294
  // Below the 80% warning threshold but at/above the 77% clear threshold.
295
295
  setDiskUsage(DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT + 1);
296
- expect(evaluateDiskPressureNow().state).toBe("warning");
296
+ expect((await evaluateDiskPressureNow()).state).toBe("warning");
297
297
  });
298
298
 
299
- test("clears the warning state once usage falls below the warning clear threshold", () => {
299
+ test("clears the warning state once usage falls below the warning clear threshold", async () => {
300
300
  setDiskUsage(DISK_PRESSURE_WARNING_THRESHOLD_PERCENT + 2);
301
- expect(evaluateDiskPressureNow().state).toBe("warning");
301
+ expect((await evaluateDiskPressureNow()).state).toBe("warning");
302
302
 
303
303
  setDiskUsage(DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT - 1);
304
- expect(evaluateDiskPressureNow().state).toBe("ok");
304
+ expect((await evaluateDiskPressureNow()).state).toBe("ok");
305
305
  });
306
306
 
307
- test("steps a critical lock down into a held warning state", () => {
307
+ test("steps a critical lock down into a held warning state", async () => {
308
308
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
309
- expect(evaluateDiskPressureNow().state).toBe("critical");
309
+ expect((await evaluateDiskPressureNow()).state).toBe("critical");
310
310
 
311
311
  // Below the 90% critical clear but above the 80% warning threshold.
312
312
  setDiskUsage(DISK_PRESSURE_CLEAR_THRESHOLD_PERCENT - 2);
313
- const stepped = evaluateDiskPressureNow();
313
+ const stepped = await evaluateDiskPressureNow();
314
314
  expect(stepped.state).toBe("warning");
315
315
  expect(stepped.locked).toBe(false);
316
316
 
317
317
  // Now within the warning clear deadband — warning must hold, not flap to ok.
318
318
  setDiskUsage(DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT + 1);
319
- expect(evaluateDiskPressureNow().state).toBe("warning");
319
+ expect((await evaluateDiskPressureNow()).state).toBe("warning");
320
320
  });
321
321
 
322
- test("holds warning when a critical lock drops straight into the warning deadband", () => {
322
+ test("holds warning when a critical lock drops straight into the warning deadband", async () => {
323
323
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
324
- expect(evaluateDiskPressureNow().state).toBe("critical");
324
+ expect((await evaluateDiskPressureNow()).state).toBe("critical");
325
325
 
326
326
  // A single large cleanup drops usage directly from critical to below the
327
327
  // 80% warning threshold but still at/above the 77% clear threshold. The
328
328
  // deadband must apply when stepping down out of critical too, so this holds
329
329
  // as warning rather than flapping to ok (which would reopen the flap window).
330
330
  setDiskUsage(DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT + 1);
331
- const stepped = evaluateDiskPressureNow();
331
+ const stepped = await evaluateDiskPressureNow();
332
332
  expect(stepped.state).toBe("warning");
333
333
  expect(stepped.locked).toBe(false);
334
334
  });
335
335
 
336
- test("clears straight to ok when a critical lock drops below the warning clear threshold", () => {
336
+ test("clears straight to ok when a critical lock drops below the warning clear threshold", async () => {
337
337
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT + 1);
338
- expect(evaluateDiskPressureNow().state).toBe("critical");
338
+ expect((await evaluateDiskPressureNow()).state).toBe("critical");
339
339
 
340
340
  // A drop below even the warning-clear threshold is a genuine recovery.
341
341
  setDiskUsage(DISK_PRESSURE_WARNING_CLEAR_THRESHOLD_PERCENT - 1);
342
- expect(evaluateDiskPressureNow().state).toBe("ok");
342
+ expect((await evaluateDiskPressureNow()).state).toBe("ok");
343
343
  });
344
344
 
345
- test("stays ok at a critical usage percentage while ample free space remains", () => {
345
+ test("stays ok at a critical usage percentage while ample free space remains", async () => {
346
346
  // 99% used of a large volume still leaves gigabytes free — above the floor.
347
347
  const totalMb = 1_000_000;
348
348
  const usedMb = Math.round(totalMb * 0.99); // freeMb ~= 10_000 MiB
@@ -351,31 +351,31 @@ describe("disk pressure guard", () => {
351
351
  DISK_PRESSURE_MIN_FREE_FLOOR_MB,
352
352
  );
353
353
 
354
- const status = evaluateDiskPressureNow();
354
+ const status = await evaluateDiskPressureNow();
355
355
 
356
356
  expect(status.state).toBe("ok");
357
357
  expect(status.locked).toBe(false);
358
358
  expect(status.effectivelyLocked).toBe(false);
359
359
  });
360
360
 
361
- test("stays ok at a warning usage percentage while ample free space remains", () => {
361
+ test("stays ok at a warning usage percentage while ample free space remains", async () => {
362
362
  const totalMb = 1_000_000;
363
363
  const usedMb = Math.round(totalMb * 0.85); // 85% used, freeMb ~= 150_000 MiB
364
364
  setDiskUsage(usedMb, totalMb);
365
365
 
366
- const status = evaluateDiskPressureNow();
366
+ const status = await evaluateDiskPressureNow();
367
367
 
368
368
  expect(status.state).toBe("ok");
369
369
  });
370
370
 
371
- test("locks at a critical usage percentage once free space drops below the floor", () => {
371
+ test("locks at a critical usage percentage once free space drops below the floor", async () => {
372
372
  // High percentage AND little absolute headroom: floor does not apply.
373
373
  const totalMb = 100_000;
374
374
  const freeMb = DISK_PRESSURE_MIN_FREE_FLOOR_MB - 1;
375
375
  setDiskUsage(totalMb - freeMb, totalMb);
376
376
  expect(diskSample!.freeMb).toBeLessThan(DISK_PRESSURE_MIN_FREE_FLOOR_MB);
377
377
 
378
- const status = evaluateDiskPressureNow();
378
+ const status = await evaluateDiskPressureNow();
379
379
 
380
380
  expect(status.state).toBe("critical");
381
381
  expect(status.locked).toBe(true);
@@ -170,7 +170,7 @@ describe("disk pressure routes", () => {
170
170
 
171
171
  test("returns the full status shape for an active lock", async () => {
172
172
  setDiskUsage(99);
173
- evaluateDiskPressureNow();
173
+ await evaluateDiskPressureNow();
174
174
 
175
175
  const result = await callRoute("disk-pressure/status", "GET");
176
176
 
@@ -223,7 +223,7 @@ describe("disk pressure routes", () => {
223
223
 
224
224
  test("acknowledges an active lock without overriding it", async () => {
225
225
  setDiskUsage(99);
226
- evaluateDiskPressureNow();
226
+ await evaluateDiskPressureNow();
227
227
 
228
228
  const result = await callRoute("disk-pressure/acknowledge", "POST");
229
229
 
@@ -234,7 +234,7 @@ describe("disk pressure routes", () => {
234
234
 
235
235
  test("overrides an active lock only after the confirmation phrase", async () => {
236
236
  setDiskUsage(99);
237
- evaluateDiskPressureNow();
237
+ await evaluateDiskPressureNow();
238
238
 
239
239
  const result = await callRoute("disk-pressure/override", "POST", {
240
240
  confirmation: DISK_PRESSURE_OVERRIDE_CONFIRMATION,
@@ -247,7 +247,7 @@ describe("disk pressure routes", () => {
247
247
 
248
248
  test("rejects an invalid override phrase with INVALID_CONFIRMATION", async () => {
249
249
  setDiskUsage(99);
250
- evaluateDiskPressureNow();
250
+ await evaluateDiskPressureNow();
251
251
 
252
252
  await expectRouteRejects(
253
253
  "disk-pressure/override",
@@ -260,7 +260,7 @@ describe("disk pressure routes", () => {
260
260
 
261
261
  test("rejects acknowledgement and override when no lock is active", async () => {
262
262
  setDiskUsage(10);
263
- evaluateDiskPressureNow();
263
+ await evaluateDiskPressureNow();
264
264
 
265
265
  await expectRouteRejects(
266
266
  "disk-pressure/acknowledge",
@@ -280,7 +280,7 @@ describe("disk pressure routes", () => {
280
280
 
281
281
  test("rejects repeated acknowledgement", async () => {
282
282
  setDiskUsage(99);
283
- evaluateDiskPressureNow();
283
+ await evaluateDiskPressureNow();
284
284
  await callRoute("disk-pressure/acknowledge", "POST");
285
285
 
286
286
  await expectRouteRejects(
@@ -294,7 +294,7 @@ describe("disk pressure routes", () => {
294
294
 
295
295
  test("rejects repeated override", async () => {
296
296
  setDiskUsage(99);
297
- evaluateDiskPressureNow();
297
+ await evaluateDiskPressureNow();
298
298
  await callRoute("disk-pressure/override", "POST", {
299
299
  confirmation: DISK_PRESSURE_OVERRIDE_CONFIRMATION,
300
300
  });
@@ -321,15 +321,15 @@ describe("disk pressure routes", () => {
321
321
 
322
322
  try {
323
323
  setDiskUsage(99);
324
- evaluateDiskPressureNow();
324
+ await evaluateDiskPressureNow();
325
325
  await callRoute("disk-pressure/acknowledge", "POST");
326
326
  await callRoute("disk-pressure/override", "POST", {
327
327
  confirmation: DISK_PRESSURE_OVERRIDE_CONFIRMATION,
328
328
  });
329
329
  setDiskUsage(98);
330
- evaluateDiskPressureNow();
330
+ await evaluateDiskPressureNow();
331
331
  setDiskUsage(10);
332
- evaluateDiskPressureNow();
332
+ await evaluateDiskPressureNow();
333
333
  await flushPublishedEvents();
334
334
  } finally {
335
335
  subscription.dispose();
@@ -196,7 +196,7 @@ describe("disk pressure cleanup tool restrictions", () => {
196
196
  expect(result.tool.name).toBe("skill_load");
197
197
  });
198
198
 
199
- test("locking cancels registered terminal background tools with disk pressure reason", () => {
199
+ test("locking cancels registered terminal background tools with disk pressure reason", async () => {
200
200
  const bashCancel = mock((_reason?: string) => undefined);
201
201
  const hostCancel = mock((_reason?: string) => undefined);
202
202
  const otherCancel = mock((_reason?: string) => undefined);
@@ -227,7 +227,7 @@ describe("disk pressure cleanup tool restrictions", () => {
227
227
  });
228
228
 
229
229
  setDiskUsage(DISK_PRESSURE_THRESHOLD_PERCENT);
230
- const status = evaluateDiskPressureNow();
230
+ const status = await evaluateDiskPressureNow();
231
231
 
232
232
  expect(status.locked).toBe(true);
233
233
  expect(bashCancel).toHaveBeenCalledWith("disk_pressure");
@@ -1,3 +1,4 @@
1
+ import { promisify } from "node:util";
1
2
  import { beforeEach, describe, expect, mock, test } from "bun:test";
2
3
 
3
4
  const MIB = 1024 * 1024;
@@ -27,11 +28,25 @@ mock.module("node:fs", () => ({
27
28
  statfsSync: () => statfsResult,
28
29
  }));
29
30
 
30
- mock.module("node:child_process", () => ({
31
- spawnSync: (command: string, args: string[]) => {
32
- spawnCalls.push({ command, args });
33
- return spawnResult;
31
+ // The module under test calls `promisify(execFile)`, so the mock only needs
32
+ // to provide the promisified implementation via the promisify.custom symbol.
33
+ const execFileMock = Object.assign(
34
+ () => {
35
+ throw new Error("callback-style execFile is not used by disk-usage");
36
+ },
37
+ {
38
+ [promisify.custom]: async (command: string, args: string[]) => {
39
+ spawnCalls.push({ command, args });
40
+ if (spawnResult.status !== 0) {
41
+ throw new Error(`Command failed with exit code ${spawnResult.status}`);
42
+ }
43
+ return { stdout: spawnResult.stdout, stderr: "" };
44
+ },
34
45
  },
46
+ );
47
+
48
+ mock.module("node:child_process", () => ({
49
+ execFile: execFileMock,
35
50
  }));
36
51
 
37
52
  mock.module("../config/env-registry.js", () => ({
@@ -67,8 +82,8 @@ describe("disk usage sampler", () => {
67
82
  __resetDiskUsageCacheForTests();
68
83
  });
69
84
 
70
- test("reports regular statfs usage", () => {
71
- const usage = getDiskUsageInfo();
85
+ test("reports regular statfs usage", async () => {
86
+ const usage = await getDiskUsageInfo();
72
87
 
73
88
  expect(usage).toEqual({
74
89
  path: "/workspace",
@@ -79,15 +94,15 @@ describe("disk usage sampler", () => {
79
94
  expect(spawnCalls).toHaveLength(0);
80
95
  });
81
96
 
82
- test("falls back to root when the workspace path does not exist", () => {
97
+ test("falls back to root when the workspace path does not exist", async () => {
83
98
  existingPaths = new Set();
84
99
 
85
- const usage = getDiskUsageInfo();
100
+ const usage = await getDiskUsageInfo();
86
101
 
87
102
  expect(usage?.path).toBe("/");
88
103
  });
89
104
 
90
- test("uses PVC capacity and du usage when host filesystem is larger", () => {
105
+ test("uses PVC capacity and du usage when host filesystem is larger", async () => {
91
106
  minikubeStorageSize = "1Gi";
92
107
  statfsResult = statfsFor(10 * GIB, 8 * GIB);
93
108
  spawnResult = {
@@ -95,7 +110,7 @@ describe("disk usage sampler", () => {
95
110
  stdout: `${100 * MIB}\t/workspace\n`,
96
111
  };
97
112
 
98
- const usage = getDiskUsageInfo();
113
+ const usage = await getDiskUsageInfo();
99
114
 
100
115
  expect(usage).toEqual({
101
116
  path: "/workspace",
@@ -108,7 +123,7 @@ describe("disk usage sampler", () => {
108
123
  ]);
109
124
  });
110
125
 
111
- test("includes /data in PVC du usage when it exists separately", () => {
126
+ test("includes /data in PVC du usage when it exists separately", async () => {
112
127
  existingPaths = new Set([workspaceDir, "/data"]);
113
128
  minikubeStorageSize = "1Gi";
114
129
  statfsResult = statfsFor(10 * GIB, 8 * GIB);
@@ -117,7 +132,7 @@ describe("disk usage sampler", () => {
117
132
  stdout: `${100 * MIB}\t/workspace\n${20 * MIB}\t/data\n`,
118
133
  };
119
134
 
120
- const usage = getDiskUsageInfo();
135
+ const usage = await getDiskUsageInfo();
121
136
 
122
137
  expect(usage?.usedMb).toBe(120);
123
138
  expect(spawnCalls).toEqual([
@@ -125,7 +140,7 @@ describe("disk usage sampler", () => {
125
140
  ]);
126
141
  });
127
142
 
128
- test("measures workspace du usage on a local Docker hatch", () => {
143
+ test("measures workspace du usage on a local Docker hatch", async () => {
129
144
  isContainerized = true;
130
145
  isPlatform = false;
131
146
  statfsResult = statfsFor(100 * GIB, 40 * GIB);
@@ -134,7 +149,7 @@ describe("disk usage sampler", () => {
134
149
  stdout: `${2 * GIB}\t/workspace\n`,
135
150
  };
136
151
 
137
- const usage = getDiskUsageInfo();
152
+ const usage = await getDiskUsageInfo();
138
153
 
139
154
  // Used reflects only the workspace (du), free reflects the host headroom
140
155
  // the volume can grow into, and total is their sum.
@@ -149,12 +164,12 @@ describe("disk usage sampler", () => {
149
164
  ]);
150
165
  });
151
166
 
152
- test("does not use du for platform-managed containerized instances", () => {
167
+ test("does not use du for platform-managed containerized instances", async () => {
153
168
  isContainerized = true;
154
169
  isPlatform = true;
155
170
  statfsResult = statfsFor(10 * GIB, 6 * GIB);
156
171
 
157
- const usage = getDiskUsageInfo();
172
+ const usage = await getDiskUsageInfo();
158
173
 
159
174
  expect(usage).toEqual({
160
175
  path: "/workspace",
@@ -165,13 +180,13 @@ describe("disk usage sampler", () => {
165
180
  expect(spawnCalls).toHaveLength(0);
166
181
  });
167
182
 
168
- test("falls back to statfs when du fails on a local Docker hatch", () => {
183
+ test("falls back to statfs when du fails on a local Docker hatch", async () => {
169
184
  isContainerized = true;
170
185
  isPlatform = false;
171
186
  statfsResult = statfsFor(100 * GIB, 40 * GIB);
172
187
  spawnResult = { status: 1, stdout: "" };
173
188
 
174
- const usage = getDiskUsageInfo();
189
+ const usage = await getDiskUsageInfo();
175
190
 
176
191
  expect(usage).toEqual({
177
192
  path: "/workspace",
@@ -192,7 +207,7 @@ describe("disk usage sampler", () => {
192
207
  expect(parseK8sMemoryBytes("0Gi")).toBeNull();
193
208
  });
194
209
 
195
- test("falls back to statfs when du fails in PVC mode", () => {
210
+ test("falls back to statfs when du fails in PVC mode", async () => {
196
211
  minikubeStorageSize = "1Gi";
197
212
  statfsResult = statfsFor(10 * GIB, 8 * GIB);
198
213
  spawnResult = {
@@ -200,7 +215,7 @@ describe("disk usage sampler", () => {
200
215
  stdout: "",
201
216
  };
202
217
 
203
- const usage = getDiskUsageInfo();
218
+ const usage = await getDiskUsageInfo();
204
219
 
205
220
  expect(usage).toEqual({
206
221
  path: "/workspace",