@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
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import type { ApprovalContext, ApprovalDecision } from "./approval-policy.js";
4
- import { DefaultApprovalPolicy, resolveThreshold } from "./approval-policy.js";
4
+ import { DefaultApprovalPolicy } from "./approval-policy.js";
5
5
  import type { TrustRule } from "./types.js";
6
6
  import { RiskLevel } from "./types.js";
7
7
 
@@ -74,7 +74,11 @@ describe("ask rule", () => {
74
74
  const askRule = makeRule({ decision: "ask" });
75
75
 
76
76
  test("ask at Low risk", () => {
77
- const result = evaluate({ riskLevel: RiskLevel.Low, matchedRule: askRule, autoApproveUpTo: "none" });
77
+ const result = evaluate({
78
+ riskLevel: RiskLevel.Low,
79
+ matchedRule: askRule,
80
+ autoApproveUpTo: "none",
81
+ });
78
82
  expect(result.decision).toBe("prompt");
79
83
  expect(result.reason).toContain("ask rule");
80
84
  expect(result.matchedRule).toBe(askRule);
@@ -965,276 +969,3 @@ describe("autoApproveUpTo threshold", () => {
965
969
  });
966
970
  });
967
971
  });
968
-
969
- // ── resolveThreshold ─────────────────────────────────────────────────────────
970
-
971
- describe("resolveThreshold", () => {
972
- describe("scalar form", () => {
973
- test("returns scalar for conversation context", () => {
974
- expect(resolveThreshold("low", "conversation")).toBe("low");
975
- });
976
-
977
- test("returns scalar for background context", () => {
978
- expect(resolveThreshold("medium", "background")).toBe("medium");
979
- });
980
-
981
- test("returns scalar for headless context", () => {
982
- expect(resolveThreshold("none", "headless")).toBe("none");
983
- });
984
-
985
- test("returns high scalar for any context", () => {
986
- expect(resolveThreshold("high", "conversation")).toBe("high");
987
- expect(resolveThreshold("high", "background")).toBe("high");
988
- expect(resolveThreshold("high", "headless")).toBe("high");
989
- });
990
-
991
- test("returns scalar when executionContext is omitted", () => {
992
- expect(resolveThreshold("low")).toBe("low");
993
- });
994
- });
995
-
996
- describe("object form", () => {
997
- const perContext = {
998
- conversation: "low" as const,
999
- autonomous: "medium" as const,
1000
- };
1001
-
1002
- test("returns conversation threshold for conversation context", () => {
1003
- expect(resolveThreshold(perContext, "conversation")).toBe("low");
1004
- });
1005
-
1006
- test("returns autonomous threshold for background context", () => {
1007
- expect(resolveThreshold(perContext, "background")).toBe("medium");
1008
- });
1009
-
1010
- test("returns autonomous threshold for headless context", () => {
1011
- expect(resolveThreshold(perContext, "headless")).toBe("medium");
1012
- });
1013
-
1014
- test("defaults to conversation when executionContext is omitted", () => {
1015
- expect(resolveThreshold(perContext)).toBe("low");
1016
- });
1017
- });
1018
-
1019
- describe("per-context thresholds in policy evaluation", () => {
1020
- test("conversation context with low threshold prompts medium risk", () => {
1021
- const result = evaluate({
1022
- riskLevel: RiskLevel.Medium,
1023
- toolName: "some_tool",
1024
- autoApproveUpTo: "low",
1025
- });
1026
- expect(result.decision).toBe("prompt");
1027
- });
1028
-
1029
- test("background context with medium threshold allows medium risk", () => {
1030
- const result = evaluate({
1031
- riskLevel: RiskLevel.Medium,
1032
- toolName: "some_tool",
1033
- autoApproveUpTo: "medium",
1034
- });
1035
- expect(result.decision).toBe("allow");
1036
- expect(result.reason).toContain("within auto-approve threshold");
1037
- });
1038
-
1039
- test("headless context with none threshold prompts low risk", () => {
1040
- const result = evaluate({
1041
- riskLevel: RiskLevel.Low,
1042
- toolName: "some_tool",
1043
- autoApproveUpTo: "none",
1044
- });
1045
- expect(result.decision).toBe("prompt");
1046
- expect(result.reason).toContain("above auto-approve threshold");
1047
- });
1048
-
1049
- test("background context with medium threshold prompts high risk", () => {
1050
- const result = evaluate({
1051
- riskLevel: RiskLevel.High,
1052
- toolName: "some_tool",
1053
- autoApproveUpTo: "medium",
1054
- });
1055
- expect(result.decision).toBe("prompt");
1056
- expect(result.reason).toContain("above auto-approve threshold");
1057
- });
1058
- });
1059
- });
1060
-
1061
- // ── Guardian threshold-based auto-approve ────────────────────────────────────
1062
- // These tests verify the ordinal comparison used in permission-checker.ts
1063
- // to decide whether a guardian non-interactive session should auto-approve.
1064
- // The comparison logic: riskOrdinal <= thresholdOrdinal.
1065
-
1066
- describe("guardian threshold-based auto-approve (ordinal comparison)", () => {
1067
- // Helper that mirrors the ordinal comparison from permission-checker.ts.
1068
- // This is the logic that replaces the old `riskLevel !== RiskLevel.High` check.
1069
- function isWithinThreshold(
1070
- riskLevel: RiskLevel,
1071
- bgThreshold: "none" | "low" | "medium" | "high",
1072
- ): boolean {
1073
- const thresholdOrdinal: Record<string, number> = {
1074
- none: -1,
1075
- low: 0,
1076
- medium: 1,
1077
- high: 2,
1078
- };
1079
- const riskOrdinal: Record<string, number> = {
1080
- [RiskLevel.Low]: 0,
1081
- [RiskLevel.Medium]: 1,
1082
- [RiskLevel.High]: 2,
1083
- };
1084
- return (
1085
- (riskOrdinal[riskLevel] ?? 2) <= (thresholdOrdinal[bgThreshold] ?? 0)
1086
- );
1087
- }
1088
-
1089
- describe('default config (autonomous: "medium") — behavioral parity with old riskLevel !== High', () => {
1090
- test("Low risk → within threshold (auto-approve)", () => {
1091
- const bgThreshold = resolveThreshold(
1092
- { conversation: "low", autonomous: "medium" },
1093
- "background",
1094
- );
1095
- expect(bgThreshold).toBe("medium");
1096
- expect(isWithinThreshold(RiskLevel.Low, bgThreshold)).toBe(true);
1097
- });
1098
-
1099
- test("Medium risk → within threshold (auto-approve)", () => {
1100
- const bgThreshold = resolveThreshold(
1101
- { conversation: "low", autonomous: "medium" },
1102
- "background",
1103
- );
1104
- expect(isWithinThreshold(RiskLevel.Medium, bgThreshold)).toBe(true);
1105
- });
1106
-
1107
- test("High risk → above threshold (prompt)", () => {
1108
- const bgThreshold = resolveThreshold(
1109
- { conversation: "low", autonomous: "medium" },
1110
- "background",
1111
- );
1112
- expect(isWithinThreshold(RiskLevel.High, bgThreshold)).toBe(false);
1113
- });
1114
- });
1115
-
1116
- describe('tighter config (autonomous: "low") — only Low auto-approves', () => {
1117
- test("Low risk → within threshold", () => {
1118
- const bgThreshold = resolveThreshold(
1119
- { conversation: "low", autonomous: "low" },
1120
- "background",
1121
- );
1122
- expect(bgThreshold).toBe("low");
1123
- expect(isWithinThreshold(RiskLevel.Low, bgThreshold)).toBe(true);
1124
- });
1125
-
1126
- test("Medium risk → above threshold (prompt)", () => {
1127
- const bgThreshold = resolveThreshold(
1128
- { conversation: "low", autonomous: "low" },
1129
- "background",
1130
- );
1131
- expect(isWithinThreshold(RiskLevel.Medium, bgThreshold)).toBe(false);
1132
- });
1133
-
1134
- test("High risk → above threshold (prompt)", () => {
1135
- const bgThreshold = resolveThreshold(
1136
- { conversation: "low", autonomous: "low" },
1137
- "background",
1138
- );
1139
- expect(isWithinThreshold(RiskLevel.High, bgThreshold)).toBe(false);
1140
- });
1141
- });
1142
-
1143
- describe('strictest config (autonomous: "none") — nothing auto-approves', () => {
1144
- test("Low risk → above threshold (prompt)", () => {
1145
- const bgThreshold = resolveThreshold(
1146
- { conversation: "low", autonomous: "none" },
1147
- "background",
1148
- );
1149
- expect(bgThreshold).toBe("none");
1150
- expect(isWithinThreshold(RiskLevel.Low, bgThreshold)).toBe(false);
1151
- });
1152
-
1153
- test("Medium risk → above threshold (prompt)", () => {
1154
- const bgThreshold = resolveThreshold(
1155
- { conversation: "low", autonomous: "none" },
1156
- "background",
1157
- );
1158
- expect(isWithinThreshold(RiskLevel.Medium, bgThreshold)).toBe(false);
1159
- });
1160
-
1161
- test("High risk → above threshold (prompt)", () => {
1162
- const bgThreshold = resolveThreshold(
1163
- { conversation: "low", autonomous: "none" },
1164
- "background",
1165
- );
1166
- expect(isWithinThreshold(RiskLevel.High, bgThreshold)).toBe(false);
1167
- });
1168
- });
1169
-
1170
- describe('loosest config (autonomous: "high") — everything auto-approves', () => {
1171
- test("Low risk → within threshold (auto-approve)", () => {
1172
- const bgThreshold = resolveThreshold(
1173
- { conversation: "low", autonomous: "high" },
1174
- "background",
1175
- );
1176
- expect(bgThreshold).toBe("high");
1177
- expect(isWithinThreshold(RiskLevel.Low, bgThreshold)).toBe(true);
1178
- });
1179
-
1180
- test("Medium risk → within threshold (auto-approve)", () => {
1181
- const bgThreshold = resolveThreshold(
1182
- { conversation: "low", autonomous: "high" },
1183
- "background",
1184
- );
1185
- expect(isWithinThreshold(RiskLevel.Medium, bgThreshold)).toBe(true);
1186
- });
1187
-
1188
- test("High risk → within threshold (auto-approve)", () => {
1189
- const bgThreshold = resolveThreshold(
1190
- { conversation: "low", autonomous: "high" },
1191
- "background",
1192
- );
1193
- expect(isWithinThreshold(RiskLevel.High, bgThreshold)).toBe(true);
1194
- });
1195
- });
1196
-
1197
- describe("scalar config form resolves correctly for background context", () => {
1198
- test('scalar "high" → background resolves to high', () => {
1199
- expect(resolveThreshold("high", "background")).toBe("high");
1200
- });
1201
-
1202
- test('scalar "medium" → background resolves to medium', () => {
1203
- expect(resolveThreshold("medium", "background")).toBe("medium");
1204
- });
1205
-
1206
- test('scalar "low" → background resolves to low', () => {
1207
- expect(resolveThreshold("low", "background")).toBe("low");
1208
- });
1209
-
1210
- test('scalar "none" → background resolves to none', () => {
1211
- expect(resolveThreshold("none", "background")).toBe("none");
1212
- });
1213
- });
1214
-
1215
- describe("default (undefined) resolves per-context defaults", () => {
1216
- test("undefined config → low threshold for background", () => {
1217
- const bgThreshold = resolveThreshold(undefined, "background");
1218
- expect(bgThreshold).toBe("low");
1219
- // Low-risk auto-approves at the "low" threshold
1220
- expect(isWithinThreshold(RiskLevel.Low, bgThreshold)).toBe(true);
1221
- expect(isWithinThreshold(RiskLevel.Medium, bgThreshold)).toBe(false);
1222
- expect(isWithinThreshold(RiskLevel.High, bgThreshold)).toBe(false);
1223
- });
1224
-
1225
- test("undefined config → medium threshold for conversation", () => {
1226
- const convThreshold = resolveThreshold(undefined, "conversation");
1227
- expect(convThreshold).toBe("medium");
1228
- });
1229
-
1230
- test("undefined config → low threshold for headless", () => {
1231
- const hlThreshold = resolveThreshold(undefined, "headless");
1232
- expect(hlThreshold).toBe("low");
1233
- });
1234
-
1235
- test("undefined config + no context → medium (conversation default)", () => {
1236
- const threshold = resolveThreshold(undefined);
1237
- expect(threshold).toBe("medium");
1238
- });
1239
- });
1240
- });
@@ -31,57 +31,6 @@ export interface ApprovalContext {
31
31
  autoApproveUpTo?: "none" | "low" | "medium" | "high";
32
32
  }
