@vellumai/assistant 0.7.1 → 0.7.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 (535) hide show
  1. package/ARCHITECTURE.md +32 -49
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/security.md +20 -0
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +1 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
  19. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  20. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  21. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  22. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  23. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  24. package/openapi.yaml +565 -12
  25. package/package.json +6 -3
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  27. package/src/__tests__/app-bundler.test.ts +170 -1
  28. package/src/__tests__/app-control-flow.test.ts +374 -0
  29. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  31. package/src/__tests__/app-executors.test.ts +30 -43
  32. package/src/__tests__/approval-routes-http.test.ts +23 -6
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  34. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  35. package/src/__tests__/assistant-event-hub.test.ts +109 -2
  36. package/src/__tests__/assistant-event.test.ts +10 -0
  37. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
  39. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  40. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  41. package/src/__tests__/btw-routes.test.ts +13 -4
  42. package/src/__tests__/call-controller.test.ts +49 -1
  43. package/src/__tests__/call-domain.test.ts +0 -2
  44. package/src/__tests__/call-routes-http.test.ts +0 -2
  45. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  46. package/src/__tests__/checker.test.ts +3 -4
  47. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  48. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  49. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  50. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  51. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  54. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  55. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  56. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  57. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  58. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  59. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  60. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  61. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  62. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  64. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  65. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  66. package/src/__tests__/credentials-cli.test.ts +5 -12
  67. package/src/__tests__/cu-unified-flow.test.ts +185 -23
  68. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  69. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  70. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  71. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  72. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  73. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  74. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  75. package/src/__tests__/heartbeat-service.test.ts +718 -1
  76. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  77. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  78. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  79. package/src/__tests__/host-bash-proxy.test.ts +246 -47
  80. package/src/__tests__/host-bash-routes.test.ts +294 -0
  81. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  82. package/src/__tests__/host-browser-routes.test.ts +39 -13
  83. package/src/__tests__/host-cu-proxy.test.ts +41 -52
  84. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  85. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  86. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  87. package/src/__tests__/host-file-proxy.test.ts +37 -43
  88. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  89. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  90. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  91. package/src/__tests__/host-proxy-base.test.ts +312 -0
  92. package/src/__tests__/host-shell-tool.test.ts +22 -4
  93. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  94. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  95. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  96. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  97. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  98. package/src/__tests__/identity-routes.test.ts +103 -1
  99. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  100. package/src/__tests__/inline-command-runner.test.ts +0 -1
  101. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  102. package/src/__tests__/integration-status.test.ts +85 -5
  103. package/src/__tests__/intent-routing.test.ts +0 -1
  104. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  105. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  106. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  107. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  108. package/src/__tests__/mcp-cli.test.ts +338 -2
  109. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  110. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  111. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  112. package/src/__tests__/oauth-cli.test.ts +0 -2
  113. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  114. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  115. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  116. package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
  117. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  118. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  119. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  120. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  121. package/src/__tests__/retry-backoff.test.ts +87 -0
  122. package/src/__tests__/runtime-events-sse.test.ts +10 -6
  123. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  124. package/src/__tests__/schedule-retry.test.ts +715 -0
  125. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  126. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  127. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  128. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  129. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  130. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  131. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  132. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  133. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  134. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  135. package/src/__tests__/slack-channel-config.test.ts +9 -14
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  137. package/src/__tests__/system-prompt.test.ts +0 -1
  138. package/src/__tests__/telegram-config.test.ts +0 -1
  139. package/src/__tests__/test-preload.ts +8 -0
  140. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  141. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  142. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  143. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  145. package/src/__tests__/tool-executor.test.ts +0 -1
  146. package/src/__tests__/twilio-config.test.ts +3 -16
  147. package/src/__tests__/twilio-routes.test.ts +3 -5
  148. package/src/__tests__/twilio-validation.test.ts +93 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  150. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  151. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  152. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  153. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  154. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  155. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  156. package/src/backup/__tests__/paths.test.ts +0 -22
  157. package/src/backup/__tests__/restore.test.ts +51 -151
  158. package/src/backup/paths.ts +2 -18
  159. package/src/backup/restore.ts +107 -231
  160. package/src/bundler/app-bundler.ts +51 -3
  161. package/src/calls/relay-server.ts +4 -44
  162. package/src/calls/twilio-config.ts +2 -17
  163. package/src/calls/twilio-rest.ts +33 -105
  164. package/src/calls/twilio-routes.ts +11 -12
  165. package/src/channels/types.ts +8 -7
  166. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  167. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  168. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  169. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  170. package/src/cli/commands/backup.ts +6 -331
  171. package/src/cli/commands/clients.ts +36 -37
  172. package/src/cli/commands/contacts.ts +73 -0
  173. package/src/cli/commands/conversations.ts +2 -5
  174. package/src/cli/commands/credentials.ts +15 -7
  175. package/src/cli/commands/domain.ts +66 -15
  176. package/src/cli/commands/gateway.ts +183 -0
  177. package/src/cli/commands/keys.ts +9 -6
  178. package/src/cli/commands/mcp.ts +116 -156
  179. package/src/cli/commands/memory-v2.ts +296 -1
  180. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  181. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  182. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  183. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  184. package/src/cli/commands/platform/disconnect.ts +5 -4
  185. package/src/cli/commands/platform/index.ts +0 -18
  186. package/src/cli/lib/daemon-credential-client.ts +110 -28
  187. package/src/cli/program.ts +2 -0
  188. package/src/config/assistant-feature-flags.ts +67 -10
  189. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  190. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  191. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  192. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  193. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  194. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  195. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  196. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  197. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  198. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  199. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  200. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  201. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  202. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  203. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  204. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  205. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  206. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  207. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  208. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  209. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  210. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  211. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  212. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  213. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  214. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  215. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  216. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  217. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  218. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  219. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  220. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  221. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  222. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  223. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  224. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  225. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  226. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  227. package/src/config/bundled-tool-registry.ts +21 -0
  228. package/src/config/env-registry.ts +0 -2
  229. package/src/config/env.ts +19 -12
  230. package/src/config/feature-flag-registry.json +21 -133
  231. package/src/config/loader.ts +73 -99
  232. package/src/config/sanitize-for-transfer.ts +2 -0
  233. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  234. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
  235. package/src/config/schemas/calls.ts +0 -9
  236. package/src/config/schemas/heartbeat.ts +63 -0
  237. package/src/config/schemas/ingress.ts +10 -6
  238. package/src/config/schemas/llm.ts +5 -10
  239. package/src/config/schemas/memory-lifecycle.ts +77 -24
  240. package/src/config/schemas/memory-v2.ts +48 -4
  241. package/src/config/schemas/platform.ts +6 -0
  242. package/src/config/schemas/services.ts +1 -15
  243. package/src/config/schemas/skills.ts +0 -6
  244. package/src/config/seed-inference-profiles.ts +1 -1
  245. package/src/contacts/contact-store.ts +0 -30
  246. package/src/contacts/contacts-write.ts +0 -27
  247. package/src/context/window-manager.ts +1 -2
  248. package/src/credential-execution/feature-gates.ts +10 -10
  249. package/src/credential-execution/process-manager.ts +12 -41
  250. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  251. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  252. package/src/daemon/config-watcher.ts +4 -3
  253. package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
  254. package/src/daemon/conversation-agent-loop.ts +32 -28
  255. package/src/daemon/conversation-lifecycle.ts +8 -1
  256. package/src/daemon/conversation-process.ts +16 -11
  257. package/src/daemon/conversation-runtime-assembly.ts +2 -2
  258. package/src/daemon/conversation-surfaces.ts +125 -4
  259. package/src/daemon/conversation-tool-setup.ts +16 -55
  260. package/src/daemon/conversation.ts +21 -2
  261. package/src/daemon/doordash-steps.ts +1 -1
  262. package/src/daemon/handlers/shared.ts +4 -1
  263. package/src/daemon/host-app-control-proxy.ts +293 -0
  264. package/src/daemon/host-bash-proxy.ts +84 -74
  265. package/src/daemon/host-browser-proxy.ts +67 -82
  266. package/src/daemon/host-cu-proxy.ts +81 -86
  267. package/src/daemon/host-file-proxy.ts +93 -69
  268. package/src/daemon/host-proxy-base.ts +294 -0
  269. package/src/daemon/host-proxy-preactivation.ts +82 -0
  270. package/src/daemon/host-transfer-proxy.ts +247 -129
  271. package/src/daemon/lifecycle.ts +115 -117
  272. package/src/daemon/message-protocol.ts +3 -8
  273. package/src/daemon/message-types/contacts.ts +23 -1
  274. package/src/daemon/message-types/conversations.ts +11 -8
  275. package/src/daemon/message-types/host-app-control.ts +150 -0
  276. package/src/daemon/message-types/host-bash.ts +4 -0
  277. package/src/daemon/message-types/host-cu.ts +2 -0
  278. package/src/daemon/message-types/host-file.ts +4 -0
  279. package/src/daemon/message-types/host-transfer.ts +3 -0
  280. package/src/daemon/message-types/schedules.ts +8 -3
  281. package/src/daemon/message-types/skills.ts +2 -2
  282. package/src/daemon/process-message.ts +18 -1
  283. package/src/daemon/shutdown-handlers.ts +0 -3
  284. package/src/daemon/tool-setup-types.ts +51 -0
  285. package/src/daemon/tool-side-effects.ts +1 -1
  286. package/src/events/tool-audit-listener.ts +2 -1
  287. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
  288. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  289. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  290. package/src/heartbeat/heartbeat-service.ts +280 -49
  291. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  292. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  293. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  294. package/src/home/post-connect-feed.ts +68 -0
  295. package/src/home/relationship-state-writer.ts +17 -92
  296. package/src/home/suggested-prompts.ts +46 -10
  297. package/src/inbound/public-ingress-urls.ts +32 -34
  298. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  299. package/src/ipc/assistant-server.ts +14 -1
  300. package/src/ipc/cli-client.ts +32 -1
  301. package/src/live-voice/live-voice-metrics.ts +10 -10
  302. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  303. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  304. package/src/mcp/mcp-auth-state.ts +133 -0
  305. package/src/mcp/mcp-oauth-provider.ts +19 -0
  306. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  307. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  308. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  309. package/src/memory/anisotropy.test.ts +247 -0
  310. package/src/memory/anisotropy.ts +443 -0
  311. package/src/memory/auto-analysis-constants.ts +17 -0
  312. package/src/memory/auto-analysis-guard.ts +5 -15
  313. package/src/memory/canonical-guardian-store.ts +7 -7
  314. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  315. package/src/memory/context-search/agent-protocol.ts +6 -6
  316. package/src/memory/context-search/agent-runner.ts +32 -7
  317. package/src/memory/context-search/sources/memory-v2.ts +17 -5
  318. package/src/memory/conversation-crud.ts +1 -1
  319. package/src/memory/conversation-key-store.ts +2 -15
  320. package/src/memory/db-init.ts +4 -0
  321. package/src/memory/embedding-backend.ts +9 -21
  322. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
  323. package/src/memory/graph/conversation-graph-memory.ts +1 -24
  324. package/src/memory/graph/graph-search.ts +8 -0
  325. package/src/memory/graph/retriever.ts +28 -0
  326. package/src/memory/graph/tools.ts +1 -1
  327. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  328. package/src/memory/jobs/embed-concept-page.ts +28 -2
  329. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  330. package/src/memory/jobs-store.ts +66 -22
  331. package/src/memory/jobs-worker.ts +112 -63
  332. package/src/memory/memory-v2-activation-log-store.ts +1 -1
  333. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  334. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  335. package/src/memory/migrations/index.ts +5 -0
  336. package/src/memory/migrations/registry.ts +8 -0
  337. package/src/memory/pkb/pkb-search.ts +7 -0
  338. package/src/memory/qdrant-client.ts +50 -20
  339. package/src/memory/schema/infrastructure.ts +15 -0
  340. package/src/memory/search/semantic.ts +7 -0
  341. package/src/memory/sparse-tokenize.ts +49 -0
  342. package/src/memory/v2/__tests__/activation.test.ts +77 -95
  343. package/src/memory/v2/__tests__/injection.test.ts +43 -21
  344. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  345. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  346. package/src/memory/v2/__tests__/static-context.test.ts +0 -1
  347. package/src/memory/v2/activation.ts +69 -88
  348. package/src/memory/v2/consolidation-job.ts +3 -5
  349. package/src/memory/v2/constants.ts +7 -0
  350. package/src/memory/v2/injection.ts +86 -53
  351. package/src/memory/v2/prompts/consolidation.ts +312 -91
  352. package/src/memory/v2/qdrant.ts +99 -1
  353. package/src/memory/v2/sim.ts +126 -16
  354. package/src/memory/v2/skill-qdrant.ts +12 -3
  355. package/src/memory/v2/skill-store.ts +16 -1
  356. package/src/memory/v2/sparse-bm25.ts +245 -0
  357. package/src/memory/v2/static-context.ts +6 -5
  358. package/src/messaging/providers/gmail/types.ts +0 -49
  359. package/src/messaging/providers/slack/adapter.ts +1 -31
  360. package/src/messaging/providers/slack/types.ts +0 -32
  361. package/src/notifications/README.md +10 -10
  362. package/src/notifications/broadcaster.ts +1 -1
  363. package/src/notifications/guardian-question-mode.ts +5 -5
  364. package/src/oauth/connect-orchestrator.ts +4 -0
  365. package/src/oauth/credential-token-resolver.ts +1 -3
  366. package/src/oauth/manual-token-connection.ts +0 -4
  367. package/src/outbound-proxy/index.ts +1 -37
  368. package/src/outbound-proxy/logging.ts +1 -1
  369. package/src/outbound-proxy/policy.ts +6 -5
  370. package/src/outbound-proxy/router.ts +2 -1
  371. package/src/permissions/approval-policy.test.ts +6 -275
  372. package/src/permissions/approval-policy.ts +0 -51
  373. package/src/permissions/checker.test.ts +0 -1
  374. package/src/permissions/checker.ts +3 -17
  375. package/src/permissions/gateway-threshold-reader.ts +2 -0
  376. package/src/permissions/prompter.ts +34 -1
  377. package/src/permissions/secret-prompter.ts +6 -2
  378. package/src/prompts/bootstrap-cleanup.ts +27 -0
  379. package/src/prompts/system-prompt.ts +3 -18
  380. package/src/prompts/templates/SOUL.md +13 -1
  381. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  382. package/src/runtime/assistant-event-hub.ts +118 -96
  383. package/src/runtime/assistant-event.ts +1 -0
  384. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  385. package/src/runtime/auth/middleware.ts +0 -96
  386. package/src/runtime/auth/route-policy.ts +19 -0
  387. package/src/runtime/btw-sidechain.ts +2 -3
  388. package/src/runtime/channel-invite-transport.ts +2 -48
  389. package/src/runtime/channel-invite-transports/email.ts +1 -1
  390. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  391. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  392. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  393. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  394. package/src/runtime/channel-invite-types.ts +54 -0
  395. package/src/runtime/channel-readiness-service.ts +32 -13
  396. package/src/runtime/http-server.ts +3 -329
  397. package/src/runtime/http-types.ts +0 -5
  398. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  399. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  400. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  401. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  402. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  403. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  404. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  405. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  406. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  407. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  408. package/src/runtime/migrations/migration-transport.ts +7 -7
  409. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  410. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  411. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  412. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  413. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  414. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  415. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  416. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  417. package/src/runtime/pending-interactions.ts +35 -9
  418. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  419. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  420. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  421. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  422. package/src/runtime/routes/approval-interception-types.ts +13 -0
  423. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  424. package/src/runtime/routes/backup-routes.ts +15 -38
  425. package/src/runtime/routes/btw-routes.ts +14 -37
  426. package/src/runtime/routes/client-routes.ts +1 -0
  427. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  428. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  429. package/src/runtime/routes/conversation-routes.ts +30 -13
  430. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  431. package/src/runtime/routes/documents-routes.ts +30 -0
  432. package/src/runtime/routes/errors.ts +19 -4
  433. package/src/runtime/routes/events-routes.ts +12 -6
  434. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  435. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  436. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  437. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  438. package/src/runtime/routes/host-bash-routes.ts +36 -6
  439. package/src/runtime/routes/host-browser-routes.ts +108 -13
  440. package/src/runtime/routes/host-cu-routes.ts +44 -14
  441. package/src/runtime/routes/host-file-routes.ts +33 -10
  442. package/src/runtime/routes/host-transfer-routes.ts +64 -24
  443. package/src/runtime/routes/http-adapter.ts +1 -0
  444. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  445. package/src/runtime/routes/identity-routes.ts +15 -43
  446. package/src/runtime/routes/inbound-message-handler.ts +1 -9
  447. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  448. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  449. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  450. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  451. package/src/runtime/routes/index.ts +8 -0
  452. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  453. package/src/runtime/routes/memory-item-routes.ts +10 -12
  454. package/src/runtime/routes/memory-v2-routes.ts +441 -1
  455. package/src/runtime/routes/migration-routes.ts +96 -0
  456. package/src/runtime/routes/schedule-routes.ts +7 -0
  457. package/src/runtime/verification-templates.ts +4 -7
  458. package/src/schedule/integration-status.ts +66 -2
  459. package/src/schedule/recurrence-engine.ts +4 -1
  460. package/src/schedule/retry-backoff.ts +18 -0
  461. package/src/schedule/retry-policy.ts +82 -0
  462. package/src/schedule/schedule-recovery.ts +64 -0
  463. package/src/schedule/schedule-store.ts +106 -2
  464. package/src/schedule/scheduler-types.ts +25 -0
  465. package/src/schedule/scheduler.ts +63 -38
  466. package/src/security/oauth-callback-registry.ts +8 -0
  467. package/src/sequence/analytics.ts +5 -5
  468. package/src/sequence/engine.ts +1 -1
  469. package/src/skills/catalog-files.ts +2 -8
  470. package/src/skills/include-graph.ts +5 -5
  471. package/src/skills/remote-skill-policy.ts +5 -5
  472. package/src/skills/skill-file-provider.ts +1 -1
  473. package/src/skills/skill-file-types.ts +13 -0
  474. package/src/skills/skillssh-audit-types.ts +28 -0
  475. package/src/skills/skillssh-registry.ts +8 -21
  476. package/src/telemetry/types.ts +2 -0
  477. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  478. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  479. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  480. package/src/tools/apps/executors.ts +56 -69
  481. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  482. package/src/tools/browser/browser-execution.ts +2 -2
  483. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  484. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  485. package/src/tools/browser/cdp-client/factory.ts +23 -24
  486. package/src/tools/browser/cdp-client/index.ts +1 -14
  487. package/src/tools/computer-use/definitions.ts +42 -20
  488. package/src/tools/executor.ts +2 -0
  489. package/src/tools/host-filesystem/edit.ts +26 -0
  490. package/src/tools/host-filesystem/read.ts +26 -0
  491. package/src/tools/host-filesystem/transfer.ts +31 -1
  492. package/src/tools/host-filesystem/write.ts +26 -0
  493. package/src/tools/host-terminal/host-shell.ts +58 -0
  494. package/src/tools/schedule/create.ts +6 -0
  495. package/src/tools/schedule/list.ts +2 -0
  496. package/src/tools/schedule/update.ts +10 -0
  497. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  498. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  499. package/src/tools/skills/load.ts +0 -32
  500. package/src/tools/tool-approval-handler.ts +1 -5
  501. package/src/tools/types.ts +4 -0
  502. package/src/usage/pricing.ts +1 -1
  503. package/src/workspace/hatched-date.ts +86 -0
  504. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  505. package/src/workspace/migrations/006-services-config.ts +8 -5
  506. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  507. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  508. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  509. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  510. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  511. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  512. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  513. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  514. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  515. package/src/workspace/migrations/AGENTS.md +1 -1
  516. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  517. package/src/workspace/migrations/utils.ts +21 -0
  518. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  519. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  520. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  521. package/src/__tests__/twilio-rest.test.ts +0 -34
  522. package/src/backup/__tests__/backup-key.test.ts +0 -152
  523. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  524. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  525. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  526. package/src/backup/backup-key.ts +0 -137
  527. package/src/backup/backup-worker.ts +0 -472
  528. package/src/backup/offsite-writer.ts +0 -222
  529. package/src/backup/stream-crypt.ts +0 -263
  530. package/src/daemon/message-types/pairing.ts +0 -58
  531. package/src/outbound-proxy/config.ts +0 -20
  532. package/src/outbound-proxy/health.ts +0 -18
  533. package/src/outbound-proxy/types.ts +0 -150
  534. package/src/runtime/capability-tokens.ts +0 -190
  535. package/src/signals/mcp-reload.ts +0 -18
