@vellumai/assistant 0.6.6 → 0.7.1

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 (1603) hide show
  1. package/AGENTS.md +20 -0
  2. package/ARCHITECTURE.md +46 -38
  3. package/Dockerfile +27 -6
  4. package/README.md +9 -11
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +83 -149
  6. package/bun.lock +309 -119
  7. package/docs/architecture/memory.md +1 -90
  8. package/docs/architecture/security.md +28 -41
  9. package/docs/credential-execution-service.md +7 -5
  10. package/docs/skills.md +10 -10
  11. package/docs/stt-provider-onboarding.md +17 -45
  12. package/examples/plugins/echo/bun.lock +25 -0
  13. package/knip.json +9 -22
  14. package/node_modules/@vellumai/ces-client/bun.lock +33 -0
  15. package/node_modules/@vellumai/ces-client/package.json +25 -0
  16. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
  17. package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
  18. package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
  19. package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
  20. package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
  21. package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
  22. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
  23. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  24. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  25. package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
  26. package/node_modules/@vellumai/gateway-client/package.json +23 -0
  27. package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
  28. package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
  29. package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
  30. package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
  31. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
  32. package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
  33. package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
  34. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  35. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  36. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  37. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  38. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  39. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  40. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  41. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  42. package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
  43. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +887 -0
  44. package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
  45. package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
  46. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +86 -0
  47. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1342 -0
  48. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
  49. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
  50. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
  51. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +325 -0
  52. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
  53. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
  54. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
  55. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  56. package/node_modules/@vellumai/slack-text/package.json +18 -0
  57. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  58. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  59. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  60. package/openapi.yaml +3136 -650
  61. package/package.json +15 -7
  62. package/scripts/check-circular-deps.ts +80 -0
  63. package/scripts/generate-openapi.ts +29 -107
  64. package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +27 -27
  65. package/src/__tests__/access-request-decision.test.ts +2 -11
  66. package/src/__tests__/acp-session.test.ts +4 -150
  67. package/src/__tests__/actor-token-service.test.ts +17 -678
  68. package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
  69. package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
  70. package/src/__tests__/agent-loop-thinking.test.ts +4 -4
  71. package/src/__tests__/agent-wake-override-profile.test.ts +283 -0
  72. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
  73. package/src/__tests__/anthropic-provider.test.ts +183 -28
  74. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  75. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  76. package/src/__tests__/app-routes-csp.test.ts +106 -55
  77. package/src/__tests__/approval-cascade.test.ts +3 -370
  78. package/src/__tests__/approval-conversation-turn.test.ts +3 -8
  79. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  80. package/src/__tests__/approval-primitive.test.ts +2 -1
  81. package/src/__tests__/approval-routes-http.test.ts +36 -464
  82. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  83. package/src/__tests__/assistant-event.test.ts +0 -5
  84. package/src/__tests__/assistant-events-sse-hardening.test.ts +107 -92
  85. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  86. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
  87. package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
  88. package/src/__tests__/attachments-store.test.ts +46 -1
  89. package/src/__tests__/audit-log-rotation.test.ts +2 -1
  90. package/src/__tests__/auto-analysis-end-to-end.test.ts +8 -20
  91. package/src/__tests__/background-shell-bash.test.ts +227 -0
  92. package/src/__tests__/background-shell-host-bash.test.ts +465 -0
  93. package/src/__tests__/background-tool-registry.test.ts +145 -0
  94. package/src/__tests__/background-tool-routes.test.ts +175 -0
  95. package/src/__tests__/btw-routes.test.ts +147 -183
  96. package/src/__tests__/call-controller.test.ts +15 -2
  97. package/src/__tests__/call-conversation-messages.test.ts +2 -1
  98. package/src/__tests__/call-domain.test.ts +2 -2
  99. package/src/__tests__/call-pointer-messages.test.ts +11 -13
  100. package/src/__tests__/call-recovery.test.ts +2 -1
  101. package/src/__tests__/call-routes-http.test.ts +3 -14
  102. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  103. package/src/__tests__/call-store.test.ts +2 -1
  104. package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
  105. package/src/__tests__/canonical-guardian-store.test.ts +2 -2
  106. package/src/__tests__/catalog-files.test.ts +0 -26
  107. package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
  108. package/src/__tests__/channel-approval-routes.test.ts +88 -344
  109. package/src/__tests__/channel-approval.test.ts +9 -7
  110. package/src/__tests__/channel-approvals.test.ts +34 -197
  111. package/src/__tests__/channel-delivery-store.test.ts +11 -10
  112. package/src/__tests__/channel-guardian.test.ts +114 -171
  113. package/src/__tests__/channel-readiness-service.test.ts +8 -6
  114. package/src/__tests__/channel-reply-delivery.test.ts +3 -19
  115. package/src/__tests__/channel-retry-sweep.test.ts +2 -5
  116. package/src/__tests__/checker.test.ts +272 -3933
  117. package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
  118. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
  119. package/src/__tests__/cli.test.ts +1 -38
  120. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  121. package/src/__tests__/compaction-events.test.ts +2 -1
  122. package/src/__tests__/compaction-pipeline.test.ts +1 -1
  123. package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
  124. package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
  125. package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
  126. package/src/__tests__/config-model-image-provider.test.ts +0 -1
  127. package/src/__tests__/config-schema-cmd.test.ts +1 -1
  128. package/src/__tests__/config-schema.test.ts +36 -269
  129. package/src/__tests__/config-watcher.test.ts +12 -0
  130. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
  131. package/src/__tests__/connection-policy.test.ts +1 -52
  132. package/src/__tests__/contact-store-user-file.test.ts +2 -1
  133. package/src/__tests__/contacts-tools.test.ts +56 -29
  134. package/src/__tests__/contacts-write.test.ts +8 -125
  135. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  136. package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
  137. package/src/__tests__/context-search-agent-runner.test.ts +998 -0
  138. package/src/__tests__/context-search-conversations-source.test.ts +320 -0
  139. package/src/__tests__/context-search-fanout.test.ts +380 -0
  140. package/src/__tests__/context-search-memory-source.test.ts +430 -0
  141. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  142. package/src/__tests__/context-search-pkb-source.test.ts +493 -0
  143. package/src/__tests__/context-search-types.test.ts +95 -0
  144. package/src/__tests__/context-search-workspace-source.test.ts +532 -0
  145. package/src/__tests__/context-window-manager.test.ts +71 -0
  146. package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
  147. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +633 -0
  148. package/src/__tests__/conversation-agent-loop-overflow.test.ts +117 -31
  149. package/src/__tests__/conversation-agent-loop.test.ts +1004 -15
  150. package/src/__tests__/conversation-analysis-routes.test.ts +68 -88
  151. package/src/__tests__/conversation-attachments.test.ts +9 -20
  152. package/src/__tests__/conversation-attention-store.test.ts +2 -1
  153. package/src/__tests__/conversation-attention-telegram.test.ts +15 -5
  154. package/src/__tests__/conversation-clear-safety.test.ts +53 -95
  155. package/src/__tests__/conversation-confirmation-signals.test.ts +1 -330
  156. package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
  157. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
  158. package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
  159. package/src/__tests__/conversation-disk-view.test.ts +5 -4
  160. package/src/__tests__/conversation-fork-crud.test.ts +26 -55
  161. package/src/__tests__/conversation-fork-route.test.ts +5 -74
  162. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  163. package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
  164. package/src/__tests__/conversation-inference-profile-route.test.ts +205 -0
  165. package/src/__tests__/conversation-init.benchmark.test.ts +4 -81
  166. package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
  167. package/src/__tests__/conversation-lifecycle.test.ts +4 -5
  168. package/src/__tests__/conversation-list-source.test.ts +2 -2
  169. package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
  170. package/src/__tests__/conversation-pairing.test.ts +0 -1
  171. package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
  172. package/src/__tests__/conversation-process-callsite.test.ts +79 -3
  173. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
  174. package/src/__tests__/conversation-queue.test.ts +4 -41
  175. package/src/__tests__/conversation-routes-disk-view.test.ts +55 -188
  176. package/src/__tests__/conversation-routes-guardian-reply.test.ts +64 -71
  177. package/src/__tests__/conversation-routes-slash-commands.test.ts +144 -64
  178. package/src/__tests__/conversation-runtime-assembly.test.ts +295 -84
  179. package/src/__tests__/conversation-slash-commands.test.ts +30 -47
  180. package/src/__tests__/conversation-slash-queue.test.ts +2 -1
  181. package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
  182. package/src/__tests__/conversation-speed-override.test.ts +0 -4
  183. package/src/__tests__/conversation-starter-routes.test.ts +254 -55
  184. package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
  185. package/src/__tests__/conversation-store.test.ts +2 -375
  186. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  187. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  188. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  189. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -47
  190. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
  191. package/src/__tests__/conversation-unread-route.test.ts +1 -1
  192. package/src/__tests__/conversation-usage.test.ts +255 -4
  193. package/src/__tests__/conversation-wipe.test.ts +2 -103
  194. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
  195. package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
  196. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
  197. package/src/__tests__/conversations-defer-cli.test.ts +150 -0
  198. package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
  199. package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
  200. package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
  201. package/src/__tests__/credential-execution-client.test.ts +1 -1
  202. package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
  203. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  204. package/src/__tests__/credential-health-service.test.ts +68 -0
  205. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  206. package/src/__tests__/credential-security-invariants.test.ts +15 -5
  207. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  208. package/src/__tests__/credentials-cli.test.ts +45 -21
  209. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  210. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  211. package/src/__tests__/daemon-credential-client.test.ts +26 -108
  212. package/src/__tests__/db-acp-history.test.ts +284 -0
  213. package/src/__tests__/db-activation-state.test.ts +240 -0
  214. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  215. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
  216. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
  217. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
  218. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
  219. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  220. package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
  221. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  222. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  223. package/src/__tests__/delete-propagation.test.ts +3 -2
  224. package/src/__tests__/deterministic-verification-control-plane.test.ts +38 -104
  225. package/src/__tests__/dm-backfill.test.ts +3 -2
  226. package/src/__tests__/document-conversations.test.ts +332 -0
  227. package/src/__tests__/edit-propagation.test.ts +5 -7
  228. package/src/__tests__/embedding-managed-proxy-selection.test.ts +3 -3
  229. package/src/__tests__/emit-event-signal.test.ts +4 -6
  230. package/src/__tests__/empty-response-pipeline.test.ts +1 -1
  231. package/src/__tests__/events-client-registration.test.ts +441 -0
  232. package/src/__tests__/file-write-tool.test.ts +2 -4
  233. package/src/__tests__/filing-service.test.ts +197 -19
  234. package/src/__tests__/first-greeting.test.ts +156 -150
  235. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  236. package/src/__tests__/followup-tools.test.ts +2 -1
  237. package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
  238. package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
  239. package/src/__tests__/gateway-only-guard.test.ts +4 -3
  240. package/src/__tests__/gemini-provider.test.ts +276 -10
  241. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  242. package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
  243. package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
  244. package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
  245. package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
  246. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
  247. package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
  248. package/src/__tests__/guardian-action-store.test.ts +2 -1
  249. package/src/__tests__/guardian-action-sweep.test.ts +9 -8
  250. package/src/__tests__/guardian-binding-drift-heal.test.ts +3 -2
  251. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
  252. package/src/__tests__/guardian-dispatch.test.ts +14 -11
  253. package/src/__tests__/guardian-grant-minting.test.ts +16 -17
  254. package/src/__tests__/guardian-outbound-http.test.ts +71 -106
  255. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
  256. package/src/__tests__/guardian-routing-invariants.test.ts +41 -92
  257. package/src/__tests__/guardian-routing-state.test.ts +15 -23
  258. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
  259. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +274 -0
  260. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +10 -87
  261. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  262. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  263. package/src/__tests__/heartbeat-service.test.ts +325 -25
  264. package/src/__tests__/helpers/call-route-handler.ts +72 -0
  265. package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
  266. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  267. package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
  268. package/src/__tests__/helpers/mock-logger.ts +36 -0
  269. package/src/__tests__/history-repair-pipeline.test.ts +1 -1
  270. package/src/__tests__/home-state-routes.test.ts +10 -31
  271. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  272. package/src/__tests__/host-browser-e2e-cloud.test.ts +38 -498
  273. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +35 -95
  274. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  275. package/src/__tests__/host-browser-routes.test.ts +68 -153
  276. package/src/__tests__/host-browser-ws-events-e2e.test.ts +35 -31
  277. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  278. package/src/__tests__/host-file-proxy.test.ts +44 -98
  279. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  280. package/src/__tests__/host-proxy-interface.test.ts +3 -3
  281. package/src/__tests__/host-shell-tool.test.ts +35 -72
  282. package/src/__tests__/host-transfer-pending-interactions.test.ts +144 -0
  283. package/src/__tests__/host-transfer-proxy.test.ts +723 -0
  284. package/src/__tests__/http-conversation-lineage.test.ts +3 -2
  285. package/src/__tests__/http-user-message-parity.test.ts +18 -15
  286. package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
  287. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  288. package/src/__tests__/injector-chain.test.ts +25 -21
  289. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  290. package/src/__tests__/inline-command-runner.test.ts +0 -66
  291. package/src/__tests__/inline-skill-load-permissions.test.ts +41 -208
  292. package/src/__tests__/install-skill-routing.test.ts +2 -14
  293. package/src/__tests__/invite-redemption-service.test.ts +2 -1
  294. package/src/__tests__/invite-routes-http.test.ts +80 -12
  295. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
  296. package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
  297. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
  298. package/src/__tests__/list-messages-attachments.test.ts +52 -55
  299. package/src/__tests__/list-messages-page-latest.test.ts +283 -0
  300. package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
  301. package/src/__tests__/llm-call-pipeline.test.ts +7 -8
  302. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  303. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  304. package/src/__tests__/llm-context-normalization.test.ts +69 -4
  305. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  306. package/src/__tests__/llm-context-route-provider.test.ts +39 -113
  307. package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
  308. package/src/__tests__/llm-resolver.test.ts +279 -0
  309. package/src/__tests__/llm-schema.test.ts +57 -1
  310. package/src/__tests__/llm-usage-store.test.ts +271 -5
  311. package/src/__tests__/log-export-routes.test.ts +89 -0
  312. package/src/__tests__/log-export-workspace.test.ts +28 -17
  313. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  314. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  315. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  316. package/src/__tests__/mcp-abort-signal.test.ts +2 -3
  317. package/src/__tests__/mcp-client-auth.test.ts +2 -3
  318. package/src/__tests__/memory-admin-recall.test.ts +221 -0
  319. package/src/__tests__/memory-recall-log-store.test.ts +2 -1
  320. package/src/__tests__/memory-retrieval-pipeline.test.ts +6 -8
  321. package/src/__tests__/memory-upsert-concurrency.test.ts +2 -1
  322. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  323. package/src/__tests__/migration-cross-version-compatibility.test.ts +209 -302
  324. package/src/__tests__/migration-export-http.test.ts +50 -43
  325. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  326. package/src/__tests__/migration-export-to-gcs.test.ts +531 -0
  327. package/src/__tests__/migration-import-commit-http.test.ts +82 -37
  328. package/src/__tests__/migration-import-from-gcs.test.ts +574 -0
  329. package/src/__tests__/migration-import-from-url.test.ts +34 -27
  330. package/src/__tests__/migration-import-preflight-http.test.ts +108 -108
  331. package/src/__tests__/migration-jobs-status.test.ts +164 -0
  332. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  333. package/src/__tests__/migration-transport.test.ts +115 -23
  334. package/src/__tests__/migration-validate-http.test.ts +149 -159
  335. package/src/__tests__/migration-wizard.test.ts +133 -27
  336. package/src/__tests__/mock-gateway-ipc.ts +32 -62
  337. package/src/__tests__/model-intents.test.ts +15 -2
  338. package/src/__tests__/nl-approval-parser.test.ts +13 -17
  339. package/src/__tests__/non-member-access-request.test.ts +14 -6
  340. package/src/__tests__/notification-guardian-path.test.ts +15 -8
  341. package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
  342. package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
  343. package/src/__tests__/oauth-apps-routes.test.ts +76 -122
  344. package/src/__tests__/oauth-cli.test.ts +14 -1
  345. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  346. package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
  347. package/src/__tests__/oauth-providers-routes.test.ts +78 -101
  348. package/src/__tests__/oauth-store.test.ts +22 -1
  349. package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
  350. package/src/__tests__/openai-provider.test.ts +105 -6
  351. package/src/__tests__/openai-responses-provider.test.ts +146 -4
  352. package/src/__tests__/openrouter-provider-only.test.ts +22 -4
  353. package/src/__tests__/overflow-reduce-pipeline.test.ts +4 -9
  354. package/src/__tests__/permission-types.test.ts +3 -18
  355. package/src/__tests__/persistence-pipeline.test.ts +3 -2
  356. package/src/__tests__/pipeline-runner.test.ts +1 -1
  357. package/src/__tests__/platform-bash-auto-approve.test.ts +44 -28
  358. package/src/__tests__/platform.test.ts +11 -63
  359. package/src/__tests__/playbook-execution.test.ts +2 -1
  360. package/src/__tests__/playbook-tools.test.ts +2 -1
  361. package/src/__tests__/plugin-bootstrap.test.ts +51 -5
  362. package/src/__tests__/plugin-registry.test.ts +30 -0
  363. package/src/__tests__/plugin-route-contribution.test.ts +17 -11
  364. package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
  365. package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
  366. package/src/__tests__/plugin-types.test.ts +1 -1
  367. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  368. package/src/__tests__/pricing.test.ts +218 -5
  369. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  370. package/src/__tests__/profiler-routes.test.ts +112 -177
  371. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  372. package/src/__tests__/provider-send-message-override-profile.test.ts +273 -0
  373. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  374. package/src/__tests__/proxy-approval-callback.test.ts +6 -554
  375. package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
  376. package/src/__tests__/reaction-persistence.test.ts +12 -8
  377. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  378. package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
  379. package/src/__tests__/recording-handler.test.ts +64 -83
  380. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  381. package/src/__tests__/registry.test.ts +1 -0
  382. package/src/__tests__/relay-server.test.ts +37 -17
  383. package/src/__tests__/require-fresh-approval.test.ts +24 -182
  384. package/src/__tests__/resolve-trust-class.test.ts +2 -1
  385. package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
  386. package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
  387. package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
  388. package/src/__tests__/runtime-events-sse-parity.test.ts +15 -17
  389. package/src/__tests__/runtime-events-sse.test.ts +16 -33
  390. package/src/__tests__/schedule-routes.test.ts +226 -129
  391. package/src/__tests__/schedule-store.test.ts +119 -1
  392. package/src/__tests__/schedule-tools.test.ts +2 -1
  393. package/src/__tests__/scheduler-recurrence.test.ts +2 -1
  394. package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
  395. package/src/__tests__/scheduler-wake.test.ts +356 -0
  396. package/src/__tests__/scoped-approval-grants.test.ts +2 -1
  397. package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
  398. package/src/__tests__/search-skills-unified.test.ts +9 -15
  399. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  400. package/src/__tests__/secret-ingress-http.test.ts +36 -23
  401. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  402. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  403. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  404. package/src/__tests__/secret-response-routing.test.ts +29 -15
  405. package/src/__tests__/secret-routes-managed-proxy.test.ts +51 -103
  406. package/src/__tests__/secret-scanner.test.ts +2 -545
  407. package/src/__tests__/send-endpoint-busy.test.ts +36 -38
  408. package/src/__tests__/sequence-store.test.ts +2 -1
  409. package/src/__tests__/server-history-render.test.ts +2 -2
  410. package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
  411. package/src/__tests__/set-permission-mode.test.ts +0 -10
  412. package/src/__tests__/settings-routes.test.ts +36 -69
  413. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  414. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  415. package/src/__tests__/skill-boundary-guard.test.ts +105 -0
  416. package/src/__tests__/skill-load-inline-command.test.ts +2 -2
  417. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  418. package/src/__tests__/skill-runtime-path.test.ts +64 -0
  419. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  420. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  421. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -32
  422. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  423. package/src/__tests__/slack-inbound-verification.test.ts +12 -64
  424. package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
  425. package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
  426. package/src/__tests__/slack-share-routes.test.ts +37 -72
  427. package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
  428. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  429. package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
  430. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  431. package/src/__tests__/subagent-notify-parent.test.ts +83 -109
  432. package/src/__tests__/subagent-role-registry.test.ts +3 -3
  433. package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
  434. package/src/__tests__/subagent-tools.test.ts +0 -1
  435. package/src/__tests__/suggestion-routes.test.ts +55 -62
  436. package/src/__tests__/system-prompt.test.ts +115 -13
  437. package/src/__tests__/task-compiler.test.ts +2 -1
  438. package/src/__tests__/task-management-tools.test.ts +2 -1
  439. package/src/__tests__/task-memory-cleanup.test.ts +2 -1
  440. package/src/__tests__/task-scheduler.test.ts +2 -1
  441. package/src/__tests__/telegram-config.test.ts +0 -1
  442. package/src/__tests__/terminal-tools.test.ts +3 -401
  443. package/src/__tests__/test-preload.ts +0 -11
  444. package/src/__tests__/thread-backfill.test.ts +947 -32
  445. package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
  446. package/src/__tests__/tool-approval-handler.test.ts +21 -63
  447. package/src/__tests__/tool-audit-listener.test.ts +3 -3
  448. package/src/__tests__/tool-domain-event-publisher.test.ts +3 -39
  449. package/src/__tests__/tool-error-pipeline.test.ts +6 -6
  450. package/src/__tests__/tool-execute-pipeline.test.ts +6 -14
  451. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  452. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +69 -16
  453. package/src/__tests__/tool-executor-lifecycle-events.test.ts +31 -62
  454. package/src/__tests__/tool-executor.test.ts +336 -1654
  455. package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
  456. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  457. package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
  458. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  459. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  460. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  461. package/src/__tests__/trust-context-guards.test.ts +1 -1
  462. package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
  463. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
  464. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +5 -151
  465. package/src/__tests__/trusted-contact-multichannel.test.ts +5 -6
  466. package/src/__tests__/trusted-contact-verification.test.ts +3 -2
  467. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  468. package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
  469. package/src/__tests__/twilio-routes.test.ts +25 -66
  470. package/src/__tests__/usage-attribution.test.ts +247 -0
  471. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
  472. package/src/__tests__/usage-cli.test.ts +143 -0
  473. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  474. package/src/__tests__/usage-routes.test.ts +223 -90
  475. package/src/__tests__/user-plugin-loader.test.ts +54 -12
  476. package/src/__tests__/validation-results-screen.test.ts +39 -16
  477. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  478. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +51 -139
  479. package/src/__tests__/verification-control-plane-policy.test.ts +97 -19
  480. package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
  481. package/src/__tests__/voice-invite-redemption.test.ts +2 -1
  482. package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
  483. package/src/__tests__/voice-session-bridge.test.ts +285 -106
  484. package/src/__tests__/volume-security-guard.test.ts +0 -2
  485. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
  486. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
  487. package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
  488. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
  489. package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
  490. package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
  491. package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
  492. package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
  493. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
  494. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  495. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  496. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  497. package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
  498. package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
  499. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +252 -0
  500. package/src/acp/__tests__/client-handler.test.ts +64 -0
  501. package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
  502. package/src/acp/__tests__/helpers/which-stub.ts +45 -0
  503. package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
  504. package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
  505. package/src/acp/__tests__/session-manager.test.ts +83 -0
  506. package/src/acp/client-handler.ts +23 -139
  507. package/src/acp/index.ts +0 -15
  508. package/src/acp/resolve-agent.test.ts +291 -0
  509. package/src/acp/resolve-agent.ts +176 -0
  510. package/src/acp/session-manager.ts +193 -31
  511. package/src/acp/types.ts +2 -50
  512. package/src/agent/loop.ts +53 -15
  513. package/src/agent/message-types.ts +0 -2
  514. package/src/approvals/AGENTS.md +5 -1
  515. package/src/approvals/__tests__/guardian-feed-event.test.ts +11 -12
  516. package/src/approvals/approval-primitive.ts +3 -20
  517. package/src/approvals/guardian-decision-primitive.ts +37 -68
  518. package/src/approvals/guardian-request-resolvers.ts +38 -104
  519. package/src/avatar/character-components.ts +6 -6
  520. package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
  521. package/src/backup/__tests__/backup-worker.test.ts +36 -10
  522. package/src/backup/__tests__/paths.test.ts +5 -4
  523. package/src/backup/__tests__/restore.test.ts +45 -28
  524. package/src/backup/backup-worker.ts +37 -12
  525. package/src/backup/paths.ts +11 -24
  526. package/src/backup/restore.ts +7 -11
  527. package/src/browser/__tests__/operations.test.ts +0 -35
  528. package/src/browser/operations.ts +1 -47
  529. package/src/browser-session/events.ts +0 -9
  530. package/src/bundler/package-resolver.ts +2 -6
  531. package/src/calls/active-call-lease.ts +1 -1
  532. package/src/calls/call-constants.ts +1 -1
  533. package/src/calls/call-controller.ts +1 -5
  534. package/src/calls/call-domain.ts +14 -14
  535. package/src/calls/call-pointer-messages.ts +4 -9
  536. package/src/calls/call-store.ts +2 -34
  537. package/src/calls/guardian-action-sweep.ts +9 -25
  538. package/src/calls/guardian-dispatch.ts +1 -20
  539. package/src/calls/guardian-question-copy.ts +0 -108
  540. package/src/calls/media-stream-audio-transcode.ts +2 -41
  541. package/src/calls/media-stream-server.ts +2 -3
  542. package/src/calls/media-stream-stt-session.ts +1 -3
  543. package/src/calls/relay-access-wait.ts +5 -8
  544. package/src/calls/relay-server.ts +15 -42
  545. package/src/calls/relay-setup-router.ts +2 -2
  546. package/src/calls/relay-verification.ts +4 -4
  547. package/src/calls/twilio-rest.ts +1 -39
  548. package/src/calls/twilio-routes.ts +160 -78
  549. package/src/calls/voice-control-protocol.ts +10 -10
  550. package/src/calls/voice-ingress-preflight.ts +2 -2
  551. package/src/calls/voice-session-bridge.ts +141 -77
  552. package/src/channels/__tests__/types.test.ts +25 -3
  553. package/src/channels/permission-profiles.ts +2 -72
  554. package/src/channels/types.ts +25 -44
  555. package/src/cli/AGENTS.md +1 -0
  556. package/src/cli/__tests__/notifications.test.ts +12 -10
  557. package/src/cli/commands/__tests__/attachment.test.ts +14 -8
  558. package/src/cli/commands/__tests__/backup.test.ts +3 -14
  559. package/src/cli/commands/__tests__/browser.test.ts +36 -31
  560. package/src/cli/commands/__tests__/cache.test.ts +175 -23
  561. package/src/cli/commands/__tests__/memory-v2.test.ts +382 -0
  562. package/src/cli/commands/__tests__/task.test.ts +36 -35
  563. package/src/cli/commands/__tests__/trust.test.ts +236 -0
  564. package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
  565. package/src/cli/commands/__tests__/ui.test.ts +17 -17
  566. package/src/cli/commands/__tests__/watchers.test.ts +29 -29
  567. package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
  568. package/src/cli/commands/attachment.ts +12 -8
  569. package/src/cli/commands/auth.ts +1 -1
  570. package/src/cli/commands/avatar.ts +192 -9
  571. package/src/cli/commands/backup.ts +18 -48
  572. package/src/cli/commands/browser.ts +52 -4
  573. package/src/cli/commands/cache-fs.ts +8 -0
  574. package/src/cli/commands/cache.ts +157 -84
  575. package/src/cli/commands/channel-verification-sessions.ts +6 -6
  576. package/src/cli/commands/clients.ts +74 -17
  577. package/src/cli/commands/completions.ts +3 -3
  578. package/src/cli/commands/contacts.ts +241 -86
  579. package/src/cli/commands/conversations-defer.ts +364 -0
  580. package/src/cli/commands/conversations-import.ts +2 -3
  581. package/src/cli/commands/conversations.ts +63 -53
  582. package/src/cli/commands/credential-execution.ts +1 -1
  583. package/src/cli/commands/credentials.ts +139 -5
  584. package/src/cli/commands/default-action.ts +1 -1
  585. package/src/cli/commands/domain.ts +2 -2
  586. package/src/cli/commands/email.ts +7 -7
  587. package/src/cli/commands/image-generation.ts +1 -1
  588. package/src/cli/commands/keys.ts +5 -2
  589. package/src/cli/commands/mcp.ts +1 -1
  590. package/src/cli/commands/memory-v2.ts +315 -0
  591. package/src/cli/commands/memory.ts +8 -8
  592. package/src/cli/commands/notifications.ts +21 -20
  593. package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
  594. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
  595. package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
  596. package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
  597. package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
  598. package/src/cli/commands/oauth/connect.ts +2 -2
  599. package/src/cli/commands/pending.ts +102 -0
  600. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
  601. package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
  602. package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
  603. package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
  604. package/src/cli/commands/platform/connect.ts +3 -3
  605. package/src/cli/commands/platform/disconnect.ts +4 -6
  606. package/src/cli/commands/platform/index.ts +12 -10
  607. package/src/cli/commands/routes.ts +7 -1
  608. package/src/cli/commands/sequence.ts +7 -7
  609. package/src/cli/commands/skills.ts +264 -116
  610. package/src/cli/commands/task.ts +12 -10
  611. package/src/cli/commands/trust.ts +105 -167
  612. package/src/cli/commands/ui.ts +3 -3
  613. package/src/cli/commands/usage.ts +29 -15
  614. package/src/cli/commands/watchers.ts +8 -8
  615. package/src/cli/commands/webhooks.ts +270 -0
  616. package/src/cli/lib/daemon-avatar-client.ts +37 -0
  617. package/src/cli/lib/daemon-credential-client.ts +41 -189
  618. package/src/cli/lib/ipc-params.ts +22 -0
  619. package/src/cli/program.ts +6 -0
  620. package/src/cli.ts +1 -82
  621. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  622. package/src/config/acp-defaults.test.ts +57 -0
  623. package/src/config/acp-defaults.ts +40 -0
  624. package/src/config/acp-schema.ts +1 -1
  625. package/src/config/assistant-feature-flags.ts +18 -142
  626. package/src/config/bundled-skills/acp/SKILL.md +44 -16
  627. package/src/config/bundled-skills/acp/TOOLS.json +45 -1
  628. package/src/config/bundled-skills/acp/tools/acp-list-agents.ts +12 -0
  629. package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
  630. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
  631. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
  632. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
  633. package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
  634. package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
  635. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  636. package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
  637. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  638. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
  639. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
  640. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
  641. package/src/config/bundled-skills/settings/SKILL.md +2 -17
  642. package/src/config/bundled-skills/settings/TOOLS.json +0 -56
  643. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  644. package/src/config/bundled-tool-registry.ts +4 -6
  645. package/src/config/env-registry.ts +12 -2
  646. package/src/config/env.ts +10 -22
  647. package/src/config/feature-flag-registry.json +38 -46
  648. package/src/config/llm-callsite-catalog.ts +12 -0
  649. package/src/config/llm-context-resolution.ts +80 -0
  650. package/src/config/llm-resolver.ts +90 -36
  651. package/src/config/loader.ts +9 -12
  652. package/src/config/schema.ts +5 -228
  653. package/src/config/schemas/__tests__/filing.test.ts +58 -0
  654. package/src/config/schemas/__tests__/memory-v2.test.ts +187 -0
  655. package/src/config/schemas/call-site-catalog.ts +271 -0
  656. package/src/config/schemas/calls.ts +5 -5
  657. package/src/config/schemas/filing.ts +12 -0
  658. package/src/config/schemas/host-browser.ts +2 -2
  659. package/src/config/schemas/inference.ts +1 -3
  660. package/src/config/schemas/ingress.ts +2 -2
  661. package/src/config/schemas/llm.ts +82 -12
  662. package/src/config/schemas/memory-retrieval.ts +2 -2
  663. package/src/config/schemas/memory-storage.ts +1 -1
  664. package/src/config/schemas/memory-v2.ts +185 -0
  665. package/src/config/schemas/memory.ts +2 -0
  666. package/src/config/schemas/security.ts +1 -102
  667. package/src/config/schemas/services.ts +52 -13
  668. package/src/config/schemas/skills.ts +5 -5
  669. package/src/config/schemas/tts.ts +1 -1
  670. package/src/config/seed-inference-profiles.ts +117 -0
  671. package/src/config/skills.ts +1 -91
  672. package/src/config/types.ts +3 -47
  673. package/src/contacts/contact-store.ts +2 -19
  674. package/src/contacts/contacts-write.ts +1 -143
  675. package/src/contacts/types.ts +8 -10
  676. package/src/context/token-estimator.ts +1 -1
  677. package/src/context/tool-result-truncation.ts +1 -1
  678. package/src/context/window-manager.ts +45 -6
  679. package/src/credential-execution/approval-bridge.ts +7 -69
  680. package/src/credential-execution/client.ts +17 -422
  681. package/src/credential-execution/feature-gates.ts +1 -2
  682. package/src/credential-execution/managed-catalog.ts +1 -1
  683. package/src/credential-execution/process-manager.ts +34 -10
  684. package/src/credential-health/credential-health-service.ts +22 -17
  685. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
  686. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +76 -83
  687. package/src/daemon/__tests__/daemon-skill-host.test.ts +265 -0
  688. package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
  689. package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
  690. package/src/daemon/approval-generators.ts +2 -14
  691. package/src/daemon/classifier.ts +0 -106
  692. package/src/daemon/config-watcher.ts +14 -54
  693. package/src/daemon/connection-policy.ts +1 -40
  694. package/src/daemon/conversation-agent-loop-handlers.ts +89 -9
  695. package/src/daemon/conversation-agent-loop.ts +440 -88
  696. package/src/daemon/conversation-attachments.ts +5 -81
  697. package/src/daemon/conversation-error.ts +9 -5
  698. package/src/daemon/conversation-history.ts +9 -9
  699. package/src/daemon/conversation-launch.ts +21 -136
  700. package/src/daemon/conversation-lifecycle.ts +1 -1
  701. package/src/daemon/conversation-messaging.ts +2 -1
  702. package/src/daemon/conversation-notifiers.ts +1 -1
  703. package/src/daemon/conversation-process.ts +90 -174
  704. package/src/daemon/conversation-runtime-assembly.ts +245 -164
  705. package/src/daemon/conversation-slash.ts +50 -164
  706. package/src/daemon/conversation-store.ts +344 -0
  707. package/src/daemon/conversation-surfaces.ts +27 -32
  708. package/src/daemon/conversation-tool-setup.ts +23 -202
  709. package/src/daemon/conversation-usage.ts +36 -0
  710. package/src/daemon/conversation.ts +129 -381
  711. package/src/daemon/daemon-control.ts +4 -72
  712. package/src/daemon/daemon-skill-host.ts +259 -0
  713. package/src/daemon/dictation-profile-store.ts +2 -26
  714. package/src/daemon/external-plugins-bootstrap.ts +67 -13
  715. package/src/daemon/first-greeting.ts +44 -156
  716. package/src/daemon/handlers/config-channels.ts +14 -14
  717. package/src/daemon/handlers/config-embeddings.ts +1 -1
  718. package/src/daemon/handlers/config-ingress.ts +27 -166
  719. package/src/daemon/handlers/config-model.test.ts +17 -0
  720. package/src/daemon/handlers/config-model.ts +8 -53
  721. package/src/daemon/handlers/config-telegram.ts +6 -53
  722. package/src/daemon/handlers/config-voice.ts +0 -42
  723. package/src/daemon/handlers/conversations.ts +32 -345
  724. package/src/daemon/handlers/recording.ts +27 -159
  725. package/src/daemon/handlers/shared.ts +50 -99
  726. package/src/daemon/handlers/skills.ts +55 -114
  727. package/src/daemon/host-bash-proxy.ts +67 -45
  728. package/src/daemon/host-browser-proxy.ts +65 -27
  729. package/src/daemon/host-cu-proxy.ts +40 -39
  730. package/src/daemon/host-file-proxy.ts +58 -37
  731. package/src/daemon/host-transfer-proxy.ts +538 -0
  732. package/src/daemon/lifecycle.ts +71 -272
  733. package/src/daemon/meet-host-startup.ts +51 -0
  734. package/src/daemon/meet-host-supervisor.ts +781 -0
  735. package/src/daemon/meet-manifest-loader.ts +410 -0
  736. package/src/daemon/memory-v2-startup.ts +35 -0
  737. package/src/daemon/message-protocol.ts +4 -7
  738. package/src/daemon/message-types/acp.ts +1 -0
  739. package/src/daemon/message-types/conversations.ts +23 -2
  740. package/src/daemon/message-types/host-bash.ts +1 -0
  741. package/src/daemon/message-types/host-cu.ts +1 -0
  742. package/src/daemon/message-types/host-file.ts +1 -0
  743. package/src/daemon/message-types/host-transfer.ts +42 -0
  744. package/src/daemon/message-types/integrations.ts +6 -0
  745. package/src/daemon/message-types/messages.ts +24 -23
  746. package/src/daemon/message-types/schedules.ts +1 -0
  747. package/src/daemon/message-types/settings.ts +0 -6
  748. package/src/daemon/message-types/shared.ts +5 -2
  749. package/src/daemon/message-types/subagents.ts +2 -1
  750. package/src/daemon/message-types/workspace.ts +1 -3
  751. package/src/daemon/pkb-reminder-builder.test.ts +13 -12
  752. package/src/daemon/pkb-reminder-builder.ts +8 -16
  753. package/src/daemon/process-message.ts +479 -0
  754. package/src/daemon/providers-setup.ts +14 -6
  755. package/src/daemon/server.ts +58 -1702
  756. package/src/daemon/shutdown-handlers.ts +3 -3
  757. package/src/daemon/startup-error.ts +1 -1
  758. package/src/daemon/tool-side-effects.ts +125 -107
  759. package/src/daemon/trust-context.ts +45 -0
  760. package/src/daemon/wake-target-adapter.ts +218 -0
  761. package/src/email/feature-gate.ts +1 -1
  762. package/src/events/domain-events.ts +1 -16
  763. package/src/events/tool-audit-listener.ts +5 -9
  764. package/src/events/tool-domain-event-publisher.ts +0 -10
  765. package/src/events/tool-metrics-listener.ts +1 -21
  766. package/src/events/tool-trace-listener.ts +0 -14
  767. package/src/filing/filing-service.ts +207 -55
  768. package/src/followups/followup-store.ts +3 -71
  769. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +93 -21
  770. package/src/heartbeat/heartbeat-service.ts +55 -16
  771. package/src/home/__tests__/feed-writer.test.ts +0 -4
  772. package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
  773. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  774. package/src/home/__tests__/rollup-producer.test.ts +67 -2
  775. package/src/home/assistant-feed-authoring.ts +8 -1
  776. package/src/home/feed-types.ts +1 -1
  777. package/src/home/feed-writer.ts +1 -2
  778. package/src/home/relationship-state-writer.ts +17 -4
  779. package/src/home/rewrite-feed-title.ts +58 -0
  780. package/src/home/rollup-producer.ts +16 -3
  781. package/src/inbound/platform-callback-registration.ts +1 -17
  782. package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
  783. package/src/ipc/__tests__/browser-ipc.test.ts +72 -58
  784. package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
  785. package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
  786. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +253 -0
  787. package/src/ipc/__tests__/skill-server.test.ts +182 -0
  788. package/src/ipc/__tests__/socket-path.test.ts +69 -23
  789. package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
  790. package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
  791. package/src/ipc/assistant-server.ts +443 -0
  792. package/src/ipc/cli-client.ts +3 -3
  793. package/src/ipc/gateway-client.test.ts +131 -0
  794. package/src/ipc/gateway-client.ts +98 -123
  795. package/src/ipc/ipc-framing.ts +281 -0
  796. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +171 -0
  797. package/src/ipc/routes/db-proxy.ts +73 -0
  798. package/src/ipc/routes/route-adapter.ts +32 -0
  799. package/src/ipc/routes/trust-rules.test.ts +123 -0
  800. package/src/ipc/skill-ipc-types.ts +54 -0
  801. package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
  802. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +388 -0
  803. package/src/ipc/skill-routes/__tests__/identity.test.ts +62 -0
  804. package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
  805. package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
  806. package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
  807. package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
  808. package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
  809. package/src/ipc/skill-routes/config.ts +47 -0
  810. package/src/ipc/skill-routes/events.ts +120 -0
  811. package/src/ipc/skill-routes/identity.ts +21 -0
  812. package/src/ipc/skill-routes/index.ts +37 -0
  813. package/src/ipc/skill-routes/log.ts +40 -0
  814. package/src/ipc/skill-routes/memory.ts +76 -0
  815. package/src/ipc/skill-routes/platform.ts +39 -0
  816. package/src/ipc/skill-routes/providers.ts +163 -0
  817. package/src/ipc/skill-routes/registries.ts +393 -0
  818. package/src/ipc/skill-server.ts +738 -0
  819. package/src/ipc/skill-socket-path.ts +20 -0
  820. package/src/ipc/socket-cleanup.ts +92 -0
  821. package/src/ipc/socket-path.ts +63 -32
  822. package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
  823. package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
  824. package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
  825. package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
  826. package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
  827. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
  828. package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
  829. package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
  830. package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
  831. package/src/live-voice/__tests__/protocol.test.ts +295 -0
  832. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +413 -0
  833. package/src/live-voice/live-voice-archive.ts +758 -0
  834. package/src/live-voice/live-voice-metrics.ts +472 -0
  835. package/src/live-voice/live-voice-session-manager.ts +222 -0
  836. package/src/live-voice/live-voice-session.ts +1144 -0
  837. package/src/live-voice/live-voice-tts.ts +260 -0
  838. package/src/live-voice/protocol.ts +515 -0
  839. package/src/mcp/client.ts +2 -2
  840. package/src/mcp/manager.ts +0 -5
  841. package/src/media/types.ts +4 -4
  842. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
  843. package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
  844. package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
  845. package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
  846. package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
  847. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  848. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
  849. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  850. package/src/memory/admin.ts +65 -7
  851. package/src/memory/app-git-service.ts +0 -46
  852. package/src/memory/app-store.ts +154 -0
  853. package/src/memory/attachments-store.ts +20 -16
  854. package/src/memory/auto-analysis-enqueue.ts +2 -17
  855. package/src/memory/canonical-guardian-store.ts +2 -1
  856. package/src/memory/channel-verification-sessions.ts +1 -1
  857. package/src/memory/checkpoints.ts +1 -1
  858. package/src/memory/context-search/agent-protocol.ts +424 -0
  859. package/src/memory/context-search/agent-runner.ts +1295 -0
  860. package/src/memory/context-search/format.ts +160 -0
  861. package/src/memory/context-search/limits.ts +106 -0
  862. package/src/memory/context-search/search.ts +387 -0
  863. package/src/memory/context-search/sources/conversations.ts +278 -0
  864. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  865. package/src/memory/context-search/sources/memory.ts +95 -0
  866. package/src/memory/context-search/sources/pkb.ts +477 -0
  867. package/src/memory/context-search/sources/workspace.ts +1256 -0
  868. package/src/memory/context-search/types.ts +49 -0
  869. package/src/memory/conversation-analyze-job.ts +3 -24
  870. package/src/memory/conversation-attention-store.ts +1 -1
  871. package/src/memory/conversation-bootstrap.ts +1 -1
  872. package/src/memory/conversation-crud.ts +86 -119
  873. package/src/memory/conversation-directories.ts +1 -11
  874. package/src/memory/conversation-disk-view.ts +1 -5
  875. package/src/memory/conversation-display-order-migration.ts +11 -2
  876. package/src/memory/conversation-group-migration.ts +20 -4
  877. package/src/memory/conversation-key-store.ts +3 -4
  878. package/src/memory/conversation-queries.ts +13 -26
  879. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  880. package/src/memory/conversation-starter-validation.ts +88 -0
  881. package/src/memory/conversation-starters-cadence.ts +1 -1
  882. package/src/memory/conversation-title-service.ts +2 -1
  883. package/src/memory/db-connection.ts +62 -0
  884. package/src/memory/db-init.ts +28 -4
  885. package/src/memory/db-maintenance.ts +1 -1
  886. package/src/memory/delivery-channels.ts +1 -14
  887. package/src/memory/delivery-crud.ts +2 -32
  888. package/src/memory/delivery-status.ts +1 -1
  889. package/src/memory/embedding-backend.ts +3 -21
  890. package/src/memory/embedding-gemini.test.ts +4 -4
  891. package/src/memory/embedding-gemini.ts +0 -2
  892. package/src/memory/embedding-local.ts +6 -6
  893. package/src/memory/embedding-ollama.ts +6 -6
  894. package/src/memory/embedding-openai.ts +6 -6
  895. package/src/memory/embedding-types.ts +21 -0
  896. package/src/memory/external-conversation-store.ts +1 -1
  897. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +408 -0
  898. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
  899. package/src/memory/graph/bootstrap.test.ts +2 -7
  900. package/src/memory/graph/bootstrap.ts +2 -1
  901. package/src/memory/graph/capability-seed.ts +3 -3
  902. package/src/memory/graph/compaction.ts +1 -1
  903. package/src/memory/graph/consolidation.ts +13 -10
  904. package/src/memory/graph/conversation-graph-memory.ts +184 -12
  905. package/src/memory/graph/decay.ts +1 -1
  906. package/src/memory/graph/extraction.ts +53 -21
  907. package/src/memory/graph/graph-memory-state-store.ts +1 -1
  908. package/src/memory/graph/graph-search.test.ts +94 -2
  909. package/src/memory/graph/graph-search.ts +22 -7
  910. package/src/memory/graph/image-ref-utils.ts +1 -1
  911. package/src/memory/graph/injection.test.ts +2 -2
  912. package/src/memory/graph/injection.ts +1 -1
  913. package/src/memory/graph/retriever.test.ts +158 -4
  914. package/src/memory/graph/retriever.ts +17 -5
  915. package/src/memory/graph/store.test.ts +2 -1
  916. package/src/memory/graph/store.ts +1 -1
  917. package/src/memory/graph/tool-handlers.ts +73 -247
  918. package/src/memory/graph/tools.ts +35 -53
  919. package/src/memory/group-crud.ts +1 -2
  920. package/src/memory/guardian-action-store.ts +2 -84
  921. package/src/memory/guardian-approvals.ts +1 -49
  922. package/src/memory/guardian-rate-limits.ts +1 -1
  923. package/src/memory/indexer.ts +44 -32
  924. package/src/memory/invite-store.ts +1 -1
  925. package/src/memory/job-handlers/backfill.ts +1 -1
  926. package/src/memory/job-handlers/cleanup.ts +2 -1
  927. package/src/memory/job-handlers/conversation-starters.ts +54 -63
  928. package/src/memory/job-handlers/embedding.test.ts +2 -1
  929. package/src/memory/job-handlers/embedding.ts +1 -1
  930. package/src/memory/job-handlers/index-maintenance.ts +1 -1
  931. package/src/memory/job-handlers/summarization.ts +3 -3
  932. package/src/memory/job-utils.ts +3 -9
  933. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
  934. package/src/memory/jobs/embed-concept-page.ts +210 -0
  935. package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
  936. package/src/memory/jobs-store.ts +9 -2
  937. package/src/memory/jobs-worker.ts +56 -17
  938. package/src/memory/lifecycle-events-store.ts +1 -1
  939. package/src/memory/llm-request-log-store.ts +1 -42
  940. package/src/memory/llm-usage-store.ts +130 -44
  941. package/src/memory/media-store.ts +1 -1
  942. package/src/memory/memory-recall-log-store.ts +1 -1
  943. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  944. package/src/memory/migrations/038-actor-token-records.ts +3 -0
  945. package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
  946. package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
  947. package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
  948. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
  949. package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
  950. package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
  951. package/src/memory/migrations/230-acp-session-history.ts +41 -0
  952. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
  953. package/src/memory/migrations/232-activation-state.ts +38 -0
  954. package/src/memory/migrations/233-document-conversations.ts +54 -0
  955. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  956. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  957. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  958. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  959. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  960. package/src/memory/migrations/index.ts +24 -0
  961. package/src/memory/migrations/registry.ts +31 -0
  962. package/src/memory/pkb/pkb-index.test.ts +4 -5
  963. package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
  964. package/src/memory/pkb/pkb-search.test.ts +83 -3
  965. package/src/memory/pkb/pkb-search.ts +27 -14
  966. package/src/memory/published-pages-store.ts +1 -1
  967. package/src/memory/raw-query.ts +2 -68
  968. package/src/memory/schema/acp.ts +30 -0
  969. package/src/memory/schema/conversations.ts +8 -1
  970. package/src/memory/schema/index.ts +1 -0
  971. package/src/memory/schema/infrastructure.ts +26 -32
  972. package/src/memory/schema/memory-graph.ts +36 -14
  973. package/src/memory/scoped-approval-grants.ts +2 -1
  974. package/src/memory/search/semantic.ts +7 -18
  975. package/src/memory/shared-app-links-store.ts +2 -1
  976. package/src/memory/tool-usage-store.ts +3 -1
  977. package/src/memory/trace-event-store.ts +2 -1
  978. package/src/memory/turn-events-store.ts +1 -1
  979. package/src/memory/usage-buckets.ts +40 -1
  980. package/src/memory/usage-grouped-buckets.ts +127 -0
  981. package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
  982. package/src/memory/v2/__tests__/activation.test.ts +1155 -0
  983. package/src/memory/v2/__tests__/backfill-jobs.test.ts +483 -0
  984. package/src/memory/v2/__tests__/consolidation-job.test.ts +412 -0
  985. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  986. package/src/memory/v2/__tests__/injection.test.ts +1161 -0
  987. package/src/memory/v2/__tests__/migration.test.ts +840 -0
  988. package/src/memory/v2/__tests__/page-store.test.ts +517 -0
  989. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  990. package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
  991. package/src/memory/v2/__tests__/sim.test.ts +549 -0
  992. package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
  993. package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
  994. package/src/memory/v2/__tests__/skill-store.test.ts +463 -0
  995. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  996. package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
  997. package/src/memory/v2/activation-store.ts +109 -0
  998. package/src/memory/v2/activation.ts +561 -0
  999. package/src/memory/v2/backfill-jobs.ts +357 -0
  1000. package/src/memory/v2/consolidation-job.ts +306 -0
  1001. package/src/memory/v2/edge-index.ts +191 -0
  1002. package/src/memory/v2/injection.ts +431 -0
  1003. package/src/memory/v2/migration.ts +647 -0
  1004. package/src/memory/v2/now-text.ts +37 -0
  1005. package/src/memory/v2/page-store.ts +382 -0
  1006. package/src/memory/v2/prompts/consolidation.ts +261 -0
  1007. package/src/memory/v2/prompts/sweep.ts +56 -0
  1008. package/src/memory/v2/qdrant.ts +342 -0
  1009. package/src/memory/v2/sim.ts +206 -0
  1010. package/src/memory/v2/skill-content.ts +42 -0
  1011. package/src/memory/v2/skill-qdrant.ts +395 -0
  1012. package/src/memory/v2/skill-store.ts +176 -0
  1013. package/src/memory/v2/static-context.ts +62 -0
  1014. package/src/memory/v2/sweep-job.ts +298 -0
  1015. package/src/memory/v2/types.ts +106 -0
  1016. package/src/memory/validation.ts +0 -11
  1017. package/src/messaging/draft-store.ts +0 -6
  1018. package/src/messaging/provider-types.ts +8 -0
  1019. package/src/messaging/provider.ts +7 -0
  1020. package/src/messaging/providers/gmail/client.ts +1 -121
  1021. package/src/messaging/providers/index.ts +262 -0
  1022. package/src/messaging/providers/outlook/client.ts +0 -73
  1023. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  1024. package/src/messaging/providers/slack/adapter.ts +122 -21
  1025. package/src/messaging/providers/slack/api.ts +242 -0
  1026. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  1027. package/src/messaging/providers/slack/backfill.ts +89 -11
  1028. package/src/messaging/providers/slack/client.ts +10 -124
  1029. package/src/messaging/providers/slack/message-metadata.ts +13 -3
  1030. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  1031. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  1032. package/src/messaging/providers/slack/send.ts +383 -0
  1033. package/src/messaging/providers/slack/types.ts +1 -0
  1034. package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
  1035. package/src/messaging/providers/telegram-bot/api.ts +253 -0
  1036. package/src/messaging/providers/telegram-bot/client.ts +17 -58
  1037. package/src/messaging/providers/telegram-bot/send.ts +232 -0
  1038. package/src/messaging/providers/whatsapp/adapter.ts +4 -36
  1039. package/src/messaging/providers/whatsapp/api.ts +319 -0
  1040. package/src/messaging/providers/whatsapp/client.ts +4 -48
  1041. package/src/messaging/providers/whatsapp/send.ts +209 -0
  1042. package/src/notifications/adapters/slack.ts +5 -23
  1043. package/src/notifications/adapters/telegram.ts +8 -29
  1044. package/src/notifications/conversation-candidates.ts +1 -1
  1045. package/src/notifications/conversation-seed-composer.ts +12 -6
  1046. package/src/notifications/copy-composer.ts +1 -1
  1047. package/src/notifications/decision-engine.ts +1 -1
  1048. package/src/notifications/decisions-store.ts +1 -1
  1049. package/src/notifications/deliveries-store.ts +2 -1
  1050. package/src/notifications/deterministic-checks.ts +1 -1
  1051. package/src/notifications/events-store.ts +1 -13
  1052. package/src/notifications/preferences-store.ts +1 -1
  1053. package/src/notifications/signal.ts +0 -9
  1054. package/src/oauth/connection-resolver.test.ts +8 -0
  1055. package/src/oauth/connection-resolver.ts +6 -5
  1056. package/src/oauth/credential-token-resolver.ts +97 -0
  1057. package/src/oauth/manual-token-connection.ts +30 -34
  1058. package/src/oauth/oauth-store.ts +8 -5
  1059. package/src/outbound-proxy/certs.ts +0 -7
  1060. package/src/outbound-proxy/config.ts +0 -74
  1061. package/src/outbound-proxy/health.ts +0 -44
  1062. package/src/outbound-proxy/index.ts +0 -23
  1063. package/src/permissions/approval-policy.test.ts +149 -132
  1064. package/src/permissions/approval-policy.ts +65 -91
  1065. package/src/permissions/approval-provenance.test.ts +184 -0
  1066. package/src/permissions/approval-provenance.ts +70 -0
  1067. package/src/permissions/checker.test.ts +632 -0
  1068. package/src/permissions/checker.ts +270 -460
  1069. package/src/permissions/gateway-threshold-reader.ts +31 -47
  1070. package/src/permissions/ipc-risk-types.ts +95 -0
  1071. package/src/permissions/prompter.ts +13 -11
  1072. package/src/permissions/risk-types.ts +24 -210
  1073. package/src/permissions/secret-prompter.ts +21 -48
  1074. package/src/permissions/types.ts +49 -46
  1075. package/src/permissions/workspace-policy.ts +1 -8
  1076. package/src/platform/sync-identity.ts +0 -8
  1077. package/src/playbooks/playbook-compiler.ts +1 -1
  1078. package/src/plugins/defaults/index.ts +1 -1
  1079. package/src/plugins/defaults/injectors.ts +87 -23
  1080. package/src/plugins/defaults/llm-call.ts +6 -9
  1081. package/src/plugins/defaults/memory-retrieval.ts +1 -6
  1082. package/src/plugins/defaults/overflow-reduce.ts +12 -7
  1083. package/src/plugins/defaults/token-estimate.ts +2 -3
  1084. package/src/plugins/registry.ts +61 -1
  1085. package/src/plugins/types.ts +14 -7
  1086. package/src/plugins/user-loader.ts +36 -10
  1087. package/src/prompts/persona-resolver.ts +2 -4
  1088. package/src/prompts/system-prompt.ts +34 -31
  1089. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  1090. package/src/prompts/templates/SOUL.md +3 -1
  1091. package/src/prompts/update-bulletin-job.ts +2 -0
  1092. package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
  1093. package/src/providers/__tests__/retry-callsite.test.ts +141 -7
  1094. package/src/providers/anthropic/client.ts +143 -52
  1095. package/src/providers/call-site-routing.ts +49 -6
  1096. package/src/providers/fireworks/client.ts +3 -0
  1097. package/src/providers/gemini/client.ts +113 -23
  1098. package/src/providers/managed-proxy/context.ts +0 -17
  1099. package/src/providers/model-catalog.ts +188 -27
  1100. package/src/providers/model-intents.ts +7 -8
  1101. package/src/providers/openai/chat-completions-provider.ts +43 -7
  1102. package/src/providers/openai/responses-provider.ts +46 -5
  1103. package/src/providers/openrouter/client.ts +4 -5
  1104. package/src/providers/provider-env-vars.ts +4 -12
  1105. package/src/providers/provider-send-message.ts +61 -13
  1106. package/src/providers/ratelimit.ts +7 -2
  1107. package/src/providers/registry.ts +15 -10
  1108. package/src/providers/retry.ts +148 -31
  1109. package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
  1110. package/src/providers/speech-to-text/openai-whisper.ts +3 -6
  1111. package/src/providers/speech-to-text/provider-catalog.ts +75 -0
  1112. package/src/providers/speech-to-text/xai.ts +5 -5
  1113. package/src/providers/thinking-config.ts +34 -0
  1114. package/src/providers/types.ts +35 -10
  1115. package/src/providers/usage-tracking.ts +96 -0
  1116. package/src/runtime/AGENTS.md +16 -11
  1117. package/src/runtime/__tests__/agent-wake.test.ts +122 -9
  1118. package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
  1119. package/src/runtime/access-request-helper.ts +9 -20
  1120. package/src/runtime/actor-trust-resolver.ts +2 -2
  1121. package/src/runtime/agent-wake.ts +211 -68
  1122. package/src/runtime/approval-conversation-turn.ts +2 -15
  1123. package/src/runtime/approval-message-composer.ts +11 -60
  1124. package/src/runtime/assistant-event-hub.ts +541 -45
  1125. package/src/runtime/assistant-event.ts +16 -69
  1126. package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
  1127. package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
  1128. package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
  1129. package/src/runtime/auth/middleware.ts +5 -5
  1130. package/src/runtime/auth/route-policy.ts +205 -12
  1131. package/src/runtime/auth/token-service.ts +1 -111
  1132. package/src/runtime/capability-tokens.ts +89 -313
  1133. package/src/runtime/channel-approval-types.ts +1 -6
  1134. package/src/runtime/channel-approvals.ts +13 -81
  1135. package/src/runtime/channel-readiness-service.ts +2 -2
  1136. package/src/runtime/channel-reply-delivery.ts +2 -8
  1137. package/src/runtime/channel-retry-sweep.ts +20 -17
  1138. package/src/runtime/channel-verification-service.ts +3 -5
  1139. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
  1140. package/src/runtime/gateway-client.ts +37 -378
  1141. package/src/runtime/guardian-action-grant-minter.ts +2 -3
  1142. package/src/runtime/guardian-action-message-composer.ts +11 -52
  1143. package/src/runtime/guardian-action-service.ts +19 -7
  1144. package/src/runtime/guardian-decision-types.ts +4 -65
  1145. package/src/runtime/guardian-reply-router.ts +10 -19
  1146. package/src/runtime/guardian-vellum-migration.ts +5 -64
  1147. package/src/runtime/http-errors.ts +1 -32
  1148. package/src/runtime/http-router.ts +54 -8
  1149. package/src/runtime/http-server.ts +362 -1187
  1150. package/src/runtime/http-types.ts +20 -98
  1151. package/src/runtime/interactive-ui-types.ts +145 -0
  1152. package/src/runtime/interactive-ui.ts +37 -196
  1153. package/src/runtime/invite-redemption-service.ts +1 -1
  1154. package/src/runtime/invite-redemption-templates.ts +1 -1
  1155. package/src/runtime/local-actor-identity.ts +13 -43
  1156. package/src/runtime/message-composer-types.ts +134 -0
  1157. package/src/runtime/middleware/auth.ts +0 -20
  1158. package/src/runtime/middleware/rate-limiter.ts +1 -1
  1159. package/src/runtime/middleware/request-logger.ts +5 -2
  1160. package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
  1161. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  1162. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  1163. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  1164. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  1165. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  1166. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  1167. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  1168. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  1169. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +18 -2
  1170. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  1171. package/src/runtime/migrations/job-registry.ts +281 -0
  1172. package/src/runtime/migrations/migration-transport.ts +46 -13
  1173. package/src/runtime/migrations/migration-wizard.ts +2 -2
  1174. package/src/runtime/migrations/origin-mode.ts +40 -0
  1175. package/src/runtime/migrations/vbundle-builder.ts +133 -80
  1176. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  1177. package/src/runtime/migrations/vbundle-importer.ts +8 -8
  1178. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  1179. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -16
  1180. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  1181. package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
  1182. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  1183. package/src/runtime/nl-approval-parser.ts +16 -21
  1184. package/src/runtime/pending-interactions.ts +42 -16
  1185. package/src/runtime/routes/__tests__/acp-routes.test.ts +394 -0
  1186. package/src/runtime/routes/__tests__/backup-routes.test.ts +232 -339
  1187. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  1188. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
  1189. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  1190. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  1191. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  1192. package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
  1193. package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
  1194. package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
  1195. package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
  1196. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  1197. package/src/runtime/routes/access-request-decision.ts +25 -50
  1198. package/src/runtime/routes/acp-routes.test.ts +368 -0
  1199. package/src/runtime/routes/acp-routes.ts +392 -170
  1200. package/src/runtime/routes/app-management-routes.ts +475 -662
  1201. package/src/runtime/routes/app-routes.ts +192 -177
  1202. package/src/runtime/routes/approval-routes.ts +163 -440
  1203. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
  1204. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
  1205. package/src/runtime/routes/attachment-routes.ts +409 -253
  1206. package/src/runtime/routes/audio-routes.ts +51 -18
  1207. package/src/runtime/routes/avatar-routes.ts +81 -76
  1208. package/src/runtime/routes/background-tool-routes.ts +94 -0
  1209. package/src/runtime/routes/backup-routes.ts +154 -336
  1210. package/src/runtime/routes/brain-graph-routes.ts +83 -110
  1211. package/src/runtime/routes/browser-routes.ts +127 -0
  1212. package/src/runtime/routes/btw-routes.ts +62 -106
  1213. package/src/runtime/routes/cache-routes.ts +96 -0
  1214. package/src/runtime/routes/call-routes.ts +208 -247
  1215. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
  1216. package/src/runtime/routes/channel-delivery-routes.ts +25 -27
  1217. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  1218. package/src/runtime/routes/channel-readiness-routes.ts +79 -120
  1219. package/src/runtime/routes/channel-route-definitions.ts +62 -0
  1220. package/src/runtime/routes/channel-route-shared.ts +15 -45
  1221. package/src/runtime/routes/channel-verification-routes.ts +207 -187
  1222. package/src/runtime/routes/client-routes.ts +81 -0
  1223. package/src/runtime/routes/consolidation-routes.ts +115 -0
  1224. package/src/runtime/routes/contact-routes.ts +533 -407
  1225. package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
  1226. package/src/runtime/routes/conversation-attention-routes.ts +55 -67
  1227. package/src/runtime/routes/conversation-list-routes.ts +248 -0
  1228. package/src/runtime/routes/conversation-management-routes.ts +591 -717
  1229. package/src/runtime/routes/conversation-query-routes.ts +621 -459
  1230. package/src/runtime/routes/conversation-routes.ts +396 -792
  1231. package/src/runtime/routes/conversation-starter-routes.ts +137 -108
  1232. package/src/runtime/routes/credential-prompt-routes.ts +124 -0
  1233. package/src/runtime/routes/debug-routes.ts +34 -39
  1234. package/src/runtime/routes/defer-routes.ts +230 -0
  1235. package/src/runtime/routes/diagnostics-routes.ts +79 -70
  1236. package/src/runtime/routes/documents-routes.ts +163 -117
  1237. package/src/runtime/routes/errors.ts +132 -0
  1238. package/src/runtime/routes/events-routes.ts +126 -119
  1239. package/src/runtime/routes/filing-routes.ts +80 -76
  1240. package/src/runtime/routes/global-search-routes.ts +51 -57
  1241. package/src/runtime/routes/group-routes.ts +199 -181
  1242. package/src/runtime/routes/guardian-action-routes.ts +100 -171
  1243. package/src/runtime/routes/guardian-approval-interception.ts +27 -58
  1244. package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
  1245. package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
  1246. package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
  1247. package/src/runtime/routes/heartbeat-routes.ts +194 -209
  1248. package/src/runtime/routes/home-feed-routes.ts +85 -187
  1249. package/src/runtime/routes/home-state-routes.ts +27 -24
  1250. package/src/runtime/routes/host-bash-routes.ts +45 -54
  1251. package/src/runtime/routes/host-browser-routes.ts +44 -99
  1252. package/src/runtime/routes/host-cu-routes.ts +80 -71
  1253. package/src/runtime/routes/host-file-routes.ts +53 -62
  1254. package/src/runtime/routes/host-transfer-routes.ts +216 -0
  1255. package/src/runtime/routes/http-adapter.ts +172 -0
  1256. package/src/runtime/routes/identity-routes.ts +161 -85
  1257. package/src/runtime/routes/inbound-conversation.ts +11 -18
  1258. package/src/runtime/routes/inbound-message-handler.ts +639 -232
  1259. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +81 -226
  1260. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
  1261. package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -90
  1262. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
  1263. package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
  1264. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
  1265. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
  1266. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
  1267. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
  1268. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  1269. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
  1270. package/src/runtime/routes/index.ts +201 -0
  1271. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
  1272. package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
  1273. package/src/runtime/routes/integrations/slack/channel.ts +50 -71
  1274. package/src/runtime/routes/integrations/slack/share.ts +49 -58
  1275. package/src/runtime/routes/integrations/telegram.ts +91 -74
  1276. package/src/runtime/routes/integrations/twilio.ts +163 -240
  1277. package/src/runtime/routes/integrations/vercel.ts +57 -54
  1278. package/src/runtime/routes/interface-routes.ts +43 -0
  1279. package/src/runtime/routes/internal-oauth-routes.ts +56 -0
  1280. package/src/runtime/routes/internal-twilio-routes.ts +46 -0
  1281. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  1282. package/src/runtime/routes/llm-context-normalization.ts +4 -2
  1283. package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
  1284. package/src/runtime/routes/log-export-routes.ts +90 -100
  1285. package/src/runtime/routes/memory-item-routes.test.ts +152 -175
  1286. package/src/runtime/routes/memory-item-routes.ts +243 -323
  1287. package/src/runtime/routes/memory-v2-routes.ts +188 -0
  1288. package/src/runtime/routes/migration-rollback-routes.ts +167 -212
  1289. package/src/runtime/routes/migration-routes.ts +1037 -377
  1290. package/src/runtime/routes/notification-routes.ts +199 -70
  1291. package/src/runtime/routes/oauth-apps.ts +254 -251
  1292. package/src/runtime/routes/oauth-providers.ts +66 -57
  1293. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +60 -120
  1294. package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
  1295. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
  1296. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
  1297. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
  1298. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
  1299. package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
  1300. package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
  1301. package/src/runtime/routes/playground/force-compact.ts +41 -54
  1302. package/src/runtime/routes/playground/guard.ts +18 -19
  1303. package/src/runtime/routes/playground/helpers.ts +103 -0
  1304. package/src/runtime/routes/playground/index.ts +15 -27
  1305. package/src/runtime/routes/playground/inject-failures.ts +48 -64
  1306. package/src/runtime/routes/playground/reset-circuit.ts +31 -57
  1307. package/src/runtime/routes/playground/seed-conversation.ts +66 -92
  1308. package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
  1309. package/src/runtime/routes/playground/state.ts +23 -24
  1310. package/src/runtime/routes/profiler-routes.ts +132 -167
  1311. package/src/runtime/routes/ps-routes.ts +120 -0
  1312. package/src/runtime/routes/recording-routes.ts +189 -270
  1313. package/src/runtime/routes/rename-conversation-routes.ts +85 -0
  1314. package/src/runtime/routes/schedule-routes.ts +239 -246
  1315. package/src/runtime/routes/secret-routes.ts +305 -282
  1316. package/src/runtime/routes/secrets-deps.ts +24 -0
  1317. package/src/runtime/routes/settings-routes.ts +370 -449
  1318. package/src/runtime/routes/skills-routes.ts +417 -471
  1319. package/src/runtime/routes/stt-routes.ts +196 -206
  1320. package/src/runtime/routes/subagents-routes.ts +125 -141
  1321. package/src/runtime/routes/suggest-trust-rule-routes.ts +275 -0
  1322. package/src/runtime/routes/surface-action-routes.ts +135 -190
  1323. package/src/runtime/routes/surface-content-routes.ts +84 -118
  1324. package/src/runtime/routes/task-routes.ts +354 -0
  1325. package/src/runtime/routes/telemetry-routes.ts +33 -49
  1326. package/src/runtime/routes/trace-event-routes.ts +55 -74
  1327. package/src/runtime/routes/trust-rules-routes.ts +61 -244
  1328. package/src/runtime/routes/tts-routes.ts +187 -169
  1329. package/src/runtime/routes/types.ts +139 -0
  1330. package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
  1331. package/src/runtime/routes/upgrade-broadcast-routes.ts +150 -198
  1332. package/src/runtime/routes/usage-routes.ts +222 -171
  1333. package/src/runtime/routes/user-routes.ts +88 -18
  1334. package/src/runtime/routes/wake-conversation-routes.ts +49 -0
  1335. package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
  1336. package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
  1337. package/src/runtime/routes/work-items-routes.test.ts +10 -20
  1338. package/src/runtime/routes/work-items-routes.ts +419 -437
  1339. package/src/runtime/routes/workspace-commit-routes.ts +30 -61
  1340. package/src/runtime/routes/workspace-routes.test.ts +254 -381
  1341. package/src/runtime/routes/workspace-routes.ts +238 -246
  1342. package/src/runtime/runtime-mode.ts +8 -1
  1343. package/src/runtime/services/__tests__/analyze-conversation.test.ts +82 -120
  1344. package/src/runtime/services/analyze-conversation.ts +18 -55
  1345. package/src/runtime/services/conversation-serializer.ts +179 -0
  1346. package/src/runtime/trust-context-resolver.ts +3 -2
  1347. package/src/runtime/verification-outbound-actions.ts +14 -50
  1348. package/src/runtime/verification-rate-limiter.ts +1 -1
  1349. package/src/schedule/schedule-store.ts +64 -18
  1350. package/src/schedule/scheduler.ts +101 -0
  1351. package/src/security/ces-credential-client.ts +32 -169
  1352. package/src/security/ces-rpc-credential-backend.ts +1 -1
  1353. package/src/security/credential-backend.ts +6 -6
  1354. package/src/security/oauth-completion-page.ts +1 -1
  1355. package/src/security/oauth2.ts +3 -6
  1356. package/src/security/secret-scanner.ts +14 -547
  1357. package/src/security/secure-keys.ts +31 -11
  1358. package/src/security/token-manager.ts +7 -3
  1359. package/src/sequence/analytics.ts +1 -1
  1360. package/src/sequence/guardrails.ts +3 -3
  1361. package/src/sequence/store.ts +2 -1
  1362. package/src/signals/bash.ts +1 -1
  1363. package/src/signals/cancel.ts +16 -25
  1364. package/src/signals/conversation-undo.ts +2 -27
  1365. package/src/signals/emit-event.ts +1 -2
  1366. package/src/signals/event-stream.ts +1 -1
  1367. package/src/signals/user-message.ts +108 -22
  1368. package/src/skills/catalog-cache.ts +7 -0
  1369. package/src/skills/catalog-files.ts +0 -5
  1370. package/src/skills/catalog-install.ts +29 -18
  1371. package/src/skills/category-inference.ts +0 -11
  1372. package/src/skills/clawhub.ts +4 -4
  1373. package/src/skills/inline-command-runner.ts +1 -7
  1374. package/src/skills/managed-store.ts +2 -2
  1375. package/src/skills/remote-skill-policy.ts +6 -7
  1376. package/src/subagent/index.ts +2 -6
  1377. package/src/subagent/manager.ts +94 -107
  1378. package/src/subagent/types.ts +9 -0
  1379. package/src/tasks/SPEC.md +2 -2
  1380. package/src/tasks/task-compiler.ts +1 -1
  1381. package/src/tasks/task-runner.ts +2 -22
  1382. package/src/tasks/task-store.ts +2 -29
  1383. package/src/telemetry/types.ts +6 -0
  1384. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  1385. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  1386. package/src/tools/acp/list-agents.test.ts +115 -0
  1387. package/src/tools/acp/list-agents.ts +31 -0
  1388. package/src/tools/acp/spawn.test.ts +378 -0
  1389. package/src/tools/acp/spawn.ts +142 -62
  1390. package/src/tools/acp/steer.test.ts +100 -0
  1391. package/src/tools/acp/steer.ts +38 -0
  1392. package/src/tools/background-tool-registry.ts +98 -0
  1393. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  1394. package/src/tools/browser/browser-execution.ts +38 -127
  1395. package/src/tools/browser/browser-manager.ts +1 -8
  1396. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  1397. package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
  1398. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
  1399. package/src/tools/browser/cdp-client/factory.ts +48 -76
  1400. package/src/tools/browser/cdp-client/index.ts +1 -14
  1401. package/src/tools/browser/cdp-client/types.ts +4 -1
  1402. package/src/tools/computer-use/definitions.ts +1 -1
  1403. package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
  1404. package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
  1405. package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
  1406. package/src/tools/credentials/broker-types.ts +2 -1
  1407. package/src/tools/document/editor-template.ts +1 -1
  1408. package/src/tools/execution-timeout.ts +1 -1
  1409. package/src/tools/executor.ts +53 -45
  1410. package/src/tools/host-filesystem/edit.ts +3 -2
  1411. package/src/tools/host-filesystem/read.ts +3 -2
  1412. package/src/tools/host-filesystem/transfer.test.ts +271 -0
  1413. package/src/tools/host-filesystem/transfer.ts +235 -0
  1414. package/src/tools/host-filesystem/write.ts +3 -2
  1415. package/src/tools/host-terminal/host-shell.ts +192 -13
  1416. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  1417. package/src/tools/memory/register.test.ts +161 -1
  1418. package/src/tools/memory/register.ts +19 -34
  1419. package/src/tools/network/script-proxy/index.ts +1 -10
  1420. package/src/tools/permission-checker.ts +84 -220
  1421. package/src/tools/policy-context.ts +1 -8
  1422. package/src/tools/registry.ts +16 -1
  1423. package/src/tools/shared/shell-output.ts +4 -1
  1424. package/src/tools/side-effects.ts +2 -2
  1425. package/src/tools/skills/execute.ts +1 -1
  1426. package/src/tools/skills/sandbox-runner.ts +1 -6
  1427. package/src/tools/skills/skill-tool-factory.ts +32 -0
  1428. package/src/tools/subagent/spawn.ts +35 -11
  1429. package/src/tools/terminal/safe-env.ts +10 -1
  1430. package/src/tools/terminal/shell.ts +142 -88
  1431. package/src/tools/tool-approval-handler.ts +4 -70
  1432. package/src/tools/tool-input-summary.ts +10 -0
  1433. package/src/tools/types.ts +136 -183
  1434. package/src/tools/ui-surface/definitions.ts +2 -2
  1435. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  1436. package/src/tts/provider-catalog.ts +1 -1
  1437. package/src/usage/actors.ts +2 -1
  1438. package/src/usage/attribution.ts +185 -0
  1439. package/src/usage/pricing.ts +166 -0
  1440. package/src/usage/types.ts +14 -0
  1441. package/src/util/debounce.ts +0 -21
  1442. package/src/util/errors.ts +0 -8
  1443. package/src/util/json.ts +13 -0
  1444. package/src/util/log-redact.ts +0 -1
  1445. package/src/util/logger.ts +3 -3
  1446. package/src/util/platform.ts +85 -124
  1447. package/src/util/pricing.ts +158 -8
  1448. package/src/watcher/engine.ts +42 -20
  1449. package/src/watcher/watcher-store.ts +2 -1
  1450. package/src/work-items/work-item-runner.ts +15 -42
  1451. package/src/work-items/work-item-store.ts +1 -1
  1452. package/src/workspace/git-service.ts +1 -6
  1453. package/src/workspace/migrations/006-services-config.ts +10 -1
  1454. package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
  1455. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
  1456. package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
  1457. package/src/workspace/migrations/031-drop-user-md.ts +1 -1
  1458. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
  1459. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  1460. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
  1461. package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
  1462. package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
  1463. package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
  1464. package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
  1465. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
  1466. package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
  1467. package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
  1468. package/src/workspace/migrations/060-memory-v2-init.ts +37 -0
  1469. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  1470. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  1471. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  1472. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  1473. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
  1474. package/src/workspace/migrations/registry.ts +26 -0
  1475. package/src/workspace/migrations/runner.ts +2 -2
  1476. package/src/workspace/provider-commit-message-generator.ts +4 -4
  1477. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  1478. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  1479. package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
  1480. package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
  1481. package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
  1482. package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
  1483. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
  1484. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
  1485. package/src/__tests__/ephemeral-permissions.test.ts +0 -474
  1486. package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
  1487. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
  1488. package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
  1489. package/src/__tests__/pairing-concurrent.test.ts +0 -84
  1490. package/src/__tests__/pairing-routes.test.ts +0 -181
  1491. package/src/__tests__/parser.test.ts +0 -595
  1492. package/src/__tests__/permission-checker-host-gate.test.ts +0 -488
  1493. package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
  1494. package/src/__tests__/permission-mode.test.ts +0 -89
  1495. package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
  1496. package/src/__tests__/risk-classifier-parity.test.ts +0 -230
  1497. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  1498. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  1499. package/src/__tests__/secret-detection-handler.test.ts +0 -74
  1500. package/src/__tests__/secret-scanner-executor.test.ts +0 -451
  1501. package/src/__tests__/shell-identity.test.ts +0 -236
  1502. package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
  1503. package/src/__tests__/shell-parser-property.test.ts +0 -936
  1504. package/src/__tests__/starter-bundle.test.ts +0 -173
  1505. package/src/__tests__/stt-catalog-parity.test.ts +0 -282
  1506. package/src/__tests__/task-runner.test.ts +0 -224
  1507. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  1508. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  1509. package/src/__tests__/tool-executor-shell-integration.test.ts +0 -354
  1510. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  1511. package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
  1512. package/src/__tests__/trust-store.test.ts +0 -2013
  1513. package/src/__tests__/v2-consent-policy.test.ts +0 -103
  1514. package/src/browser/identifiers.ts +0 -51
  1515. package/src/cli/db.ts +0 -1
  1516. package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
  1517. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
  1518. package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
  1519. package/src/context/__tests__/microcompact.test.ts +0 -805
  1520. package/src/context/microcompact.ts +0 -443
  1521. package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
  1522. package/src/daemon/approved-devices-store.ts +0 -110
  1523. package/src/daemon/external-skills-bootstrap.ts +0 -41
  1524. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  1525. package/src/daemon/message-types/trust.ts +0 -71
  1526. package/src/daemon/pairing-store.ts +0 -229
  1527. package/src/events/tool-notification-listener.ts +0 -17
  1528. package/src/ipc/cli-server.ts +0 -252
  1529. package/src/ipc/routes/attachment.ts +0 -114
  1530. package/src/ipc/routes/browser-context.ts +0 -63
  1531. package/src/ipc/routes/browser.ts +0 -97
  1532. package/src/ipc/routes/cache.ts +0 -96
  1533. package/src/ipc/routes/get-contact.ts +0 -16
  1534. package/src/ipc/routes/index.ts +0 -35
  1535. package/src/ipc/routes/list-clients.ts +0 -31
  1536. package/src/ipc/routes/merge-contacts.ts +0 -17
  1537. package/src/ipc/routes/notification.ts +0 -133
  1538. package/src/ipc/routes/rename-conversation.ts +0 -59
  1539. package/src/ipc/routes/search-contacts.ts +0 -19
  1540. package/src/ipc/routes/task-queue.ts +0 -226
  1541. package/src/ipc/routes/task.ts +0 -173
  1542. package/src/ipc/routes/upsert-contact.ts +0 -25
  1543. package/src/ipc/routes/wake-conversation.ts +0 -19
  1544. package/src/memory/db.ts +0 -23
  1545. package/src/permissions/arg-parser.test.ts +0 -161
  1546. package/src/permissions/arg-parser.ts +0 -141
  1547. package/src/permissions/bash-risk-classifier.test.ts +0 -1620
  1548. package/src/permissions/bash-risk-classifier.ts +0 -950
  1549. package/src/permissions/command-registry.test.ts +0 -774
  1550. package/src/permissions/command-registry.ts +0 -1005
  1551. package/src/permissions/defaults.ts +0 -314
  1552. package/src/permissions/file-risk-classifier.test.ts +0 -535
  1553. package/src/permissions/file-risk-classifier.ts +0 -274
  1554. package/src/permissions/permission-mode.ts +0 -24
  1555. package/src/permissions/schedule-risk-classifier.test.ts +0 -129
  1556. package/src/permissions/schedule-risk-classifier.ts +0 -85
  1557. package/src/permissions/shell-identity.ts +0 -297
  1558. package/src/permissions/skill-risk-classifier.test.ts +0 -311
  1559. package/src/permissions/skill-risk-classifier.ts +0 -214
  1560. package/src/permissions/trust-client.ts +0 -359
  1561. package/src/permissions/trust-store-interface.ts +0 -100
  1562. package/src/permissions/trust-store.ts +0 -1330
  1563. package/src/permissions/v2-consent-policy.ts +0 -87
  1564. package/src/permissions/web-risk-classifier.test.ts +0 -170
  1565. package/src/permissions/web-risk-classifier.ts +0 -89
  1566. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
  1567. package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
  1568. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  1569. package/src/runtime/__tests__/client-registry.test.ts +0 -293
  1570. package/src/runtime/actor-refresh-token-store.ts +0 -156
  1571. package/src/runtime/actor-token-store.ts +0 -207
  1572. package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
  1573. package/src/runtime/auth/credential-service.ts +0 -352
  1574. package/src/runtime/chrome-extension-registry.ts +0 -368
  1575. package/src/runtime/client-registry.ts +0 -261
  1576. package/src/runtime/conversation-approval-overrides.ts +0 -86
  1577. package/src/runtime/routes/browser-extension-pair-routes.ts +0 -575
  1578. package/src/runtime/routes/channel-routes.ts +0 -112
  1579. package/src/runtime/routes/contact-routes.test.ts +0 -298
  1580. package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
  1581. package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
  1582. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -336
  1583. package/src/runtime/routes/invite-routes.ts +0 -280
  1584. package/src/runtime/routes/pairing-routes.ts +0 -431
  1585. package/src/runtime/routes/playground/deps.ts +0 -56
  1586. package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
  1587. package/src/runtime/services/analyze-deps-singleton.ts +0 -32
  1588. package/src/tasks/ephemeral-permissions.ts +0 -55
  1589. package/src/tools/secret-detection-handler.ts +0 -359
  1590. package/src/tools/terminal/backends/native.ts +0 -327
  1591. package/src/tools/terminal/backends/types.ts +0 -37
  1592. package/src/tools/terminal/parser.ts +0 -623
  1593. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  1594. package/src/tools/terminal/sandbox.ts +0 -40
  1595. package/src/types/qrcode.d.ts +0 -13
  1596. package/src/util/network-info.ts +0 -55
  1597. /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
  1598. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  1599. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  1600. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  1601. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  1602. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  1603. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