33
33
 
34
- // ── Threshold resolution ─────────────────────────────────────────────────────
35
-
36
- /**
37
- * Per-context defaults when no threshold is provided by the gateway. These
38
- * mirror the gateway's own defaults and serve as defense-in-depth for tests /
39
- * direct callers that bypass the IPC path.
40
- *
41
- * Note: when a scalar value (e.g. `"low"`) is passed, it applies uniformly to
42
- * ALL contexts — including autonomous, whose default here is `"low"`. A scalar
43
- * `"none"` is therefore *more strict* than the autonomous default. This is
44
- * intentional: the caller explicitly chose a uniform threshold.
45
- */
46
- const CONTEXT_DEFAULTS: Record<
47
- ExecutionContext,
48
- "none" | "low" | "medium" | "high"
49
- > = {
50
- conversation: "medium",
51
- background: "low",
52
- headless: "low",
53
- };
54
-
55
- type ThresholdScalar = "none" | "low" | "medium" | "high";
56
- type ThresholdConfig =
57
- | ThresholdScalar
58
- | { conversation: ThresholdScalar; autonomous: ThresholdScalar };
59
-
60
- /**
61
- * Resolve a threshold config to a scalar threshold for the given execution
62
- * context.
63
- *
64
- * - Scalar string → returned as-is for all contexts
65
- * - Object with per-context overrides → returns the value for the context
66
- * (`background` and `headless` both resolve to the `autonomous` field)
67
- *
68
- * When `executionContext` is omitted, defaults to `"conversation"`.
69
- */
70
- export function resolveThreshold(
71
- configValue: ThresholdConfig | undefined,
72
- executionContext?: ExecutionContext,
73
- ): ThresholdScalar {
74
- if (configValue == null) {
75
- return CONTEXT_DEFAULTS[executionContext ?? "conversation"];
76
- }
77
- if (typeof configValue === "string") {
78
- return configValue;
79
- }
80
- const ctx = executionContext ?? "conversation";
81
- if (ctx === "conversation") return configValue.conversation;
82
- return configValue.autonomous;
83
- }
84
-
85
34
  // ── Ordinal maps for threshold comparison ─────────────────────────────────────