@@ -13,8 +13,8 @@ import {
13
13
  getCAPath,
14
14
  issueLeafCert,
15
15
  type RewriteCallback,
16
- type RouteDecision,
17
16
  } from "../outbound-proxy/index.js";
17
+ import type { RouteDecision } from "../outbound-proxy/router.js";
18
18
 
19
19
  let dataDir: string;
20
20
  let caDir: string;
@@ -213,6 +213,7 @@ function makeSendMessageDeps() {
213
213
  hasPendingConfirmation: () => false,
214
214
  setHostBrowserProxy: () => {},
215
215
  setHostCuProxy: () => {},
216
+ setHostAppControlProxy: () => {},
216
217
  addPreactivatedSkillId: () => {},
217
218
  } as unknown as import("../daemon/conversation.js").Conversation;
218
219
 
@@ -160,6 +160,7 @@ function makeCompletingConversation(): Conversation {
160
160
  updateClient: () => {},
161
161
  setHostBrowserProxy: () => {},
162
162
  setHostCuProxy: () => {},
163
+ setHostAppControlProxy: () => {},
163
164
  addPreactivatedSkillId: () => {},
164
165
  hasAnyPendingConfirmation: () => false,
165
166
  hasPendingConfirmation: () => false,
@@ -216,6 +217,7 @@ function makeHangingConversation(): Conversation {
216
217
  updateClient: () => {},
217
218
  setHostBrowserProxy: () => {},
218
219
  setHostCuProxy: () => {},
220
+ setHostAppControlProxy: () => {},
219
221
  addPreactivatedSkillId: () => {},
220
222
  hasAnyPendingConfirmation: () => false,
221
223
  hasPendingConfirmation: () => false,
@@ -300,6 +302,7 @@ function makePendingApprovalConversation(
300
302
  updateClient: () => {},
301
303
  setHostBrowserProxy: () => {},
302
304
  setHostCuProxy: () => {},
305
+ setHostAppControlProxy: () => {},
303
306
  addPreactivatedSkillId: () => {},
304
307
  hasAnyPendingConfirmation: () => pending.size > 0,
305
308
  hasPendingConfirmation: (candidateRequestId: string) =>
@@ -45,7 +45,6 @@ mock.module("../config/loader.js", () => ({
45
45
  getConfig: () => mockConfig,
46
46
  loadConfig: () => mockConfig,
47
47
  invalidateConfigCache: () => {},
48
- saveConfig: () => {},
49
48
  loadRawConfig: () => ({}),
50
49
  saveRawConfig: () => {},
51
50
  getNestedValue: () => undefined,
@@ -16,10 +16,11 @@ afterEach(() => {
16
16
  _setOverridesForTesting({});
17
17
  });
18
18
 
19
- const DECLARED_FLAG_ID = "sounds";
19
+ const DECLARED_FLAG_ID = "email-channel";
20
20
  const DECLARED_FLAG_KEY = DECLARED_FLAG_ID;
21
- const DECLARED_SKILL_ID = "sounds";
22
- const APP_BUILDER_MULTIFILE_FLAG_KEY = "app-builder-multifile";
21
+ const DECLARED_SKILL_ID = "email-channel";
22
+ const ENABLED_UNDECLARED_FLAG_KEY = "enabled-undeclared-flag";
23
+ const ENABLED_UNDECLARED_SKILL_ID = "enabled-undeclared-skill";
23
24
  // ---------------------------------------------------------------------------
24
25
  // Helpers
25
26
  // ---------------------------------------------------------------------------
@@ -91,14 +92,14 @@ describe("skillFlagKey", () => {
91
92
  // ---------------------------------------------------------------------------
92
93
 
93
94
  describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
94
- test("returns true when no flag overrides (registry default is true)", () => {
95
+ test("returns false when no flag overrides (registry default is false)", () => {
95
96
  const config = makeConfig();
96
97
  expect(
97
98
  isAssistantFeatureFlagEnabled(
98
99
  skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
99
100
  config,
100
101
  ),
101
- ).toBe(true);
102
+ ).toBe(false);
102
103
  });
103
104
 
104
105
  test("returns true when skill key is explicitly true", () => {
@@ -144,27 +145,18 @@ describe("isAssistantFeatureFlagEnabled", () => {
144
145
 
145
146
  test("falls back to registry default when no override", () => {
146
147
  const config = makeConfig();
147
- // sounds defaults to true in the registry
148
- expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(true);
148
+ // email-channel defaults to false in the registry
149
+ expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(
150
+ false,
151
+ );
149
152
  });
150
153
 
151
154
  test("respects persisted overrides for undeclared keys", () => {
152
- _setOverridesForTesting({ browser: false });
153
- const config = makeConfig();
154
- expect(isAssistantFeatureFlagEnabled("browser", config)).toBe(false);
155
- });
156
-
157
- test("declared keys with no persisted override use registry default", () => {
158
- const config = makeConfig();
159
- // browser is declared in the registry with defaultEnabled: true
160
- expect(isAssistantFeatureFlagEnabled("browser", config)).toBe(true);
161
- });
162
-
163
- test("app-builder-multifile defaults to enabled when no override is set", () => {
155
+ _setOverridesForTesting({ "some-undeclared-flag": false });
164
156
  const config = makeConfig();
165
- expect(
166
- isAssistantFeatureFlagEnabled(APP_BUILDER_MULTIFILE_FLAG_KEY, config),
167
- ).toBe(true);
157
+ expect(isAssistantFeatureFlagEnabled("some-undeclared-flag", config)).toBe(
158
+ false,
159
+ );
168
160
  });
169
161
  });
170
162
 
@@ -176,11 +168,15 @@ describe("resolveSkillStates with feature flags", () => {
176
168
  test("flag OFF skill does not appear in resolved list", () => {
177
169
  _setOverridesForTesting({
178
170
  [DECLARED_FLAG_KEY]: false,
179
- browser: true,
171
+ [ENABLED_UNDECLARED_FLAG_KEY]: true,
180
172
  });
181
173
  const catalog = [
182
174
  makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
183
- makeSkill("browser", "bundled", "browser"),
175
+ makeSkill(
176
+ ENABLED_UNDECLARED_SKILL_ID,
177
+ "bundled",
178
+ ENABLED_UNDECLARED_FLAG_KEY,
179
+ ),
184
180
  ];
185
181
  const config = makeConfig();
186
182
 
@@ -188,17 +184,21 @@ describe("resolveSkillStates with feature flags", () => {
188
184
  const ids = resolved.map((r) => r.summary.id);
189
185
 
190
186
  expect(ids).not.toContain(DECLARED_SKILL_ID);
191
- expect(ids).toContain("browser");
187
+ expect(ids).toContain(ENABLED_UNDECLARED_SKILL_ID);
192
188
  });
193
189
 
194
190
  test("flag ON skill appears normally", () => {
195
191
  _setOverridesForTesting({
196
192
  [DECLARED_FLAG_KEY]: true,
197
- browser: true,
193
+ [ENABLED_UNDECLARED_FLAG_KEY]: true,
198
194
  });
199
195
  const catalog = [
200
196
  makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
201
- makeSkill("browser", "bundled", "browser"),
197
+ makeSkill(
198
+ ENABLED_UNDECLARED_SKILL_ID,
199
+ "bundled",
200
+ ENABLED_UNDECLARED_FLAG_KEY,
201
+ ),
202
202
  ];
203
203
  const config = makeConfig();
204
204
 
@@ -206,17 +206,16 @@ describe("resolveSkillStates with feature flags", () => {
206
206
  const ids = resolved.map((r) => r.summary.id);
207
207
 
208
208
  expect(ids).toContain(DECLARED_SKILL_ID);
209
- expect(ids).toContain("browser");
209
+ expect(ids).toContain(ENABLED_UNDECLARED_SKILL_ID);
210
210
  });
211
211
 
212
- test("declared flag key defaults to registry value (true)", () => {
212
+ test("declared flag key defaults to registry value (false)", () => {
213
213
  const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
214
214
  const config = makeConfig();
215
215
 
216
216
  const resolved = resolveSkillStates(catalog, config);
217
- // sounds registry default is true, so it passes through
218
- expect(resolved.length).toBe(1);
219
- expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
217
+ // email-channel registry default is false, so it is filtered out
218
+ expect(resolved.length).toBe(0);
220
219
  });
221
220
 
222
221
  test("skill without featureFlag is never flag-gated", () => {
@@ -259,12 +258,16 @@ describe("resolveSkillStates with feature flags", () => {
259
258
  test("multiple skills with mixed flags — persisted overrides respected", () => {
260
259
  _setOverridesForTesting({
261
260
  [DECLARED_FLAG_KEY]: false,
262
- browser: true,
261
+ [ENABLED_UNDECLARED_FLAG_KEY]: true,
263
262
  deploy: false,
264
263
  });
265
264
  const catalog = [
266
265
  makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
267
- makeSkill("browser", "bundled", "browser"),
266
+ makeSkill(
267
+ ENABLED_UNDECLARED_SKILL_ID,
268
+ "bundled",
269
+ ENABLED_UNDECLARED_FLAG_KEY,
270
+ ),
268
271
  makeSkill("deploy", "bundled", "deploy"),
269
272
  ];
270
273
  const config = makeConfig();
@@ -272,8 +275,8 @@ describe("resolveSkillStates with feature flags", () => {
272
275
  const resolved = resolveSkillStates(catalog, config);
273
276
  const ids = resolved.map((r) => r.summary.id);
274
277
 
275
- // sounds and deploy explicitly false; browser explicitly true
276
- expect(ids).toEqual(["browser"]);
278
+ // email-channel and deploy explicitly false; one unrelated skill explicitly true
279
+ expect(ids).toEqual([ENABLED_UNDECLARED_SKILL_ID]);
277
280
  });
278
281
  });
279
282
 
@@ -282,15 +285,14 @@ describe("resolveSkillStates with feature flags", () => {
282
285
  // ---------------------------------------------------------------------------
283
286
 
284
287
  describe("resolveSkillStates with frontmatter featureFlag", () => {
285
- test("skill with featureFlag (defaultEnabled: true) is included when no config override", () => {
286
- // sounds has defaultEnabled: true in the registry
288
+ test("skill with featureFlag (defaultEnabled: false) is excluded when no config override", () => {
289
+ // email-channel has defaultEnabled: false in the registry
287
290
  const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
288
291
  const config = makeConfig();
289
292
 
290
293
  const resolved = resolveSkillStates(catalog, config);
291
- // No override, registry default is truepasses through
292
- expect(resolved.length).toBe(1);
293
- expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
294
+ // No override, registry default is falsefiltered out
295
+ expect(resolved.length).toBe(0);
294
296
  });
295
297
 
296
298
  test("skill with featureFlag is included when override enables it", () => {
@@ -12,8 +12,8 @@ const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
12
12
 
13
13
  let currentConfig: Record<string, unknown> = {};
14
14
 
15
- const DECLARED_SKILL_ID = "sounds";
16
- const DECLARED_FLAG_KEY = "sounds";
15
+ const DECLARED_SKILL_ID = "email-channel";
16
+ const DECLARED_FLAG_KEY = "email-channel";
17
17
 
18
18
  const noopLogger = new Proxy({} as Record<string, unknown>, {
19
19
  get: (_target, prop) => (prop === "child" ? () => noopLogger : () => {}),
@@ -35,7 +35,6 @@ mock.module("../config/loader.js", () => ({
35
35
  getConfigReadOnly: () => currentConfig,
36
36
  loadConfig: () => currentConfig,
37
37
  loadRawConfig: () => ({}),
38
- saveConfig: () => {},
39
38
  saveRawConfig: () => {},
40
39
  invalidateConfigCache: () => {},
41
40
  getNestedValue: () => undefined,
@@ -99,8 +98,8 @@ describe("skill_load feature flag enforcement", () => {
99
98
  test("returns deterministic error for flag OFF skill", async () => {
100
99
  writeSkill(
101
100
  DECLARED_SKILL_ID,
102
- "Sounds",
103
- "Toggle sounds behavior",
101
+ "Email Channel",
102
+ "Toggle email channel behavior",
104
103
  "Use the feature.",
105
104
  );
106
105
  writeFileSync(
@@ -120,8 +119,8 @@ describe("skill_load feature flag enforcement", () => {
120
119
  test("loads skill normally when flag is ON", async () => {
121
120
  writeSkill(
122
121
  DECLARED_SKILL_ID,
123
- "Sounds",
124
- "Toggle sounds behavior",
122
+ "Email Channel",
123
+ "Toggle email channel behavior",
125
124
  "Use the feature.",
126
125
  );
127
126
  writeFileSync(
@@ -134,14 +133,14 @@ describe("skill_load feature flag enforcement", () => {
134
133
  const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
135
134
 
136
135
  expect(result.isError).toBe(false);
137
- expect(result.content).toContain("Skill: Sounds");
136
+ expect(result.content).toContain("Skill: Email Channel");
138
137
  });
139
138
 
140
- test("loads skill when flag key is absent (registry defaults to enabled)", async () => {
139
+ test("returns error when flag key is absent (registry defaults to disabled)", async () => {
141
140
  writeSkill(
142
141
  DECLARED_SKILL_ID,
143
- "Sounds",
144
- "Toggle sounds behavior",
142
+ "Email Channel",
143
+ "Toggle email channel behavior",
145
144
  "Use the feature.",
146
145
  );
147
146
  writeFileSync(
@@ -153,8 +152,8 @@ describe("skill_load feature flag enforcement", () => {
153
152
 
154
153
  const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
155
154
 
156
- // sounds is declared in the registry with defaultEnabled: true
157
- expect(result.isError).toBe(false);
158
- expect(result.content).toContain("Skill: Sounds");
155
+ // email-channel is declared in the registry with defaultEnabled: false
156
+ expect(result.isError).toBe(true);
157
+ expect(result.content).toContain("disabled by feature flag");
159
158
  });
160
159
  });
@@ -4,8 +4,6 @@
4
4
  * Validates that:
5
5
  * - Root skills with `!\`command\`` tokens get those tokens expanded exactly
6
6
  * once at skill_load time, wrapped in <inline_skill_command> XML tags.
7
- * - When the feature flag is off, skill_load returns an error instead of
8
- * leaving unresolved live tokens in the prompt.
9
7
  * - When the skill source is "extra", skill_load rejects with a specific error.
10
8
  * - Render failures produce stable inline stubs rather than raw stderr.
11
9
  */
@@ -14,8 +12,6 @@ import { mkdirSync, writeFileSync } from "node:fs";
14
12
  import { join } from "node:path";
15
13
  import { beforeEach, describe, expect, mock, test } from "bun:test";
16
14
 
17
- import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
18
-
19
15
  // ── Test directory ────────────────────────────────────────────────────────────
20
16
 
21
17
  const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
@@ -93,7 +89,6 @@ mock.module("../config/loader.js", () => ({
93
89
  getConfig: () => testConfig,
94
90
  loadConfig: () => testConfig,
95
91
  invalidateConfigCache: () => {},
96
- saveConfig: () => {},
97
92
  loadRawConfig: () => ({}),
98
93
  saveRawConfig: () => {},
99
94
  getNestedValue: () => undefined,
@@ -163,10 +158,6 @@ describe("skill_load inline command expansion", () => {
163
158
  ) => mockRunInlineCommand(command, workingDir),
164
159
  }));
165
160
 
166
- // Enable the feature flag
167
- _setOverridesForTesting({
168
- "inline-skill-commands": true,
169
- });
170
161
  testConfig.skills = { load: { extraDirs: [] } };
171
162
  });
172
163
 
@@ -255,48 +246,6 @@ describe("skill_load inline command expansion", () => {
255
246
  });
256
247
  });
257
248
 
258
- // ── Feature flag off ─────────────────────────────────────────────────
259
-
260
- describe("feature flag disabled", () => {
261
- test("returns error when flag is off and skill has inline commands", async () => {
262
- _setOverridesForTesting({
263
- "inline-skill-commands": false,
264
- });
265
-
266
- writeSkill(
267
- "flagged-off-skill",
268
- "Flagged Off Skill",
269
- "Has inline commands",
270
- "Data: !`echo hello`",
271
- );
272
-
273
- const result = await executeSkillLoad({ skill: "flagged-off-skill" });
274
- expect(result.isError).toBe(true);
275
- expect(result.content).toContain(
276
- "inline-skill-commands feature flag is disabled",
277
- );
278
- // Runner should not be called when flag is off
279
- expect(runInlineCommandCalls).toHaveLength(0);
280
- });
281
-
282
- test("plain skill still loads when flag is off", async () => {
283
- _setOverridesForTesting({
284
- "inline-skill-commands": false,
285
- });
286
-
287
- writeSkill(
288
- "plain-flag-off",
289
- "Plain Flag Off",
290
- "No inline commands",
291
- "Regular content.",
292
- );
293
-
294
- const result = await executeSkillLoad({ skill: "plain-flag-off" });
295
- expect(result.isError).toBe(false);
296
- expect(result.content).toContain("Regular content.");
297
- });
298
- });
299
-
300
249
  // ── Extra source rejection ───────────────────────────────────────────
301
250
  //
302
251
  // The SkillLoadTool checks `skill.source === "extra"` and rejects inline
@@ -16,8 +16,6 @@ import { mkdirSync, writeFileSync } from "node:fs";
16
16
  import { join } from "node:path";
17
17
  import { beforeEach, describe, expect, mock, test } from "bun:test";
18
18
 
19
- import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
20
-
21
19
  // ── Test directory ────────────────────────────────────────────────────────────
22
20
 
23
21
  const TEST_DIR = process.env.VELLUM_WORKSPACE_DIR!;
@@ -95,7 +93,6 @@ mock.module("../config/loader.js", () => ({
95
93
  getConfig: () => testConfig,
96
94
  loadConfig: () => testConfig,
97
95
  invalidateConfigCache: () => {},
98
- saveConfig: () => {},
99
96
  loadRawConfig: () => ({}),
100
97
  saveRawConfig: () => {},
101
98
  getNestedValue: () => undefined,
@@ -173,10 +170,6 @@ describe("skill_load inline command expansion for included skills", () => {
173
170
  ) => mockRunInlineCommand(command, workingDir),
174
171
  }));
175
172
 
176
- // Enable the feature flag
177
- _setOverridesForTesting({
178
- "inline-skill-commands": true,
179
- });
180
173
  testConfig.skills = { load: { extraDirs: [] } };
181
174
  });
182
175
 
@@ -514,42 +507,6 @@ describe("skill_load inline command expansion for included skills", () => {
514
507
  });
515
508
  });
516
509
 
517
- // ── Feature flag off for child inline commands ────────────────────────
518
-
519
- describe("feature flag disabled for included skills", () => {
520
- test("skill_load returns error when child has inline commands and flag is off", async () => {
521
- _setOverridesForTesting({
522
- "inline-skill-commands": false,
523
- });
524
-
525
- writeSkill(
526
- "child-flag-off",
527
- "Flag Off Child",
528
- "Child with inline cmds",
529
- "Data: !`echo hello`",
530
- );
531
- writeSkill(
532
- "parent-flag-off",
533
- "Parent Flag Off",
534
- "Parent for flag-off test",
535
- "Root content.",
536
- { includes: ["child-flag-off"] },
537
- );
538
-
539
- const result = await executeSkillLoad({ skill: "parent-flag-off" });
540
- // Fail closed: the entire skill_load must error when any included child
541
- // has inline commands and the feature flag is off, matching the root
542
- // skill behavior and the documented fail-closed contract.
543
- expect(result.isError).toBe(true);
544
- expect(result.content).toContain("child-flag-off");
545
- expect(result.content).toContain(
546
- "inline-skill-commands feature flag is disabled",
547
- );
548
- // Runner should not be called
549
- expect(runInlineCommandCalls).toHaveLength(0);
550
- });
551
- });
552
-
553
510
  // ── Root with inline + child with inline ──────────────────────────────
554
511
 
555
512
  describe("root and child both have inline commands", () => {
@@ -28,7 +28,6 @@ mock.module("../config/loader.js", () => ({
28
28
  getConfig: () => ({}),
29
29
  loadConfig: () => ({}),
30
30
  applyNestedDefaults: (c: unknown) => c,
31
- saveConfig: () => {},
32
31
  invalidateConfigCache: () => {},
33
32
  loadRawConfig: () => ({}),
34
33
  saveRawConfig: () => {},
@@ -28,7 +28,6 @@ mock.module("../config/loader.js", () => ({
28
28
  getConfig: () => mockConfig,
29
29
  loadConfig: () => mockConfig,
30
30
  invalidateConfigCache: () => {},
31
- saveConfig: () => {},
32
31
  loadRawConfig: () => ({}),
33
32
  saveRawConfig: () => {},
34
33
  getNestedValue: () => undefined,
@@ -61,7 +61,6 @@ mock.module("../config/loader.js", () => ({
61
61
  saveRawConfig: (raw: Record<string, unknown>) => {
62
62
  configStore = structuredClone(raw);
63
63
  },
64
- saveConfig: () => {},
65
64
  invalidateConfigCache: () => {},
66
65
  setNestedValue,
67
66
  }));
@@ -438,11 +437,7 @@ describe("Slack channel config handler", () => {
438
437
  });
439
438
 
440
439
  test("POST rejects user token with invalid prefix", async () => {
441
- const result = await setSlackChannelConfig(
442
- undefined,
443
- undefined,
444
- "abc-123",
445
- );
440
+ const result = await setSlackChannelConfig(undefined, undefined, "abc-123");
446
441
  expect(result.success).toBe(false);
447
442
  expect(result.error).toContain("xoxp-");
448
443
  // Nothing was stored.
@@ -660,9 +655,7 @@ describe("Slack channel config handler", () => {
660
655
  expect(
661
656
  await getSecureKeyAsync(credentialKey("slack_channel", "user_token")),
662
657
  ).toBe("xoxp-still-valid");
663
- expect(
664
- getCredentialMetadata("slack_channel", "user_token"),
665
- ).toBeDefined();
658
+ expect(getCredentialMetadata("slack_channel", "user_token")).toBeDefined();
666
659
 
667
660
  // No warning about user_token removal — nothing was removed.
668
661
  expect(result.warning ?? "").not.toContain("User token");
@@ -697,10 +690,10 @@ describe("Slack channel config handler", () => {
697
690
  }
698
691
  if (auth === "Bearer xoxp-workspace-a") {
699
692
  // Workspace mismatch — handler will try to clear the user_token.
700
- return new Response(
701
- JSON.stringify({ ok: true, team_id: "T_A" }),
702
- { status: 200, headers: { "content-type": "application/json" } },
703
- );
693
+ return new Response(JSON.stringify({ ok: true, team_id: "T_A" }), {
694
+ status: 200,
695
+ headers: { "content-type": "application/json" },
696
+ });
704
697
  }
705
698
  throw new Error(`Unexpected auth header: ${auth}`);
706
699
  }) as unknown as typeof globalThis.fetch;
@@ -808,7 +801,9 @@ describe("Slack channel config handler", () => {
808
801
  expect(
809
802
  await getSecureKeyAsync(credentialKey("slack_channel", "user_token")),
810
803
  ).toBeUndefined();
811
- expect(getCredentialMetadata("slack_channel", "user_token")).toBeUndefined();
804
+ expect(
805
+ getCredentialMetadata("slack_channel", "user_token"),
806
+ ).toBeUndefined();
812
807
  });
813
808
 
814
809
  test("clearSlackUserToken leaves bot+app tokens and oauth_connection intact", async () => {
@@ -49,7 +49,6 @@ mock.module("../config/loader.js", () => ({
49
49
  }),
50
50
  loadConfig: () => ({}),
51
51
  loadRawConfig: () => ({}),
52
- saveConfig: () => {},
53
52
  saveRawConfig: () => {},
54
53
  invalidateConfigCache: () => {},
55
54
  getNestedValue: () => undefined,
@@ -55,7 +55,6 @@ mock.module("../config/loader.js", () => ({
55
55
  }),
56
56
  loadConfig: () => mockLoadedConfig,
57
57
  loadRawConfig: () => ({}),
58
- saveConfig: () => {},
59
58
  saveRawConfig: () => {},
60
59
  invalidateConfigCache: () => {},
61
60
  getNestedValue: () => undefined,
@@ -13,7 +13,6 @@ mock.module("../config/loader.js", () => ({
13
13
  getConfig: () => ({ telegram: {}, ui: {} }),
14
14
  loadRawConfig: () => ({}),
15
15
  saveRawConfig: () => {},
16
- saveConfig: () => {},
17
16
  invalidateConfigCache: () => {},
18
17
  setNestedValue: () => {},
19
18
  }));
@@ -17,6 +17,7 @@ import { join } from "node:path";
17
17
  import { afterAll } from "bun:test";
18
18
 
19
19
  import { installGatewayIpcMock } from "../__tests__/mock-gateway-ipc.js";
20
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
20
21
  import { resetDb } from "../memory/db-connection.js";
21
22
  import { _setStorePath } from "../security/encrypted-store.js";
22
23
 
@@ -36,6 +37,13 @@ _setStorePath(join(testDir, "keys.enc"));
36
37
  // Tests that need to control IPC responses use mockGatewayIpc() / resetMockGatewayIpc().
37
38
  installGatewayIpcMock();
38
39
 
40
+ // Pre-populate the feature-flag override cache so `initFeatureFlagOverrides()`
41
+ // short-circuits its retry loop — there is no real gateway in tests, and the
42
+ // retry backoff would otherwise exceed the per-test timeout for any test that
43
+ // builds the CLI program. Tests exercising the retry behavior call
44
+ // `clearFeatureFlagOverridesCache()` first.
45
+ _setOverridesForTesting({});
46
+
39
47
  // Force-close any DB connection inherited from the parent process (e.g. when
40
48
  // the test runner is spawned by the running assistant via a pre-push hook).
41
49
  // Without this, the db singleton in db-connection.ts may still point at the
@@ -518,7 +518,7 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
518
518
  }
519
519
  });
520
520
 
521
- test("trusted contact bypasses tool grants for sandboxed side-effect tools", async () => {
521
+ test("trusted contact requires grant for sandboxed side-effect tools", async () => {
522
522
  const result = await handler.checkPreExecutionGates(
523
523
  "bash",
524
524
  { command: "echo hello" },
@@ -529,12 +529,11 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
529
529
  emitLifecycleEvent,
530
530
  );
531
531
 
532
- expect(result.allowed).toBe(true);
532
+ expect(result.allowed).toBe(false);
533
533
  expect(events.filter((e) => e.type === "permission_denied")).toHaveLength(
534
- 0,
534
+ 1,
535
535
  );
536
536
  });
537
-
538
537
  });
539
538
 
540
539
  afterAll(() => {
@@ -64,6 +64,54 @@ describe("tool audit listener", () => {
64
64
  expect(records[1].decision).toBe("denied");
65
65
  });
66
66
 
67
+ test("redacts known-pattern secrets in tool result content before recording", () => {
68
+ const records: ToolInvocationRecord[] = [];
69
+ const listener = createToolAuditListener((record) => records.push(record));
70
+
71
+ // Anthropic key pattern requires 80+ chars after "sk-ant-"
72
+ const anthropicKey =
73
+ "sk-ant-api03-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
74
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
75
+ listener({
76
+ type: "executed",
77
+ toolName: "bash",
78
+ input: { command: "echo $ANTHROPIC_API_KEY" },
79
+ workingDir: "/tmp",
80
+ conversationId: "conv-redact",
81
+ riskLevel: "low",
82
+ decision: "allow",
83
+ durationMs: 5,
84
+ result: { content: `key=${anthropicKey}`, isError: false },
85
+ });
86
+
87
+ expect(records).toHaveLength(1);
88
+ expect(records[0].result).not.toContain("sk-ant-api03-");
89
+ expect(records[0].result).toContain("<redacted");
90
+ });
91
+
92
+ test("does not redact non-secret content like UUIDs or hashes", () => {
93
+ const records: ToolInvocationRecord[] = [];
94
+ const listener = createToolAuditListener((record) => records.push(record));
95
+
96
+ const safeContent =
97
+ "file id: 550e8400-e29b-41d4-a716-446655440000, sha: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2";
98
+
99
+ listener({
100
+ type: "executed",
101
+ toolName: "file_read",
102
+ input: { path: "/tmp/data" },
103
+ workingDir: "/tmp",
104
+ conversationId: "conv-safe",
105
+ riskLevel: "low",
106
+ decision: "allow",
107
+ durationMs: 3,
108
+ result: { content: safeContent, isError: false },
109
+ });
110
+
111
+ expect(records).toHaveLength(1);
112
+ expect(records[0].result).toBe(safeContent);
113
+ });
114
+
67
115
  test("records error events and ignores non-terminal events", () => {
68
116
  const records: ToolInvocationRecord[] = [];
69
117
  const listener = createToolAuditListener((record) => records.push(record));