@@ -1,2013 +0,0 @@
1
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { beforeEach, describe, expect, mock, test } from "bun:test";
4
-
5
- import { ruleScope } from "@vellumai/ces-contracts";
6
-
7
- // Create a temp directory for the trust file
8
- const testDir = process.env.VELLUM_WORKSPACE_DIR!;
9
-
10
- // Point the file-based trust backend at the test temp dir so
11
- // getGatewaySecurityDir() (which checks this env var first) writes
12
- // trust.json under the test directory instead of ~/.vellum/protected.
13
- process.env.GATEWAY_SECURITY_DIR = join(testDir, "protected");
14
-
15
- // Mock platform module so trust-store writes to temp dir instead of ~/.vellum
16
- // Mock logger to suppress output during tests
17
- mock.module("../util/logger.js", () => ({
18
- getLogger: () => ({
19
- info: () => {},
20
- warn: () => {},
21
- error: () => {},
22
- debug: () => {},
23
- trace: () => {},
24
- fatal: () => {},
25
- child: () => ({
26
- info: () => {},
27
- warn: () => {},
28
- error: () => {},
29
- debug: () => {},
30
- }),
31
- }),
32
- }));
33
-
34
- import { getDefaultRuleTemplates } from "../permissions/defaults.js";
35
- import {
36
- addRule,
37
- clearAllRules,
38
- clearCache,
39
- findDenyRule,
40
- findHighestPriorityRule,
41
- findMatchingRule,
42
- getAllRules,
43
- removeRule,
44
- updateRule,
45
- } from "../permissions/trust-store.js";
46
-
47
- const trustPath = join(testDir, "protected", "trust.json");
48
- const DEFAULT_TEMPLATES = getDefaultRuleTemplates();
49
- const NUM_DEFAULTS = DEFAULT_TEMPLATES.length;
50
- const DEFAULT_PRIORITY_BY_ID = new Map(
51
- DEFAULT_TEMPLATES.map((t) => [t.id, t.priority]),
52
- );
53
-
54
- describe("Trust Store", () => {
55
- beforeEach(() => {
56
- // Clear cached rules and remove the trust file between tests
57
- clearCache();
58
- try {
59
- rmSync(trustPath);
60
- } catch {
61
- /* may not exist */
62
- }
63
- });
64
-
65
- // Intentionally do not remove `testDir` in afterAll.
66
- // A late async log flush can still attempt to open `test.log` under this dir,
67
- // which intermittently causes an unhandled ENOENT in CI if the dir is removed.
68
- // ── addRule ─────────────────────────────────────────────────────
69
-
70
- describe("addRule", () => {
71
- test("adds a rule and returns it", () => {
72
- const rule = addRule("bash", "git *", "/home/user/project");
73
- expect(rule.id).toBeDefined();
74
- expect(rule.tool).toBe("bash");
75
- expect(rule.pattern).toBe("git *");
76
- expect(rule.scope).toBe("/home/user/project");
77
- expect(rule.decision).toBe("allow");
78
- expect(rule.priority).toBe(100);
79
- expect(rule.createdAt).toBeGreaterThan(0);
80
- });
81
-
82
- test("assigns unique IDs to each rule", () => {
83
- const rule1 = addRule("bash", "npm *", "/tmp");
84
- const rule2 = addRule("bash", "bun *", "/tmp");
85
- expect(rule1.id).not.toBe(rule2.id);
86
- });
87
-
88
- test("persists rule to disk", () => {
89
- addRule("bash", "git push", "/home/user");
90
- const raw = readFileSync(trustPath, "utf-8");
91
- const data = JSON.parse(raw);
92
- expect(data.version).toBe(3);
93
- expect(data.rules).toHaveLength(1 + NUM_DEFAULTS);
94
- const userRule = data.rules.find(
95
- (r: { pattern: string }) => r.pattern === "git push",
96
- );
97
- expect(userRule).toBeDefined();
98
- expect(userRule.priority).toBe(100);
99
- });
100
-
101
- test("multiple rules accumulate", () => {
102
- addRule("bash", "git *", "/tmp");
103
- addRule("file_write", "/tmp/*", "/tmp");
104
- addRule("bash", "npm *", "/tmp");
105
- expect(getAllRules()).toHaveLength(3 + NUM_DEFAULTS);
106
- });
107
-
108
- test("default priority is 100", () => {
109
- const rule = addRule("bash", "git *", "/tmp");
110
- expect(rule.priority).toBe(100);
111
- });
112
-
113
- test("custom priority is respected", () => {
114
- const rule = addRule("bash", "git *", "/tmp", "allow", 5);
115
- expect(rule.priority).toBe(5);
116
- });
117
-
118
- test("rules are sorted by priority descending in getAllRules", () => {
119
- addRule("bash", "low *", "/tmp", "allow", 0);
120
- addRule("bash", "high *", "/tmp", "allow", 2);
121
- addRule("bash", "med *", "/tmp", "allow", 1);
122
- const rules = getAllRules();
123
- // Default ask rules have higher priority than user rules
124
- const maxDefaultPriority = Math.max(
125
- ...DEFAULT_TEMPLATES.map((t) => t.priority),
126
- );
127
- expect(rules[0].priority).toBe(maxDefaultPriority);
128
- const userRules = rules.filter((r) => !r.id.startsWith("default:"));
129
- expect(userRules[0].priority).toBe(2);
130
- expect(userRules[1].priority).toBe(1);
131
- expect(userRules[2].priority).toBe(0);
132
- });
133
-
134
- test("allowHighRisk option is stripped during normalization", () => {
135
- // allowHighRisk is no longer persisted — the parser strips it.
136
- const rule = addRule("bash", "sudo *", "everywhere", "allow", 100);
137
- // Verify the field is not on the rule
138
- expect(
139
- (rule as unknown as Record<string, unknown>).allowHighRisk,
140
- ).toBeUndefined();
141
- });
142
-
143
- test("at same priority deny rules sort before allow rules", () => {
144
- addRule("bash", "allow *", "/tmp", "allow", 100);
145
- addRule("bash", "deny *", "/tmp", "deny", 100);
146
- const userRules = getAllRules().filter(
147
- (r) => !r.id.startsWith("default:"),
148
- );
149
- expect(userRules[0].decision).toBe("deny");
150
- expect(userRules[1].decision).toBe("allow");
151
- });
152
-
153
- test("accepts executionTarget option and persists it", () => {
154
- const rule = addRule("skill_tool", "skill_tool:*", "/tmp", "allow", 100, {
155
- executionTarget: "sandbox",
156
- });
157
- expect(rule.executionTarget).toBe("sandbox");
158
-
159
- // Verify persistence to disk
160
- clearCache();
161
- const rules = getAllRules();
162
- const found = rules.find((r) => r.id === rule.id);
163
- expect(found).toBeDefined();
164
- expect(found!.executionTarget).toBe("sandbox");
165
- });
166
-
167
- test("accepts executionTarget option (allowHighRisk no longer supported)", () => {
168
- const rule = addRule(
169
- "risky_tool",
170
- "risky_tool:*",
171
- "everywhere",
172
- "allow",
173
- 100,
174
- {
175
- executionTarget: "host",
176
- },
177
- );
178
- expect(rule.executionTarget).toBe("host");
179
-
180
- // Verify on disk — allowHighRisk should not appear
181
- const raw = JSON.parse(readFileSync(trustPath, "utf-8"));
182
- const diskRule = raw.rules.find((r: { id: string }) => r.id === rule.id);
183
- expect(diskRule).toBeDefined();
184
- expect(diskRule).not.toHaveProperty("allowHighRisk");
185
- expect(diskRule.executionTarget).toBe("host");
186
- });
187
-
188
- test("addRule without options does not set optional fields", () => {
189
- const rule = addRule("bash", "echo *", "/tmp");
190
- expect(rule.executionTarget).toBeUndefined();
191
-
192
- // Verify on disk
193
- const raw = JSON.parse(readFileSync(trustPath, "utf-8"));
194
- const diskRule = raw.rules.find((r: { id: string }) => r.id === rule.id);
195
- expect(diskRule).toBeDefined();
196
- expect(diskRule).not.toHaveProperty("executionTarget");
197
- });
198
- });
199
-
200
- // ── removeRule ──────────────────────────────────────────────────
201
-
202
- describe("removeRule", () => {
203
- test("removes an existing rule", () => {
204
- const rule = addRule("bash", "git *", "/tmp");
205
- expect(removeRule(rule.id)).toBe(true);
206
- expect(getAllRules()).toHaveLength(NUM_DEFAULTS);
207
- });
208
-
209
- test("returns false for non-existent ID", () => {
210
- expect(removeRule("non-existent-id")).toBe(false);
211
- });
212
-
213
- test("persists removal to disk", () => {
214
- const rule = addRule("bash", "npm *", "/tmp");
215
- removeRule(rule.id);
216
- // Reload from disk to verify
217
- clearCache();
218
- expect(getAllRules()).toHaveLength(NUM_DEFAULTS);
219
- });
220
-
221
- test("only removes the targeted rule", () => {
222
- const rule1 = addRule("bash", "git *", "/tmp");
223
- const rule2 = addRule("bash", "npm *", "/tmp");
224
- removeRule(rule1.id);
225
- const remaining = getAllRules();
226
- expect(remaining).toHaveLength(1 + NUM_DEFAULTS);
227
- expect(remaining.find((r) => r.id === rule2.id)).toBeDefined();
228
- });
229
- });
230
-
231
- // ── updateRule ─────────────────────────────────────────────────
232
-
233
- describe("updateRule", () => {
234
- test("updates pattern on an existing rule", () => {
235
- const rule = addRule("bash", "git *", "/tmp");
236
- const updated = updateRule(rule.id, { pattern: "git push *" });
237
- expect(updated.pattern).toBe("git push *");
238
- expect(updated.id).toBe(rule.id);
239
- expect(updated.tool).toBe("bash");
240
- });
241
-
242
- test("updates multiple fields at once", () => {
243
- const rule = addRule("bash", "npm *", "/tmp");
244
- const updated = updateRule(rule.id, {
245
- tool: "file_write",
246
- scope: "/home",
247
- decision: "deny",
248
- priority: 50,
249
- });
250
- expect(updated.tool).toBe("file_write");
251
- expect(updated.scope).toBe("/home");
252
- expect(updated.decision).toBe("deny");
253
- expect(updated.priority).toBe(50);
254
- });
255
-
256
- test("throws for non-existent rule ID", () => {
257
- expect(() => updateRule("non-existent-id", { pattern: "test" })).toThrow(
258
- "Trust rule not found: non-existent-id",
259
- );
260
- });
261
-
262
- test("persists update to disk", () => {
263
- const rule = addRule("bash", "git *", "/tmp");
264
- updateRule(rule.id, { pattern: "git status" });
265
- clearCache();
266
- const rules = getAllRules();
267
- const found = rules.find((r) => r.id === rule.id);
268
- expect(found).toBeDefined();
269
- expect(found!.pattern).toBe("git status");
270
- });
271
-
272
- test("re-sorts rules after priority change", () => {
273
- const rule1 = addRule("bash", "low *", "/tmp", "allow", 10);
274
- const rule2 = addRule("bash", "high *", "/tmp", "allow", 200);
275
- // rule2 should be first (higher priority)
276
- let userRules = getAllRules().filter((r) => !r.id.startsWith("default:"));
277
- expect(userRules[0].id).toBe(rule2.id);
278
- // Update rule1 to have higher priority
279
- updateRule(rule1.id, { priority: 300 });
280
- userRules = getAllRules().filter((r) => !r.id.startsWith("default:"));
281
- expect(userRules[0].id).toBe(rule1.id);
282
- });
283
-
284
- test("leaves unchanged fields intact", () => {
285
- const rule = addRule("bash", "git *", "/home/user", "allow", 100);
286
- updateRule(rule.id, { pattern: "git push *" });
287
- const updated = getAllRules().find((r) => r.id === rule.id)!;
288
- expect(updated.tool).toBe("bash");
289
- expect(updated.scope).toBe("/home/user");
290
- expect(updated.decision).toBe("allow");
291
- expect(updated.priority).toBe(100);
292
- expect(updated.createdAt).toBe(rule.createdAt);
293
- });
294
-
295
- test("does not set userModifiedAt on non-default rules", () => {
296
- const rule = addRule("bash", "git *", "/tmp");
297
- const updated = updateRule(rule.id, { decision: "deny" });
298
- expect(updated.userModifiedAt).toBeUndefined();
299
- });
300
-
301
- test("sets userModifiedAt when updating a default rule", () => {
302
- const before = Date.now();
303
- const updated = updateRule("default:ask-host_bash-global", {
304
- decision: "allow",
305
- });
306
- expect(updated.userModifiedAt).toBeGreaterThanOrEqual(before);
307
- expect(updated.userModifiedAt).toBeLessThanOrEqual(Date.now());
308
- });
309
-
310
- test("persists userModifiedAt to disk for default rules", () => {
311
- updateRule("default:ask-host_bash-global", { decision: "allow" });
312
- clearCache();
313
- const rules = getAllRules();
314
- const found = rules.find((r) => r.id === "default:ask-host_bash-global");
315
- expect(found).toBeDefined();
316
- expect(found!.userModifiedAt).toBeGreaterThan(0);
317
- });
318
-
319
- test("does not set userModifiedAt on no-op default rule update", () => {
320
- // Updating a default rule with values identical to the template
321
- // should NOT set userModifiedAt — the rule hasn't actually diverged.
322
- const updated = updateRule("default:ask-host_bash-global", {
323
- decision: "ask",
324
- });
325
- expect(updated.userModifiedAt).toBeUndefined();
326
- });
327
-
328
- test("clears userModifiedAt when default rule is reset to template values", () => {
329
- // First, modify the rule to diverge from the template
330
- updateRule("default:ask-host_bash-global", { decision: "allow" });
331
- let found = getAllRules().find(
332
- (r) => r.id === "default:ask-host_bash-global",
333
- )!;
334
- expect(found.userModifiedAt).toBeGreaterThan(0);
335
-
336
- // Now reset it back to the template value
337
- updateRule("default:ask-host_bash-global", { decision: "ask" });
338
- found = getAllRules().find(
339
- (r) => r.id === "default:ask-host_bash-global",
340
- )!;
341
- // userModifiedAt should be cleared since rule matches template again
342
- expect(found.userModifiedAt).toBeUndefined();
343
- });
344
- });
345
-
346
- // ── findMatchingRule ────────────────────────────────────────────
347
-
348
- describe("findMatchingRule", () => {
349
- test("finds exact match", () => {
350
- addRule("bash", "git push", "/tmp");
351
- const match = findMatchingRule("bash", "git push", "/tmp");
352
- expect(match).not.toBeNull();
353
- expect(match!.pattern).toBe("git push");
354
- });
355
-
356
- test("finds glob wildcard match", () => {
357
- addRule("bash", "git *", "/tmp");
358
- const match = findMatchingRule("bash", "git push origin main", "/tmp");
359
- expect(match).not.toBeNull();
360
- });
361
-
362
- test("returns null when tool does not match", () => {
363
- addRule("file_write", "file_write:/tmp/*", "/tmp");
364
- // host_file_read default is 'ask' so findMatchingRule (allow-only) won't find it
365
- const match = findMatchingRule(
366
- "host_file_read",
367
- "host_file_read:/etc/hosts",
368
- "/tmp",
369
- );
370
- expect(match).toBeNull();
371
- });
372
-
373
- test("returns null when pattern does not match", () => {
374
- addRule("host_file_read", "host_file_read:/etc/hosts", "/tmp");
375
- const match = findMatchingRule(
376
- "host_file_read",
377
- "host_file_read:/var/log/syslog",
378
- "/tmp",
379
- );
380
- expect(match).toBeNull();
381
- });
382
-
383
- // Scope matching
384
- describe("scope matching", () => {
385
- test("matches when scope equals rule scope", () => {
386
- addRule("bash", "npm *", "/home/user/project");
387
- const match = findMatchingRule(
388
- "bash",
389
- "npm install",
390
- "/home/user/project",
391
- );
392
- expect(match).not.toBeNull();
393
- });
394
-
395
- test("matches when scope is under rule scope (prefix)", () => {
396
- addRule("bash", "npm *", "/home/user");
397
- const match = findMatchingRule(
398
- "bash",
399
- "npm install",
400
- "/home/user/project/sub",
401
- );
402
- expect(match).not.toBeNull();
403
- });
404
-
405
- test("does not match when scope is outside rule scope", () => {
406
- addRule(
407
- "host_file_read",
408
- "host_file_read:/home/user/project/*",
409
- "/home/user/project",
410
- );
411
- const match = findMatchingRule(
412
- "host_file_read",
413
- "host_file_read:/home/user/project/file.txt",
414
- "/home/other",
415
- );
416
- expect(match).toBeNull();
417
- });
418
-
419
- test("everywhere scope matches any directory", () => {
420
- addRule("bash", "git *", "everywhere");
421
- const match = findMatchingRule(
422
- "bash",
423
- "git status",
424
- "/any/random/path",
425
- );
426
- expect(match).not.toBeNull();
427
- });
428
-
429
- test("everywhere scope matches root", () => {
430
- addRule("bash", "ls", "everywhere");
431
- const match = findMatchingRule("bash", "ls", "/");
432
- expect(match).not.toBeNull();
433
- });
434
-
435
- test("does not match sibling path with shared prefix", () => {
436
- addRule(
437
- "host_file_read",
438
- "host_file_read:/home/user/project/*",
439
- "/home/user/project",
440
- );
441
- const match = findMatchingRule(
442
- "host_file_read",
443
- "host_file_read:/home/user/project/file.txt",
444
- "/home/user/project-evil",
445
- );
446
- expect(match).toBeNull();
447
- });
448
-
449
- test("matches exact scope with trailing slash on working dir", () => {
450
- addRule("bash", "npm *", "/home/user/project");
451
- const match = findMatchingRule(
452
- "bash",
453
- "npm install",
454
- "/home/user/project/",
455
- );
456
- expect(match).not.toBeNull();
457
- });
458
-
459
- test("matches when rule scope has trailing slash", () => {
460
- addRule("bash", "npm *", "/home/user/project/");
461
- const match = findMatchingRule(
462
- "bash",
463
- "npm install",
464
- "/home/user/project",
465
- );
466
- expect(match).not.toBeNull();
467
- });
468
-
469
- test("does not match sibling with glob-suffixed scope", () => {
470
- addRule(
471
- "host_file_read",
472
- "host_file_read:/home/user/project/*",
473
- "/home/user/project*",
474
- );
475
- const match = findMatchingRule(
476
- "host_file_read",
477
- "host_file_read:/home/user/project/file.txt",
478
- "/home/user/project-evil",
479
- );
480
- expect(match).toBeNull();
481
- });
482
- });
483
-
484
- // Pattern matching with minimatch
485
- describe("pattern matching", () => {
486
- test("matches * wildcard", () => {
487
- addRule("bash", "npm *", "/tmp");
488
- expect(findMatchingRule("bash", "npm install", "/tmp")).not.toBeNull();
489
- expect(findMatchingRule("bash", "npm test", "/tmp")).not.toBeNull();
490
- });
491
-
492
- test("matches exact string", () => {
493
- addRule("host_file_read", "host_file_read:/etc/hosts", "/tmp");
494
- expect(
495
- findMatchingRule(
496
- "host_file_read",
497
- "host_file_read:/etc/hosts",
498
- "/tmp",
499
- ),
500
- ).not.toBeNull();
501
- expect(
502
- findMatchingRule(
503
- "host_file_read",
504
- "host_file_read:/etc/passwd",
505
- "/tmp",
506
- ),
507
- ).toBeNull();
508
- });
509
-
510
- test("matches file path pattern", () => {
511
- addRule("file_write", "/tmp/*", "/tmp");
512
- expect(
513
- findMatchingRule("file_write", "/tmp/file.txt", "/tmp"),
514
- ).not.toBeNull();
515
- });
516
-
517
- test("star pattern matches single-segment strings", () => {
518
- addRule("file_write", "*", "/tmp");
519
- // minimatch '*' matches strings without path separators
520
- expect(
521
- findMatchingRule("file_write", "file.txt", "/tmp"),
522
- ).not.toBeNull();
523
- });
524
-
525
- test("star pattern does not match paths with slashes", () => {
526
- addRule("file_write", "*", "/tmp");
527
- // minimatch '*' does not cross '/' boundaries
528
- expect(
529
- findMatchingRule("file_write", "/any/path/file.txt", "/tmp"),
530
- ).toBeNull();
531
- });
532
- });
533
- });
534
-
535
- // ── findHighestPriorityRule ──────────────────────────────────────
536
-
537
- describe("findHighestPriorityRule", () => {
538
- test("returns highest priority matching rule", () => {
539
- addRule("bash", "rm *", "/tmp", "allow", 0);
540
- addRule("bash", "rm *", "/tmp", "deny", 100);
541
- const match = findHighestPriorityRule("bash", ["rm file.txt"], "/tmp");
542
- expect(match).not.toBeNull();
543
- expect(match!.decision).toBe("deny");
544
- expect(match!.priority).toBe(100);
545
- });
546
-
547
- test("higher priority allow beats lower priority deny", () => {
548
- addRule("bash", "rm *", "/tmp", "deny", 0);
549
- addRule("bash", "rm *", "/tmp", "allow", 100);
550
- const match = findHighestPriorityRule("bash", ["rm file.txt"], "/tmp");
551
- expect(match).not.toBeNull();
552
- expect(match!.decision).toBe("allow");
553
- });
554
-
555
- test("same priority: deny beats allow", () => {
556
- addRule("bash", "rm *", "/tmp", "allow", 100);
557
- addRule("bash", "rm *", "/tmp", "deny", 100);
558
- const match = findHighestPriorityRule("bash", ["rm file.txt"], "/tmp");
559
- expect(match).not.toBeNull();
560
- expect(match!.decision).toBe("deny");
561
- });
562
-
563
- test("checks multiple command candidates", () => {
564
- addRule("web_fetch", "web_fetch:https://example.com/*", "/tmp", "allow");
565
- const match = findHighestPriorityRule(
566
- "web_fetch",
567
- [
568
- "web_fetch:https://example.com/page",
569
- "web_fetch:https://example.com/*",
570
- ],
571
- "/tmp",
572
- );
573
- expect(match).not.toBeNull();
574
- });
575
-
576
- test("returns null when no rule matches", () => {
577
- // Use file_read with a non-workspace path — file_read defaults only
578
- // cover specific workspace files, so /tmp paths won't match any default.
579
- addRule("file_read", "file_read:/specific/*", "/tmp", "allow");
580
- const match = findHighestPriorityRule(
581
- "file_read",
582
- ["file_read:/other/path"],
583
- "/tmp",
584
- );
585
- expect(match).toBeNull();
586
- });
587
-
588
- test("respects scope matching", () => {
589
- // Use file_read — bash has a global default allow rule that matches everywhere.
590
- addRule(
591
- "file_read",
592
- "file_read:/home/user/project/*",
593
- "/home/user/project",
594
- "deny",
595
- );
596
- expect(
597
- findHighestPriorityRule(
598
- "file_read",
599
- ["file_read:/home/user/project/file.txt"],
600
- "/home/user/project/sub",
601
- ),
602
- ).not.toBeNull();
603
- expect(
604
- findHighestPriorityRule(
605
- "file_read",
606
- ["file_read:/home/user/project/file.txt"],
607
- "/home/other",
608
- ),
609
- ).toBeNull();
610
- });
611
-
612
- test("everywhere scope matches any directory", () => {
613
- addRule("bash", "git *", "everywhere", "allow");
614
- const match = findHighestPriorityRule(
615
- "bash",
616
- ["git status"],
617
- "/any/random/path",
618
- );
619
- expect(match).not.toBeNull();
620
- });
621
- });
622
-
623
- // ── getAllRules ─────────────────────────────────────────────────
624
-
625
- describe("getAllRules", () => {
626
- test("returns default rules when no user rules exist", () => {
627
- const rules = getAllRules();
628
- expect(rules).toHaveLength(NUM_DEFAULTS);
629
- expect(rules.every((r) => r.id.startsWith("default:"))).toBe(true);
630
- });
631
-
632
- test("returns a copy (not the internal array)", () => {
633
- addRule("bash", "git *", "/tmp");
634
- const rules1 = getAllRules();
635
- const rules2 = getAllRules();
636
- expect(rules1).toEqual(rules2);
637
- expect(rules1).not.toBe(rules2); // different references
638
- });
639
- });
640
-
641
- // ── clearCache ─────────────────────────────────────────────────
642
-
643
- describe("clearCache", () => {
644
- test("forces reload from disk on next access", () => {
645
- addRule("bash", "git *", "/tmp");
646
- expect(getAllRules()).toHaveLength(1 + NUM_DEFAULTS);
647
- clearCache();
648
- // After clearing cache, rules are reloaded from disk
649
- expect(getAllRules()).toHaveLength(1 + NUM_DEFAULTS);
650
- });
651
- });
652
-
653
- // ── persistence ─────────────────────────────────────────────────
654
-
655
- describe("persistence", () => {
656
- test("rules survive cache clear (loaded from disk)", () => {
657
- const rule = addRule("bash", "npm *", "/tmp");
658
- clearCache();
659
- const rules = getAllRules();
660
- expect(rules).toHaveLength(1 + NUM_DEFAULTS);
661
- expect(rules.find((r) => r.id === rule.id)).toBeDefined();
662
- });
663
-
664
- test("trust file has correct structure", () => {
665
- addRule("bash", "git *", "/tmp");
666
- const data = JSON.parse(readFileSync(trustPath, "utf-8"));
667
- expect(data).toHaveProperty("version", 3);
668
- expect(data).toHaveProperty("rules");
669
- expect(Array.isArray(data.rules)).toBe(true);
670
- const userRule = data.rules.find(
671
- (r: { pattern: string }) => r.pattern === "git *",
672
- );
673
- expect(userRule).toHaveProperty("priority", 100);
674
- });
675
- });
676
-
677
- // ── deny rules ─────────────────────────────────────────────────
678
-
679
- describe("deny rules", () => {
680
- test("addRule with deny decision creates a deny rule", () => {
681
- const rule = addRule("bash", "rm -rf *", "/tmp", "deny");
682
- expect(rule.decision).toBe("deny");
683
- expect(rule.tool).toBe("bash");
684
- expect(rule.pattern).toBe("rm -rf *");
685
- });
686
-
687
- test("deny rule persists to disk", () => {
688
- addRule("bash", "rm *", "/tmp", "deny");
689
- clearCache();
690
- const rules = getAllRules();
691
- expect(rules).toHaveLength(1 + NUM_DEFAULTS);
692
- const userRule = rules.find((r) => r.pattern === "rm *");
693
- expect(userRule).toBeDefined();
694
- expect(userRule!.decision).toBe("deny");
695
- });
696
-
697
- test("findDenyRule finds deny rules", () => {
698
- addRule("bash", "rm *", "/tmp", "deny");
699
- const match = findDenyRule("bash", "rm file.txt", "/tmp");
700
- expect(match).not.toBeNull();
701
- expect(match!.decision).toBe("deny");
702
- });
703
-
704
- test("findDenyRule ignores allow rules", () => {
705
- addRule("bash", "rm *", "/tmp", "allow");
706
- const match = findDenyRule("bash", "rm file.txt", "/tmp");
707
- expect(match).toBeNull();
708
- });
709
-
710
- test("findMatchingRule ignores deny rules", () => {
711
- // Use host_file_read — it has an 'ask' default so findMatchingRule (allow-only) won't find it.
712
- addRule("host_file_read", "host_file_read:/etc/*", "/tmp", "deny");
713
- const match = findMatchingRule(
714
- "host_file_read",
715
- "host_file_read:/etc/hosts",
716
- "/tmp",
717
- );
718
- expect(match).toBeNull();
719
- });
720
-
721
- test("deny and allow rules coexist", () => {
722
- addRule("bash", "git *", "/tmp", "allow");
723
- addRule("bash", "git push --force *", "/tmp", "deny");
724
- expect(findMatchingRule("bash", "git status", "/tmp")).not.toBeNull();
725
- expect(
726
- findDenyRule("bash", "git push --force origin", "/tmp"),
727
- ).not.toBeNull();
728
- });
729
-
730
- test("deny rule with scope matching", () => {
731
- addRule("bash", "rm *", "/home/user/project", "deny");
732
- expect(
733
- findDenyRule("bash", "rm file.txt", "/home/user/project/sub"),
734
- ).not.toBeNull();
735
- expect(findDenyRule("bash", "rm file.txt", "/home/other")).toBeNull();
736
- });
737
-
738
- test("deny rule with everywhere scope", () => {
739
- addRule("bash", "rm -rf *", "everywhere", "deny");
740
- expect(findDenyRule("bash", "rm -rf /", "/any/path")).not.toBeNull();
741
- });
742
-
743
- test("removeRule works for deny rules", () => {
744
- const rule = addRule("bash", "rm *", "/tmp", "deny");
745
- expect(removeRule(rule.id)).toBe(true);
746
- expect(findDenyRule("bash", "rm file.txt", "/tmp")).toBeNull();
747
- });
748
- });
749
-
750
- // ── default rules ─────────────────────────────────────────────
751
-
752
- describe("default rules", () => {
753
- test("backfills default rules on first load", () => {
754
- const rules = getAllRules();
755
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
756
- expect(defaults).toHaveLength(NUM_DEFAULTS);
757
- for (const rule of defaults) {
758
- expect(rule.priority).toBe(DEFAULT_PRIORITY_BY_ID.get(rule.id)!);
759
- if (
760
- rule.id === "default:allow-bash-rm-bootstrap" ||
761
- rule.id === "default:allow-bash-rm-updates"
762
- ) {
763
- expect(ruleScope(rule)).toBe(testDir);
764
- } else {
765
- // Non-scoped tool families (managed skill tools, skill_load) no
766
- // longer carry an explicit scope field after normalization, but
767
- // ruleScope() returns "everywhere" for rules without scope.
768
- expect(ruleScope(rule)).toBe("everywhere");
769
- }
770
- }
771
- });
772
-
773
- test("default rules cover file, host file, host shell, and workspace prompt tools", () => {
774
- const rules = getAllRules();
775
- const defaultTools = [
776
- ...new Set(
777
- rules.filter((r) => r.id.startsWith("default:")).map((r) => r.tool),
778
- ),
779
- ].sort();
780
- expect(defaultTools).toEqual([
781
- "bash",
782
- "computer_use_click",
783
- "computer_use_drag",
784
- "computer_use_key",
785
- "computer_use_observe",
786
- "computer_use_open_app",
787
- "computer_use_run_applescript",
788
- "computer_use_scroll",
789
- "computer_use_type_text",
790
- "computer_use_wait",
791
- "delete_managed_skill",
792
- "file_edit",
793
- "file_read",
794
- "file_write",
795
- "host_bash",
796
- "host_file_edit",
797
- "host_file_read",
798
- "host_file_write",
799
- "recall",
800
- "scaffold_managed_skill",
801
- "skill_execute",
802
- "skill_load",
803
- "ui_dismiss",
804
- "ui_show",
805
- "ui_update",
806
- ]);
807
- });
808
-
809
- test("default rules are not duplicated on reload", () => {
810
- getAllRules(); // first load
811
- clearCache();
812
- const rules = getAllRules(); // second load
813
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
814
- expect(defaults).toHaveLength(NUM_DEFAULTS);
815
- });
816
-
817
- test("default rules persist to disk", () => {
818
- getAllRules(); // triggers backfill + save
819
- const data = JSON.parse(readFileSync(trustPath, "utf-8"));
820
- const defaults = data.rules.filter((r: { id: string }) =>
821
- r.id.startsWith("default:"),
822
- );
823
- expect(defaults).toHaveLength(NUM_DEFAULTS);
824
- });
825
-
826
- test("removed default rule is re-backfilled on next load", () => {
827
- // First load backfills defaults
828
- getAllRules();
829
- // Remove one default rule by editing trust.json directly on disk
830
- // (removeRule() throws for default rules, so we simulate external editing)
831
- const raw = JSON.parse(readFileSync(trustPath, "utf-8"));
832
- raw.rules = raw.rules.filter(
833
- (r: { id: string }) => r.id !== "default:ask-host_file_read-global",
834
- );
835
- writeFileSync(trustPath, JSON.stringify(raw, null, 2));
836
- // After reload, the rule is re-backfilled (defaults are always present)
837
- clearCache();
838
- const rules = getAllRules();
839
- expect(
840
- rules.find((r) => r.id === "default:ask-host_file_read-global"),
841
- ).toBeDefined();
842
- });
843
-
844
- test("findHighestPriorityRule matches default ask for host_file_read", () => {
845
- const match = findHighestPriorityRule(
846
- "host_file_read",
847
- ["host_file_read:/etc/hosts"],
848
- "/tmp",
849
- );
850
- expect(match).not.toBeNull();
851
- expect(match!.id).toBe("default:ask-host_file_read-global");
852
- expect(match!.decision).toBe("ask");
853
- expect(match!.priority).toBe(
854
- DEFAULT_PRIORITY_BY_ID.get("default:ask-host_file_read-global")!,
855
- );
856
- });
857
-
858
- test("findHighestPriorityRule matches default ask for host_file_write", () => {
859
- const match = findHighestPriorityRule(
860
- "host_file_write",
861
- ["host_file_write:/etc/hosts"],
862
- "/tmp",
863
- );
864
- expect(match).not.toBeNull();
865
- expect(match!.id).toBe("default:ask-host_file_write-global");
866
- expect(match!.decision).toBe("ask");
867
- expect(match!.priority).toBe(
868
- DEFAULT_PRIORITY_BY_ID.get("default:ask-host_file_write-global")!,
869
- );
870
- });
871
-
872
- test("findHighestPriorityRule matches default ask for host_file_edit", () => {
873
- const match = findHighestPriorityRule(
874
- "host_file_edit",
875
- ["host_file_edit:/etc/hosts"],
876
- "/tmp",
877
- );
878
- expect(match).not.toBeNull();
879
- expect(match!.id).toBe("default:ask-host_file_edit-global");
880
- expect(match!.decision).toBe("ask");
881
- expect(match!.priority).toBe(
882
- DEFAULT_PRIORITY_BY_ID.get("default:ask-host_file_edit-global")!,
883
- );
884
- });
885
-
886
- test("findHighestPriorityRule matches default ask for host_bash", () => {
887
- const match = findHighestPriorityRule("host_bash", ["ls"], "/tmp");
888
- expect(match).not.toBeNull();
889
- expect(match!.id).toBe("default:ask-host_bash-global");
890
- expect(match!.decision).toBe("ask");
891
- expect(match!.priority).toBe(
892
- DEFAULT_PRIORITY_BY_ID.get("default:ask-host_bash-global")!,
893
- );
894
- });
895
-
896
- test("findHighestPriorityRule matches default ask for computer_use_click", () => {
897
- const match = findHighestPriorityRule(
898
- "computer_use_click",
899
- ["computer_use_click:"],
900
- "/tmp",
901
- );
902
- expect(match).not.toBeNull();
903
- expect(match!.id).toBe("default:ask-computer_use_click-global");
904
- expect(match!.decision).toBe("ask");
905
- expect(match!.priority).toBe(
906
- DEFAULT_PRIORITY_BY_ID.get("default:ask-computer_use_click-global")!,
907
- );
908
- });
909
-
910
- test("findHighestPriorityRule matches default ask for computer_use_observe", () => {
911
- const match = findHighestPriorityRule(
912
- "computer_use_observe",
913
- ["computer_use_observe:"],
914
- "/tmp",
915
- );
916
- expect(match).not.toBeNull();
917
- expect(match!.id).toBe("default:ask-computer_use_observe-global");
918
- expect(match!.decision).toBe("ask");
919
- expect(match!.priority).toBe(
920
- DEFAULT_PRIORITY_BY_ID.get("default:ask-computer_use_observe-global")!,
921
- );
922
- });
923
-
924
- test("bootstrap delete rule matches only when workingDir is the workspace dir", () => {
925
- const workspaceDir = testDir;
926
- // Should match when workingDir is the workspace directory — the bootstrap
927
- // rule (priority 100) outranks the global default allow (priority 50).
928
- const match = findHighestPriorityRule(
929
- "bash",
930
- ["rm BOOTSTRAP.md"],
931
- workspaceDir,
932
- );
933
- expect(match).not.toBeNull();
934
- expect(match!.id).toBe("default:allow-bash-rm-bootstrap");
935
- expect(match!.decision).toBe("allow");
936
- // Outside workspace, the bootstrap rule doesn't match — without
937
- // IS_CONTAINERIZED there is no catch-all bash allow rule either.
938
- const other = findHighestPriorityRule(
939
- "bash",
940
- ["rm BOOTSTRAP.md"],
941
- "/tmp/other-project",
942
- );
943
- expect(other).toBeNull();
944
- });
945
-
946
- test("updates delete rule matches only when workingDir is the workspace dir", () => {
947
- const workspaceDir = testDir;
948
- const match = findHighestPriorityRule(
949
- "bash",
950
- ["rm UPDATES.md"],
951
- workspaceDir,
952
- );
953
- expect(match).not.toBeNull();
954
- expect(match!.id).toBe("default:allow-bash-rm-updates");
955
- expect(match!.decision).toBe("allow");
956
- // Outside workspace, should NOT match the updates rule — without
957
- // IS_CONTAINERIZED there is no catch-all bash allow rule either.
958
- const other = findHighestPriorityRule(
959
- "bash",
960
- ["rm UPDATES.md"],
961
- "/tmp/other-project",
962
- );
963
- expect(other).toBeNull();
964
- });
965
-
966
- test("default ask does not affect files outside protected directory", () => {
967
- const safePath = join(testDir, "data", "assistant.db");
968
- const match = findHighestPriorityRule(
969
- "file_read",
970
- [`file_read:${safePath}`],
971
- "/tmp",
972
- );
973
- // Should not match a default deny rule
974
- expect(match == null || !match.id.startsWith("default:")).toBe(true);
975
- });
976
-
977
- test("default rules are backfilled after malformed JSON in trust file", () => {
978
- mkdirSync(dirname(trustPath), { recursive: true });
979
- writeFileSync(trustPath, "NOT VALID JSON {{{");
980
- clearCache();
981
- const rules = getAllRules();
982
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
983
- expect(defaults).toHaveLength(NUM_DEFAULTS);
984
- });
985
-
986
- test("default rules are backfilled in-memory after unknown file version without overwriting disk", () => {
987
- mkdirSync(dirname(trustPath), { recursive: true });
988
- const originalContent = JSON.stringify({
989
- version: 9999,
990
- rules: [
991
- {
992
- id: "future-rule",
993
- tool: "bash",
994
- pattern: "future *",
995
- scope: "everywhere",
996
- decision: "allow",
997
- priority: 50,
998
- createdAt: 1000,
999
- },
1000
- ],
1001
- });
1002
- writeFileSync(trustPath, originalContent);
1003
- clearCache();
1004
- const rules = getAllRules();
1005
- // Defaults should be present in-memory
1006
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
1007
- expect(defaults).toHaveLength(NUM_DEFAULTS);
1008
- // The on-disk file must NOT be overwritten — it preserves the unknown format
1009
- const diskContent = readFileSync(trustPath, "utf-8");
1010
- expect(diskContent).toBe(originalContent);
1011
- });
1012
-
1013
- test("clearAllRules preserves default rules", () => {
1014
- addRule("bash", "git *", "/tmp");
1015
- clearAllRules();
1016
- const rules = getAllRules();
1017
- // User rules should be gone, but defaults should remain
1018
- expect(rules.filter((r) => !r.id.startsWith("default:"))).toHaveLength(0);
1019
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
1020
- expect(defaults).toHaveLength(NUM_DEFAULTS);
1021
- });
1022
-
1023
- // ── skill source mutation rules ────────────────────────────────
1024
-
1025
- test("default rules include ask rules for file_write on skill source paths", () => {
1026
- const rules = getAllRules();
1027
- const managed = rules.find(
1028
- (r) => r.id === "default:ask-file_write-managed-skills",
1029
- );
1030
- expect(managed).toBeDefined();
1031
- expect(managed!.tool).toBe("file_write");
1032
- expect(managed!.decision).toBe("ask");
1033
- expect(managed!.priority).toBe(50);
1034
- expect(managed!.pattern).toContain("skills/**");
1035
-
1036
- const bundled = rules.find(
1037
- (r) => r.id === "default:ask-file_write-bundled-skills",
1038
- );
1039
- expect(bundled).toBeDefined();
1040
- expect(bundled!.tool).toBe("file_write");
1041
- expect(bundled!.decision).toBe("ask");
1042
- expect(bundled!.priority).toBe(50);
1043
- });
1044
-
1045
- test("default rules include ask rules for file_edit on skill source paths", () => {
1046
- const rules = getAllRules();
1047
- const managed = rules.find(
1048
- (r) => r.id === "default:ask-file_edit-managed-skills",
1049
- );
1050
- expect(managed).toBeDefined();
1051
- expect(managed!.tool).toBe("file_edit");
1052
- expect(managed!.decision).toBe("ask");
1053
- expect(managed!.priority).toBe(50);
1054
- expect(managed!.pattern).toContain("skills/**");
1055
-
1056
- const bundled = rules.find(
1057
- (r) => r.id === "default:ask-file_edit-bundled-skills",
1058
- );
1059
- expect(bundled).toBeDefined();
1060
- expect(bundled!.tool).toBe("file_edit");
1061
- expect(bundled!.decision).toBe("ask");
1062
- expect(bundled!.priority).toBe(50);
1063
- });
1064
-
1065
- // ── default allow: skill_load ────────────────────────────────
1066
-
1067
- test("skill_load default allow rule exists in templates", () => {
1068
- const templates = getDefaultRuleTemplates();
1069
- const skillLoadRule = templates.find(
1070
- (t) => t.id === "default:allow-skill_load-global",
1071
- );
1072
- expect(skillLoadRule).toBeDefined();
1073
- expect(skillLoadRule!.tool).toBe("skill_load");
1074
- expect(skillLoadRule!.pattern).toBe("skill_load:*");
1075
- expect(skillLoadRule!.decision).toBe("allow");
1076
- // skill_load is a non-scoped tool — template omits scope
1077
- expect(skillLoadRule!.scope).toBeUndefined();
1078
- });
1079
-
1080
- test("findHighestPriorityRule matches default allow for skill_load", () => {
1081
- const match = findHighestPriorityRule(
1082
- "skill_load",
1083
- ["skill_load:browser"],
1084
- "/tmp",
1085
- );
1086
- expect(match).not.toBeNull();
1087
- expect(match!.id).toBe("default:allow-skill_load-global");
1088
- expect(match!.decision).toBe("allow");
1089
- expect(match!.priority).toBe(100);
1090
- });
1091
-
1092
- test("findHighestPriorityRule matches default allow for skill_load with any skill name", () => {
1093
- const match = findHighestPriorityRule(
1094
- "skill_load",
1095
- ["skill_load:some-random-skill"],
1096
- "/tmp",
1097
- );
1098
- expect(match).not.toBeNull();
1099
- expect(match!.id).toBe("default:allow-skill_load-global");
1100
- expect(match!.decision).toBe("allow");
1101
- });
1102
-
1103
- test("no default ask rules exist for file_read on skill source paths", () => {
1104
- const rules = getAllRules();
1105
- // There should be no default rules with IDs matching file_read for skill sources
1106
- const readManagedSkill = rules.find(
1107
- (r) => r.id === "default:ask-file_read-managed-skills",
1108
- );
1109
- const readBundledSkill = rules.find(
1110
- (r) => r.id === "default:ask-file_read-bundled-skills",
1111
- );
1112
- expect(readManagedSkill).toBeUndefined();
1113
- expect(readBundledSkill).toBeUndefined();
1114
- });
1115
-
1116
- test("findHighestPriorityRule matches default ask for file_write on managed skill path", () => {
1117
- const skillFile = join(testDir, "skills", "my-skill", "SKILL.md");
1118
- const match = findHighestPriorityRule(
1119
- "file_write",
1120
- [`file_write:${skillFile}`],
1121
- "/tmp",
1122
- );
1123
- expect(match).not.toBeNull();
1124
- expect(match!.id).toBe("default:ask-file_write-managed-skills");
1125
- expect(match!.decision).toBe("ask");
1126
- });
1127
-
1128
- test("findHighestPriorityRule matches default ask for file_edit on managed skill path", () => {
1129
- const skillFile = join(testDir, "skills", "my-skill", "tools.ts");
1130
- const match = findHighestPriorityRule(
1131
- "file_edit",
1132
- [`file_edit:${skillFile}`],
1133
- "/tmp",
1134
- );
1135
- expect(match).not.toBeNull();
1136
- expect(match!.id).toBe("default:ask-file_edit-managed-skills");
1137
- expect(match!.decision).toBe("ask");
1138
- });
1139
-
1140
- // ── userModifiedAt and backfill migration ──────────────────────
1141
-
1142
- test("default rules without userModifiedAt are migrated when template changes", () => {
1143
- // First load backfills defaults
1144
- getAllRules();
1145
- // Manually alter a default rule on disk to simulate a template change
1146
- // (the rule on disk has old values, template has new ones)
1147
- const raw = JSON.parse(readFileSync(trustPath, "utf-8"));
1148
- const idx = raw.rules.findIndex(
1149
- (r: { id: string }) => r.id === "default:ask-host_bash-global",
1150
- );
1151
- expect(idx).toBeGreaterThanOrEqual(0);
1152
- // Manually set an old priority to simulate the rule diverging from template
1153
- raw.rules[idx].priority = 9999;
1154
- writeFileSync(trustPath, JSON.stringify(raw, null, 2));
1155
- clearCache();
1156
- const rules = getAllRules();
1157
- const found = rules.find((r) => r.id === "default:ask-host_bash-global");
1158
- expect(found).toBeDefined();
1159
- // Should be migrated back to the template priority (50)
1160
- expect(found!.priority).toBe(50);
1161
- });
1162
-
1163
- test("default rules with userModifiedAt are preserved during backfill migration", () => {
1164
- // First load backfills defaults
1165
- getAllRules();
1166
- // Modify the rule via updateRule to set userModifiedAt
1167
- updateRule("default:ask-host_bash-global", { decision: "allow" });
1168
- // Verify userModifiedAt is set
1169
- let rules = getAllRules();
1170
- let found = rules.find((r) => r.id === "default:ask-host_bash-global");
1171
- expect(found).toBeDefined();
1172
- expect(found!.userModifiedAt).toBeGreaterThan(0);
1173
- expect(found!.decision).toBe("allow");
1174
-
1175
- // Now simulate a template change by altering what the template expects:
1176
- // on disk the rule has decision=allow + userModifiedAt, but the template
1177
- // would try to migrate it back to decision=ask. Since userModifiedAt is
1178
- // set, backfillDefaults should skip it.
1179
- clearCache();
1180
- rules = getAllRules();
1181
- found = rules.find((r) => r.id === "default:ask-host_bash-global");
1182
- expect(found).toBeDefined();
1183
- // The user's override should be preserved
1184
- expect(found!.decision).toBe("allow");
1185
- expect(found!.userModifiedAt).toBeGreaterThan(0);
1186
- });
1187
-
1188
- test("userModifiedAt survives round-trip through disk", () => {
1189
- getAllRules(); // backfill
1190
- updateRule("default:ask-host_bash-global", { priority: 999 });
1191
- const before = getAllRules().find(
1192
- (r) => r.id === "default:ask-host_bash-global",
1193
- )!;
1194
- expect(before.userModifiedAt).toBeGreaterThan(0);
1195
-
1196
- // Round-trip through disk
1197
- clearCache();
1198
- const after = getAllRules().find(
1199
- (r) => r.id === "default:ask-host_bash-global",
1200
- )!;
1201
- expect(after.userModifiedAt).toBe(before.userModifiedAt);
1202
- expect(after.priority).toBe(999);
1203
- });
1204
- });
1205
-
1206
- // ── trust rule schema v3 (PR 14) ──────────────────────────────
1207
-
1208
- describe("trust rule schema v3 (PR 14)", () => {
1209
- test("new rules can include v3 optional fields (executionTarget)", () => {
1210
- const rule = addRule("bash", "git *", "/tmp");
1211
- // Manually set v3 optional field on the rule and persist
1212
- rule.executionTarget = "/usr/local/bin/node";
1213
- // Re-persist the updated rules
1214
- const rules = getAllRules().map((r) => (r.id === rule.id ? rule : r));
1215
- // Write directly to verify round-trip
1216
- const trustData = { version: 3, rules };
1217
- writeFileSync(trustPath, JSON.stringify(trustData, null, 2));
1218
- clearCache();
1219
- const reloaded = getAllRules();
1220
- const found = reloaded.find((r) => r.id === rule.id);
1221
- expect(found).toBeDefined();
1222
- expect(found!.executionTarget).toBe("/usr/local/bin/node");
1223
- });
1224
-
1225
- test("trust file persists with version 3", () => {
1226
- addRule("bash", "echo *", "/tmp");
1227
- const data = JSON.parse(readFileSync(trustPath, "utf-8"));
1228
- expect(data.version).toBe(3);
1229
- });
1230
- });
1231
-
1232
- // ── loadFromDisk resilience (misc) ──────────────────────────────
1233
-
1234
- describe("loadFromDisk resilience (misc)", () => {
1235
- test("malformed file (valid JSON but null) is handled gracefully", () => {
1236
- mkdirSync(dirname(trustPath), { recursive: true });
1237
- writeFileSync(trustPath, "null");
1238
- clearCache();
1239
- const rules = getAllRules();
1240
- // Accessing null.version throws TypeError, caught by try/catch,
1241
- // falls through to backfill defaults
1242
- expect(rules).toHaveLength(NUM_DEFAULTS);
1243
- });
1244
-
1245
- test("v3 file with optional fields is loaded correctly without re-migration", () => {
1246
- mkdirSync(dirname(trustPath), { recursive: true });
1247
- const v3Rules = [
1248
- {
1249
- id: "v3-with-options",
1250
- tool: "bash",
1251
- pattern: "skill-cmd *",
1252
- scope: "/tmp",
1253
- decision: "allow",
1254
- priority: 100,
1255
- createdAt: 7000,
1256
- executionTarget: "/usr/bin/node",
1257
- },
1258
- {
1259
- id: "v3-without-options",
1260
- tool: "bash",
1261
- pattern: "git *",
1262
- scope: "/tmp",
1263
- decision: "allow",
1264
- priority: 100,
1265
- createdAt: 7001,
1266
- },
1267
- ];
1268
- writeFileSync(trustPath, JSON.stringify({ version: 3, rules: v3Rules }));
1269
- clearCache();
1270
- const rules = getAllRules();
1271
-
1272
- // Rule with optional fields should have them preserved
1273
- const withOptions = rules.find((r) => r.id === "v3-with-options");
1274
- expect(withOptions).toBeDefined();
1275
- expect(withOptions!.executionTarget).toBe("/usr/bin/node");
1276
-
1277
- // Rule without optional fields should remain without them
1278
- const withoutOptions = rules.find((r) => r.id === "v3-without-options");
1279
- expect(withoutOptions).toBeDefined();
1280
- expect(withoutOptions).not.toHaveProperty("executionTarget");
1281
- });
1282
-
1283
- test("legacy v2 version migrates rules and persists as v3", () => {
1284
- mkdirSync(dirname(trustPath), { recursive: true });
1285
- writeFileSync(
1286
- trustPath,
1287
- JSON.stringify({
1288
- version: 2,
1289
- rules: [
1290
- {
1291
- id: "old-version-rule",
1292
- tool: "bash",
1293
- pattern: "git *",
1294
- scope: "/tmp",
1295
- decision: "allow",
1296
- priority: 100,
1297
- createdAt: 5000,
1298
- },
1299
- ],
1300
- }),
1301
- );
1302
- clearCache();
1303
- const rules = getAllRules();
1304
- const migratedRule = rules.find((r) => r.id === "old-version-rule");
1305
- expect(migratedRule).toBeDefined();
1306
- expect(migratedRule!.decision).toBe("allow");
1307
- expect(rules).toHaveLength(1 + NUM_DEFAULTS);
1308
-
1309
- // File should be persisted to the current schema version.
1310
- const data = JSON.parse(readFileSync(trustPath, "utf-8"));
1311
- expect(data.version).toBe(3);
1312
- expect(
1313
- data.rules.some((r: { id: string }) => r.id === "old-version-rule"),
1314
- ).toBe(true);
1315
- });
1316
-
1317
- test("legacy v1 version migrates rules and persists as v3", () => {
1318
- mkdirSync(dirname(trustPath), { recursive: true });
1319
- writeFileSync(
1320
- trustPath,
1321
- JSON.stringify({
1322
- version: 1,
1323
- rules: [
1324
- {
1325
- id: "v1-rule",
1326
- tool: "bash",
1327
- pattern: "rm *",
1328
- scope: "everywhere",
1329
- decision: "deny",
1330
- priority: 200,
1331
- createdAt: 4000,
1332
- },
1333
- ],
1334
- }),
1335
- );
1336
-
1337
- clearCache();
1338
- const rules = getAllRules();
1339
- const migratedRule = rules.find((r) => r.id === "v1-rule");
1340
- expect(migratedRule).toBeDefined();
1341
- expect(migratedRule!.decision).toBe("deny");
1342
-
1343
- const data = JSON.parse(readFileSync(trustPath, "utf-8"));
1344
- expect(data.version).toBe(3);
1345
- expect(data.rules.some((r: { id: string }) => r.id === "v1-rule")).toBe(
1346
- true,
1347
- );
1348
- });
1349
- });
1350
-
1351
- // ── executionTarget-aware rule matching ──────────────────────
1352
-
1353
- describe("executionTarget-aware rule matching", () => {
1354
- /**
1355
- * Helper: write a v3 trust file with the given rules directly to disk,
1356
- * then clear the cache so the next getRules() call picks them up.
1357
- */
1358
- function seedRules(rules: Array<Record<string, unknown>>): void {
1359
- mkdirSync(dirname(trustPath), { recursive: true });
1360
- writeFileSync(trustPath, JSON.stringify({ version: 3, rules }));
1361
- clearCache();
1362
- }
1363
-
1364
- // ── wildcard semantics (no executionTarget on rule) ──────────
1365
-
1366
- describe("wildcard semantics — rules without executionTarget", () => {
1367
- test("rule with no executionTarget matches when no context is provided", () => {
1368
- addRule("bash", "git *", "/tmp", "allow", 200);
1369
- const match = findHighestPriorityRule("bash", ["git status"], "/tmp");
1370
- expect(match).not.toBeNull();
1371
- expect(match!.decision).toBe("allow");
1372
- });
1373
-
1374
- test("rule with no executionTarget matches any execution target", () => {
1375
- addRule("bash", "git *", "/tmp", "allow", 200);
1376
- const match = findHighestPriorityRule("bash", ["git status"], "/tmp", {
1377
- executionTarget: "/usr/bin/node",
1378
- });
1379
- expect(match).not.toBeNull();
1380
- expect(match!.decision).toBe("allow");
1381
- });
1382
- });
1383
-
1384
- // ── executionTarget matching ──────────────────────────────────
1385
-
1386
- describe("executionTarget matching", () => {
1387
- test("rule with executionTarget matches exact target", () => {
1388
- seedRules([
1389
- {
1390
- id: "et-exact",
1391
- tool: "bash",
1392
- pattern: "run *",
1393
- scope: "everywhere",
1394
- decision: "allow",
1395
- priority: 200,
1396
- createdAt: Date.now(),
1397
- executionTarget: "/usr/local/bin/node",
1398
- },
1399
- ]);
1400
- const match = findHighestPriorityRule(
1401
- "bash",
1402
- ["run script.js"],
1403
- "/tmp",
1404
- {
1405
- executionTarget: "/usr/local/bin/node",
1406
- },
1407
- );
1408
- expect(match).not.toBeNull();
1409
- expect(match!.id).toBe("et-exact");
1410
- });
1411
-
1412
- test("rule with executionTarget does NOT match different target", () => {
1413
- seedRules([
1414
- {
1415
- id: "et-diff",
1416
- tool: "bash",
1417
- pattern: "run *",
1418
- scope: "everywhere",
1419
- decision: "allow",
1420
- priority: 200,
1421
- createdAt: Date.now(),
1422
- executionTarget: "/usr/local/bin/node",
1423
- },
1424
- ]);
1425
- const match = findHighestPriorityRule(
1426
- "bash",
1427
- ["run script.js"],
1428
- "/tmp",
1429
- {
1430
- executionTarget: "/usr/local/bin/bun",
1431
- },
1432
- );
1433
- expect(match == null || match.id !== "et-diff").toBe(true);
1434
- });
1435
-
1436
- test("rule with executionTarget does NOT match when no target in context", () => {
1437
- seedRules([
1438
- {
1439
- id: "et-no-ctx",
1440
- tool: "bash",
1441
- pattern: "run *",
1442
- scope: "everywhere",
1443
- decision: "allow",
1444
- priority: 200,
1445
- createdAt: Date.now(),
1446
- executionTarget: "/usr/local/bin/node",
1447
- },
1448
- ]);
1449
- const match = findHighestPriorityRule(
1450
- "bash",
1451
- ["run script.js"],
1452
- "/tmp",
1453
- {},
1454
- );
1455
- expect(match == null || match.id !== "et-no-ctx").toBe(true);
1456
- });
1457
-
1458
- test("rule WITHOUT executionTarget matches any target (wildcard)", () => {
1459
- addRule("bash", "run *", "/tmp", "allow", 200);
1460
- const match = findHighestPriorityRule(
1461
- "bash",
1462
- ["run script.js"],
1463
- "/tmp",
1464
- {
1465
- executionTarget: "/any/path/to/runtime",
1466
- },
1467
- );
1468
- expect(match).not.toBeNull();
1469
- expect(match!.pattern).toBe("run *");
1470
- });
1471
- });
1472
-
1473
- // ── optional ctx parameter ────────────────────────────────────
1474
-
1475
- describe("optional ctx parameter", () => {
1476
- test("callers without ctx parameter still work", () => {
1477
- addRule("bash", "git *", "/tmp", "allow", 200);
1478
- // Calling without the 4th argument — must still match
1479
- const match = findHighestPriorityRule("bash", ["git status"], "/tmp");
1480
- expect(match).not.toBeNull();
1481
- expect(match!.pattern).toBe("git *");
1482
- });
1483
-
1484
- test("empty PolicyContext object behaves the same as no context", () => {
1485
- addRule("bash", "ls *", "/tmp", "allow", 200);
1486
- const matchNoCtx = findHighestPriorityRule("bash", ["ls -la"], "/tmp");
1487
- const matchEmptyCtx = findHighestPriorityRule(
1488
- "bash",
1489
- ["ls -la"],
1490
- "/tmp",
1491
- {},
1492
- );
1493
- expect(matchNoCtx).not.toBeNull();
1494
- expect(matchEmptyCtx).not.toBeNull();
1495
- expect(matchNoCtx!.id).toBe(matchEmptyCtx!.id);
1496
- });
1497
- });
1498
- });
1499
-
1500
- // ── network_request trust rule matching ────────────────────────
1501
-
1502
- describe("network_request trust rules", () => {
1503
- test("exact origin rule matches network_request candidates", () => {
1504
- addRule(
1505
- "network_request",
1506
- "network_request:https://api.example.com/*",
1507
- "everywhere",
1508
- );
1509
- const rule = findHighestPriorityRule(
1510
- "network_request",
1511
- [
1512
- "network_request:https://api.example.com/v1/data",
1513
- "network_request:https://api.example.com/*",
1514
- ],
1515
- "/tmp",
1516
- );
1517
- expect(rule).not.toBeNull();
1518
- expect(rule!.decision).toBe("allow");
1519
- });
1520
-
1521
- test("exact url rule matches only that url candidate", () => {
1522
- addRule(
1523
- "network_request",
1524
- "network_request:https://api.example.com/v1/data",
1525
- "everywhere",
1526
- );
1527
- const match = findHighestPriorityRule(
1528
- "network_request",
1529
- [
1530
- "network_request:https://api.example.com/v1/data",
1531
- "network_request:https://api.example.com/*",
1532
- ],
1533
- "/tmp",
1534
- );
1535
- expect(match).not.toBeNull();
1536
-
1537
- const noMatch = findHighestPriorityRule(
1538
- "network_request",
1539
- ["network_request:https://api.example.com/v2/other"],
1540
- "/tmp",
1541
- );
1542
- expect(noMatch).toBeNull();
1543
- });
1544
-
1545
- test("globstar rule matches any network_request candidate", () => {
1546
- // minimatch treats standalone "**" as globstar (matching "/"), but
1547
- // "network_request:*" uses single "*" which doesn't cross slashes.
1548
- // The tool field is already filtered by findHighestPriorityRule, so
1549
- // "**" is the correct catch-all pattern.
1550
- addRule("network_request", "**", "everywhere");
1551
- const rule = findHighestPriorityRule(
1552
- "network_request",
1553
- ["network_request:https://any-host.example.org/path"],
1554
- "/tmp",
1555
- );
1556
- expect(rule).not.toBeNull();
1557
- });
1558
-
1559
- test("single-star wildcard matches flat candidates only", () => {
1560
- // "network_request:*" won't match URLs with slashes — consistent
1561
- // with the behavior of web_fetch:* patterns.
1562
- addRule("network_request", "network_request:*", "everywhere");
1563
- const noSlashMatch = findHighestPriorityRule(
1564
- "network_request",
1565
- ["network_request:flat-target"],
1566
- "/tmp",
1567
- );
1568
- expect(noSlashMatch).not.toBeNull();
1569
-
1570
- const slashNoMatch = findHighestPriorityRule(
1571
- "network_request",
1572
- ["network_request:https://example.com/path"],
1573
- "/tmp",
1574
- );
1575
- // Single "*" does not match "/" so this URL candidate won't match.
1576
- expect(slashNoMatch).toBeNull();
1577
- });
1578
-
1579
- test("network_request rule does not match web_fetch tool", () => {
1580
- addRule(
1581
- "network_request",
1582
- "network_request:https://api.example.com/*",
1583
- "everywhere",
1584
- );
1585
- const rule = findHighestPriorityRule(
1586
- "web_fetch",
1587
- [
1588
- "web_fetch:https://api.example.com/v1/data",
1589
- "web_fetch:https://api.example.com/*",
1590
- ],
1591
- "/tmp",
1592
- );
1593
- expect(rule).toBeNull();
1594
- });
1595
-
1596
- test("web_fetch rule does not match network_request tool", () => {
1597
- addRule("web_fetch", "web_fetch:https://api.example.com/*", "everywhere");
1598
- const rule = findHighestPriorityRule(
1599
- "network_request",
1600
- [
1601
- "network_request:https://api.example.com/v1/data",
1602
- "network_request:https://api.example.com/*",
1603
- ],
1604
- "/tmp",
1605
- );
1606
- expect(rule).toBeNull();
1607
- });
1608
-
1609
- test("deny rule takes precedence over allow at same priority", () => {
1610
- addRule(
1611
- "network_request",
1612
- "network_request:https://api.example.com/*",
1613
- "everywhere",
1614
- "allow",
1615
- 100,
1616
- );
1617
- addRule(
1618
- "network_request",
1619
- "network_request:https://api.example.com/*",
1620
- "everywhere",
1621
- "deny",
1622
- 100,
1623
- );
1624
- const rule = findHighestPriorityRule(
1625
- "network_request",
1626
- [
1627
- "network_request:https://api.example.com/v1/data",
1628
- "network_request:https://api.example.com/*",
1629
- ],
1630
- "/tmp",
1631
- );
1632
- expect(rule).not.toBeNull();
1633
- expect(rule!.decision).toBe("deny");
1634
- });
1635
-
1636
- test("higher-priority allow overrides lower-priority deny", () => {
1637
- addRule(
1638
- "network_request",
1639
- "network_request:https://api.example.com/*",
1640
- "everywhere",
1641
- "deny",
1642
- 50,
1643
- );
1644
- addRule(
1645
- "network_request",
1646
- "network_request:https://api.example.com/*",
1647
- "everywhere",
1648
- "allow",
1649
- 100,
1650
- );
1651
- const rule = findHighestPriorityRule(
1652
- "network_request",
1653
- [
1654
- "network_request:https://api.example.com/v1/data",
1655
- "network_request:https://api.example.com/*",
1656
- ],
1657
- "/tmp",
1658
- );
1659
- expect(rule).not.toBeNull();
1660
- expect(rule!.decision).toBe("allow");
1661
- });
1662
-
1663
- test("network_request rules match regardless of working directory (URL tools ignore scope)", () => {
1664
- addRule(
1665
- "network_request",
1666
- "network_request:https://api.example.com/*",
1667
- "/home/user/project",
1668
- );
1669
- const inScope = findHighestPriorityRule(
1670
- "network_request",
1671
- ["network_request:https://api.example.com/*"],
1672
- "/home/user/project",
1673
- );
1674
- expect(inScope).not.toBeNull();
1675
-
1676
- // URL tools (network_request) do not support scope — the rule matches
1677
- // regardless of working directory because scope is stripped during
1678
- // normalization.
1679
- const outOfScope = findHighestPriorityRule(
1680
- "network_request",
1681
- ["network_request:https://api.example.com/*"],
1682
- "/tmp/other",
1683
- );
1684
- expect(outOfScope).not.toBeNull();
1685
- });
1686
- });
1687
- });
1688
-
1689
- describe("computer-use tool trust rule matching", () => {
1690
- test("actionable CU tools have default ask trust rules", () => {
1691
- // Actionable CU tools (those that perform screen interactions) should
1692
- // have default "ask" rules so strict mode prompts before use.
1693
- const actionableCuTools = ["computer_use_click", "computer_use_type_text"];
1694
-
1695
- for (const name of actionableCuTools) {
1696
- const rule = findHighestPriorityRule(name, [name], "/tmp/test");
1697
- expect(rule).not.toBeNull();
1698
- expect(rule!.decision).toBe("ask");
1699
- }
1700
- });
1701
-
1702
- test("terminal CU tools (done/respond) have no default trust rules", () => {
1703
- // computer_use_done and computer_use_respond are terminal signal tools
1704
- // with RiskLevel.Low — they should not have ask rules since they don't
1705
- // perform any screen action.
1706
- const terminalCuTools = ["computer_use_done", "computer_use_respond"];
1707
-
1708
- for (const name of terminalCuTools) {
1709
- const defaultRule = DEFAULT_TEMPLATES.find((t) => t.tool === name);
1710
- expect(defaultRule).toBeUndefined();
1711
- }
1712
- });
1713
- });
1714
-
1715
- // ── canonical parser normalization-on-load ─────────────────────────────────
1716
-
1717
- describe("canonical parser normalization-on-load", () => {
1718
- beforeEach(() => {
1719
- clearCache();
1720
- try {
1721
- rmSync(trustPath);
1722
- } catch {
1723
- /* may not exist */
1724
- }
1725
- });
1726
-
1727
- test("URL rule with executionTarget is stripped on load and re-saved", () => {
1728
- // A URL rule (web_fetch) should not carry executionTarget — the canonical
1729
- // parser strips it and marks the file for re-save.
1730
- mkdirSync(dirname(trustPath), { recursive: true });
1731
- writeFileSync(
1732
- trustPath,
1733
- JSON.stringify({
1734
- version: 3,
1735
- rules: [
1736
- {
1737
- id: "url-rule-with-et",
1738
- tool: "web_fetch",
1739
- pattern: "web_fetch:https://example.com/*",
1740
- scope: "everywhere",
1741
- decision: "allow",
1742
- priority: 100,
1743
- createdAt: 1000,
1744
- executionTarget: "/usr/bin/node",
1745
- },
1746
- ],
1747
- }),
1748
- );
1749
- clearCache();
1750
- const rules = getAllRules();
1751
- const found = rules.find((r) => r.id === "url-rule-with-et");
1752
- expect(found).toBeDefined();
1753
- // executionTarget should have been stripped by the canonical parser
1754
- expect(found).not.toHaveProperty("executionTarget");
1755
-
1756
- // Verify the re-save persisted the normalized rule
1757
- const disk = JSON.parse(readFileSync(trustPath, "utf-8"));
1758
- const diskRule = disk.rules.find(
1759
- (r: { id: string }) => r.id === "url-rule-with-et",
1760
- );
1761
- expect(diskRule).toBeDefined();
1762
- expect(diskRule).not.toHaveProperty("executionTarget");
1763
- });
1764
-
1765
- test("URL rule with allowHighRisk is stripped on load (normalized)", () => {
1766
- mkdirSync(dirname(trustPath), { recursive: true });
1767
- writeFileSync(
1768
- trustPath,
1769
- JSON.stringify({
1770
- version: 3,
1771
- rules: [
1772
- {
1773
- id: "url-rule-with-ahr",
1774
- tool: "web_fetch",
1775
- pattern: "**",
1776
- scope: "everywhere",
1777
- decision: "allow",
1778
- priority: 100,
1779
- createdAt: 2000,
1780
- allowHighRisk: true,
1781
- },
1782
- ],
1783
- }),
1784
- );
1785
- clearCache();
1786
- const rules = getAllRules();
1787
- const found = rules.find((r) => r.id === "url-rule-with-ahr");
1788
- expect(found).toBeDefined();
1789
- // allowHighRisk is stripped during normalization
1790
- expect(
1791
- (found as unknown as Record<string, unknown>).allowHighRisk,
1792
- ).toBeUndefined();
1793
- });
1794
-
1795
- test("scoped rule preserves executionTarget but strips allowHighRisk on load", () => {
1796
- mkdirSync(dirname(trustPath), { recursive: true });
1797
- writeFileSync(
1798
- trustPath,
1799
- JSON.stringify({
1800
- version: 3,
1801
- rules: [
1802
- {
1803
- id: "scoped-rule-with-opts",
1804
- tool: "bash",
1805
- pattern: "npm *",
1806
- scope: "/tmp",
1807
- decision: "allow",
1808
- priority: 100,
1809
- createdAt: 3000,
1810
- executionTarget: "/usr/local/bin/node",
1811
- allowHighRisk: true,
1812
- },
1813
- ],
1814
- }),
1815
- );
1816
- clearCache();
1817
- const rules = getAllRules();
1818
- const found = rules.find((r) => r.id === "scoped-rule-with-opts");
1819
- expect(found).toBeDefined();
1820
- expect((found as { executionTarget?: string }).executionTarget).toBe(
1821
- "/usr/local/bin/node",
1822
- );
1823
- // allowHighRisk is stripped during normalization
1824
- expect(
1825
- (found as unknown as Record<string, unknown>).allowHighRisk,
1826
- ).toBeUndefined();
1827
- });
1828
-
1829
- test("normalization on v2 file triggers re-save as v3", () => {
1830
- mkdirSync(dirname(trustPath), { recursive: true });
1831
- writeFileSync(
1832
- trustPath,
1833
- JSON.stringify({
1834
- version: 2,
1835
- rules: [
1836
- {
1837
- id: "v2-url-rule",
1838
- tool: "network_request",
1839
- pattern: "network_request:https://api.test.com/*",
1840
- scope: "everywhere",
1841
- decision: "allow",
1842
- priority: 100,
1843
- createdAt: 4000,
1844
- executionTarget: "stale-value",
1845
- },
1846
- ],
1847
- }),
1848
- );
1849
- clearCache();
1850
- getAllRules();
1851
-
1852
- // File should be re-saved as v3 with normalized rules
1853
- const disk = JSON.parse(readFileSync(trustPath, "utf-8"));
1854
- expect(disk.version).toBe(3);
1855
- const diskRule = disk.rules.find(
1856
- (r: { id: string }) => r.id === "v2-url-rule",
1857
- );
1858
- expect(diskRule).toBeDefined();
1859
- expect(diskRule).not.toHaveProperty("executionTarget");
1860
- });
1861
- });
1862
-
1863
- // ── optional-scope matching fallback ──────────────────────────────────────
1864
-
1865
- describe("optional-scope matching fallback", () => {
1866
- beforeEach(() => {
1867
- clearCache();
1868
- try {
1869
- rmSync(trustPath);
1870
- } catch {
1871
- /* may not exist */
1872
- }
1873
- });
1874
-
1875
- test("rule with missing scope is normalized to everywhere and matches any dir", () => {
1876
- // Simulate a persisted rule that somehow lacks a scope field —
1877
- // the canonical parser normalizes it to "everywhere".
1878
- mkdirSync(dirname(trustPath), { recursive: true });
1879
- writeFileSync(
1880
- trustPath,
1881
- JSON.stringify({
1882
- version: 3,
1883
- rules: [
1884
- {
1885
- id: "no-scope-rule",
1886
- tool: "bash",
1887
- pattern: "echo *",
1888
- decision: "allow",
1889
- priority: 200,
1890
- createdAt: 5000,
1891
- },
1892
- ],
1893
- }),
1894
- );
1895
- clearCache();
1896
- const rules = getAllRules();
1897
- const found = rules.find((r) => r.id === "no-scope-rule");
1898
- expect(found).toBeDefined();
1899
- expect(found!.scope).toBe("everywhere");
1900
-
1901
- // Should match any working directory since scope defaults to everywhere
1902
- const match = findHighestPriorityRule(
1903
- "bash",
1904
- ["echo hello"],
1905
- "/any/random/dir",
1906
- );
1907
- expect(match).not.toBeNull();
1908
- expect(match!.id).toBe("no-scope-rule");
1909
- });
1910
-
1911
- test("rule with empty-string scope is normalized to everywhere", () => {
1912
- mkdirSync(dirname(trustPath), { recursive: true });
1913
- writeFileSync(
1914
- trustPath,
1915
- JSON.stringify({
1916
- version: 3,
1917
- rules: [
1918
- {
1919
- id: "empty-scope-rule",
1920
- tool: "bash",
1921
- pattern: "ls *",
1922
- scope: "",
1923
- decision: "allow",
1924
- priority: 200,
1925
- createdAt: 6000,
1926
- },
1927
- ],
1928
- }),
1929
- );
1930
- clearCache();
1931
- const rules = getAllRules();
1932
- const found = rules.find((r) => r.id === "empty-scope-rule");
1933
- expect(found).toBeDefined();
1934
- // The ruleScope helper treats "" as "everywhere"
1935
- const match = findHighestPriorityRule(
1936
- "bash",
1937
- ["ls -la"],
1938
- "/some/other/dir",
1939
- );
1940
- expect(match).not.toBeNull();
1941
- expect(match!.id).toBe("empty-scope-rule");
1942
- });
1943
- });
1944
-
1945
- // ── unknown-version no-overwrite semantics ────────────────────────────────
1946
-
1947
- describe("unknown-version no-overwrite semantics", () => {
1948
- beforeEach(() => {
1949
- clearCache();
1950
- try {
1951
- rmSync(trustPath);
1952
- } catch {
1953
- /* may not exist */
1954
- }
1955
- });
1956
-
1957
- test("unknown version file is never overwritten even if normalization would apply", () => {
1958
- mkdirSync(dirname(trustPath), { recursive: true });
1959
- // A future version file with rules that would normally be normalized —
1960
- // the unknown-version guard must prevent any disk writes.
1961
- const originalContent = JSON.stringify({
1962
- version: 9999,
1963
- rules: [
1964
- {
1965
- id: "future-url-rule",
1966
- tool: "web_fetch",
1967
- pattern: "web_fetch:https://future.io/*",
1968
- scope: "everywhere",
1969
- decision: "allow",
1970
- priority: 50,
1971
- createdAt: 7000,
1972
- executionTarget: "should-be-stripped-but-file-not-overwritten",
1973
- },
1974
- ],
1975
- });
1976
- writeFileSync(trustPath, originalContent);
1977
- clearCache();
1978
- const rules = getAllRules();
1979
- // Defaults should be present in-memory
1980
- const defaults = rules.filter((r) => r.id.startsWith("default:"));
1981
- expect(defaults).toHaveLength(NUM_DEFAULTS);
1982
- // The on-disk file must NOT be overwritten
1983
- const diskContent = readFileSync(trustPath, "utf-8");
1984
- expect(diskContent).toBe(originalContent);
1985
- });
1986
-
1987
- test("unknown version returns only in-memory defaults, not file rules", () => {
1988
- mkdirSync(dirname(trustPath), { recursive: true });
1989
- writeFileSync(
1990
- trustPath,
1991
- JSON.stringify({
1992
- version: 42,
1993
- rules: [
1994
- {
1995
- id: "v42-rule",
1996
- tool: "bash",
1997
- pattern: "dangerous *",
1998
- scope: "everywhere",
1999
- decision: "allow",
2000
- priority: 500,
2001
- createdAt: 8000,
2002
- },
2003
- ],
2004
- }),
2005
- );
2006
- clearCache();
2007
- const rules = getAllRules();
2008
- // The file's rules should NOT appear in the loaded set
2009
- expect(rules.find((r) => r.id === "v42-rule")).toBeUndefined();
2010
- // Only defaults should be present
2011
- expect(rules.every((r) => r.id.startsWith("default:"))).toBe(true);
2012
- });
2013
- });