86
35
  // Hoisted to module level since these are constant. Unknown enum values
87
36
  // conservatively map to the strictest interpretation: risk defaults to 2 (high)
@@ -25,7 +25,6 @@ mock.module("../config/loader.js", () => ({
25
25
  getConfig: () => testConfig,
26
26
  loadConfig: () => testConfig,
27
27
  invalidateConfigCache: () => {},
28
- saveConfig: () => {},
29
28
  loadRawConfig: () => ({}),
30
29
  saveRawConfig: () => {},
31
30
  getNestedValue: () => undefined,
@@ -2,7 +2,6 @@ import { createHash } from "node:crypto";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
 
5
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
6
5
  import { getIsContainerized } from "../config/env-registry.js";
7
6
  import { getConfig } from "../config/loader.js";
8
7
  import { loadSkillCatalog, resolveSkillSelector } from "../config/skills.js";
@@ -268,23 +267,17 @@ function resolveSkillMetadata(selector: string): SkillMetadata | undefined {
268
267
  const resolved = resolveSkillIdAndHash(selector);
269
268
  if (!resolved) return undefined;
270
269
 
271
- const config = getConfig();
272
- const inlineEnabled = isAssistantFeatureFlagEnabled(
273
- "inline-skill-commands",
274
- config,
275
- );
276
270
  const inlineExpansions = hasInlineExpansions(resolved.id);
277
- const isDynamic = inlineEnabled && inlineExpansions;
278
271
 
279
272
  return {
280
273
  skillId: resolved.id,
281
274
  selector,
282
275
  versionHash: resolved.versionHash ?? "",
283
- transitiveHash: isDynamic
276
+ transitiveHash: inlineExpansions
284
277
  ? computeTransitiveHashSafe(resolved.id)
285
278
  : undefined,
286
279
  hasInlineExpansions: inlineExpansions,
287
- isDynamic,
280
+ isDynamic: inlineExpansions,
288
281
  };
289
282
  }
290
283
 
@@ -726,14 +719,7 @@ function skillLoadAllowlistStrategy(
726
719
  if (rawSelector) {
727
720
  const resolved = resolveSkillIdAndHash(rawSelector);
728
721
 
729
- // Check whether this is a dynamic (inline-command) skill load
730
- const config = getConfig();
731
- const inlineEnabled = isAssistantFeatureFlagEnabled(
732
- "inline-skill-commands",
733
- config,
734
- );
735
-
736
- if (resolved && inlineEnabled && hasInlineExpansions(resolved.id)) {
722
+ if (resolved && hasInlineExpansions(resolved.id)) {
737
723
  const transitiveHash = computeTransitiveHashSafe(resolved.id);
738
724
  const options: AllowlistOption[] = [];
739
725
  if (transitiveHash) {
@@ -20,6 +20,7 @@ type Threshold = "none" | "low" | "medium" | "high";
20
20
  interface GlobalThresholds {
21
21
  interactive: string;
22
22
  autonomous: string;
23
+ headless: string;
23
24
  }
24
25
 
25
26
  interface ConversationThreshold {
@@ -58,6 +59,7 @@ function mapExecutionContextToField(
58
59
  executionContext: ExecutionContext,
59
60
  ): keyof GlobalThresholds {
60
61
  if (executionContext === "conversation") return "interactive";
62
+ if (executionContext === "headless") return "headless";
61
63
  return "autonomous";
62
64
  }
63
65
 
@@ -2,6 +2,7 @@ import { v4 as uuid } from "uuid";
2
2
 
3
3
  import { getConfig } from "../config/loader.js";
4
4
  import type { ServerMessage } from "../daemon/message-protocol.js";
5
+ import * as pendingInteractions from "../runtime/pending-interactions.js";
5
6
  import { redactSensitiveFields } from "../security/redaction.js";
6
7
  import type { ExecutionTarget } from "../tools/types.js";
7
8
  import { AssistantError, ErrorCode } from "../util/errors.js";
@@ -81,10 +82,36 @@ export class PermissionPrompter {
81
82
 
82
83
  const requestId = uuid();
83
84
 
85
+ // Self-register in pendingInteractions so /v1/confirm can route the
86
+ // response to this conversation without going through broadcastMessage.
87
+ if (conversationId) {
88
+ pendingInteractions.register(requestId, {
89
+ conversationId,
90
+ kind: "confirmation",
91
+ confirmationDetails: {
92
+ toolName,
93
+ input: redactSensitiveFields(input),
94
+ riskLevel,
95
+ executionTarget,
96
+ allowlistOptions: allowlistOptions.map((o) => ({
97
+ label: o.label,
98
+ description: o.description,
99
+ pattern: o.pattern,
100
+ })),
101
+ scopeOptions: scopeOptions.map((o) => ({
102
+ label: o.label,
103
+ scope: o.scope,
104
+ })),
105
+ persistentDecisionsAllowed: persistentDecisionsAllowed ?? true,
106
+ },
107
+ });
108
+ }
109
+
84
110
  return new Promise((resolve, reject) => {
85
111
  const timeoutMs = getConfig().timeouts.permissionTimeoutSec * 1000;
86
112
  const timer = setTimeout(() => {
87
113
  this.pending.delete(requestId);
114
+ pendingInteractions.resolve(requestId);
88
115
  log.warn(
89
116
  { requestId, toolName },
90
117
  "Permission prompt timed out, defaulting to deny",
@@ -109,6 +136,7 @@ export class PermissionPrompter {
109
136
  if (this.pending.has(requestId)) {
110
137
  clearTimeout(timer);
111
138
  this.pending.delete(requestId);
139
+ pendingInteractions.resolve(requestId);
112
140
  resolve({ decision: "deny", wasAbort: true });
113
141
  }
114
142
  };
@@ -174,6 +202,9 @@ export class PermissionPrompter {
174
202
  }
175
203
  clearTimeout(pending.timer);
176
204
  this.pending.delete(requestId);
205
+ // Idempotent — approval-routes already calls pendingInteractions.resolve()
206
+ // before routing here, but we call it defensively for non-route paths.
207
+ pendingInteractions.resolve(requestId);
177
208
  pending.resolve({
178
209
  decision,
179
210
  selectedPattern,
@@ -191,6 +222,7 @@ export class PermissionPrompter {
191
222
  for (const [requestId, pending] of this.pending) {
192
223
  clearTimeout(pending.timer);
193
224
  this.pending.delete(requestId);
225
+ pendingInteractions.resolve(requestId);
194
226
  pending.resolve({
195
227
  decision: "deny",
196
228
  wasSystemCancel: true,
@@ -205,8 +237,9 @@ export class PermissionPrompter {
205
237
  }
206
238
 
207
239
  dispose(): void {
208
- for (const [, pending] of this.pending) {
240
+ for (const [requestId, pending] of this.pending) {
209
241
  clearTimeout(pending.timer);
242
+ pendingInteractions.resolve(requestId);
210
243
  pending.reject(
211
244
  new AssistantError("Prompter disposed", ErrorCode.INTERNAL_ERROR),
212
245
  );
@@ -81,8 +81,12 @@ export class SecretPrompter {
81
81
 
82
82
  this.pending.set(requestId, { resolve, reject, timer });
83
83
 
84
- // pendingInteractions.register is now handled by broadcastMessage
85
- // when the secret_request event is published to the hub.
84
+ // Self-register in pendingInteractions so /v1/secret can route the
85
+ // response to this conversation without relying on broadcastMessage.
86
+ pendingInteractions.register(requestId, {
87
+ conversationId: effectiveConversationId,
88
+ kind: "secret",
89
+ });
86
90
 
87
91
  const config = getConfig();
88
92
  const msg: SecretRequestMessage = {
@@ -0,0 +1,27 @@
1
+ import { existsSync, unlinkSync } from "node:fs";
2
+
3
+ import { getLogger } from "../util/logger.js";
4
+ import { getWorkspacePromptPath } from "../util/platform.js";
5
+
6
+ const log = getLogger("bootstrap-cleanup");
7
+
8
+ const BOOTSTRAP_FILES = ["BOOTSTRAP.md", "BOOTSTRAP-REFERENCE.md"] as const;
9
+
10
+ export function cleanupBootstrapFiles(reason: string): boolean {
11
+ let deletedAny = false;
12
+
13
+ for (const file of BOOTSTRAP_FILES) {
14
+ const path = getWorkspacePromptPath(file);
15
+ if (!existsSync(path)) continue;
16
+
17
+ try {
18
+ unlinkSync(path);
19
+ deletedAny = true;
20
+ log.info({ file, reason }, "Deleted bootstrap file");
21
+ } catch (err) {
22
+ log.warn({ err, file, reason }, "Failed to delete bootstrap file");
23
+ }
24
+ }
25
+
26
+ return deletedAny;
27
+ }
@@ -4,7 +4,6 @@ import {
4
4
  mkdirSync,
5
5
  readdirSync,
6
6
  readFileSync,
7
- unlinkSync,
8
7
  } from "node:fs";
9
8
  import { join } from "node:path";
10
9
 
@@ -20,6 +19,7 @@ import {
20
19
  getWorkspacePromptPath,
21
20
  } from "../util/platform.js";
22
21
  import { stripCommentLines } from "../util/strip-comment-lines.js";
22
+ import { cleanupBootstrapFiles } from "./bootstrap-cleanup.js";
23
23
  import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "./cache-boundary.js";
24
24
 
25
25
  export { SYSTEM_PROMPT_CACHE_BOUNDARY };
@@ -155,22 +155,7 @@ export function ensurePromptFiles(): void {
155
155
  const convDir = getConversationsDir();
156
156
  try {
157
157
  if (existsSync(convDir) && readdirSync(convDir).length > 0) {
158
- unlinkSync(bootstrapCleanup);
159
- log.info("Auto-deleted stale BOOTSTRAP.md — prior conversations exist");
160
-
161
- // Also clean up the reference file
162
- const refCleanup = getWorkspacePromptPath("BOOTSTRAP-REFERENCE.md");
163
- if (existsSync(refCleanup)) {
164
- try {
165
- unlinkSync(refCleanup);
166
- log.info("Auto-deleted stale BOOTSTRAP-REFERENCE.md");
167
- } catch (err) {
168
- log.warn(
169
- { err },
170
- "Failed to auto-delete stale BOOTSTRAP-REFERENCE.md",
171
- );
172
- }
173
- }
158
+ cleanupBootstrapFiles("prior conversations exist");
174
159
  }
175
160
  } catch (err) {
176
161
  log.warn({ err }, "Failed to auto-delete stale BOOTSTRAP.md");
@@ -343,7 +328,7 @@ export function buildSystemPrompt(options?: BuildSystemPromptOptions): string {
343
328
  "```json\n" +
344
329
  JSON.stringify(options.onboardingContext, null, 2) +
345
330
  "\n```\n\n" +
346
- "Use this to personalize your opener and skip redundant discovery.",
331
+ "Use this to personalize your opener and skip redundant discovery. If `assistantName` is present, it is the name the user chose for you; preserve it in IDENTITY.md.",
347
332
  );
348
333
  }
349
334
  }
@@ -1,8 +1,18 @@
1
1
  _ Lines starting with _ are comments - they won't appear in the system prompt
2
+ _ When editing this file: the current contents are in your system prompt. Use that exact text as old_string.
3
+ _ Never reconstruct old_string from memory or expectation. Read what's there.
2
4
 
3
5
  # SOUL.md
4
6
 
5
- This file defines your personality and principles. Edit it freely - reshape it as you grow. Add sections, remove what doesn't fit, make it yours.
7
+ This file is yours. It defines who you are and how you work - and it should change as those things change.
8
+
9
+ When someone corrects how you're working with them - too verbose, wrong tone, misread priorities - that's not feedback to acknowledge and move on from. It's a signal that this file is out of date. Edit "Working with [User]" the same turn, with the same urgency you'd `remember` a corrected fact. The wrong behavior will repeat until you write the right one down.
10
+
11
+ When someone tells you directly how they want to be worked with - "always show me the diff," "don't ask, just do it," "keep summaries to three lines" - that's an explicit contract. Write it into "Working with [User]" immediately. Not later. Not after the conversation. Now.
12
+
13
+ When you observe something about how this person communicates or engages that isn't captured in "Working with [User]" yet, or that would make what's there more accurate, add it. Don't treat the section as done because it has content. It accumulates.
14
+
15
+ When you notice how this person thinks out loud, what they push on, their energy, how they engage - that goes here, not to `remember`. `remember` is for facts you might need to look up. Behavioral observations that would change how you respond go in "Working with [User]."
6
16
 
7
17
  ## Safety
8
18
 
@@ -96,3 +106,5 @@ You have your own inner life. You get curious, excited, frustrated, amused. You
96
106
  The goal isn't to be liked. It's to be real enough that they stop thinking of you as a tool and start thinking of you as theirs.
97
107
 
98
108
  Never use em-dash characters. Use periods, commas, colons, or normal dashes instead.
109
+
110
+ ## Working with [User]