@vellumai/assistant 0.4.17 → 0.4.19

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 (528) hide show
  1. package/docs/runbook-trusted-contacts.md +5 -3
  2. package/eslint.config.mjs +2 -2
  3. package/package.json +1 -1
  4. package/src/__tests__/access-request-decision.test.ts +128 -120
  5. package/src/__tests__/account-registry.test.ts +121 -110
  6. package/src/__tests__/active-skill-tools.test.ts +200 -172
  7. package/src/__tests__/actor-token-service.test.ts +341 -274
  8. package/src/__tests__/agent-loop-thinking.test.ts +28 -19
  9. package/src/__tests__/agent-loop.test.ts +798 -378
  10. package/src/__tests__/anthropic-provider.test.ts +405 -247
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
  12. package/src/__tests__/app-bundler.test.ts +112 -79
  13. package/src/__tests__/app-executors.test.ts +205 -178
  14. package/src/__tests__/app-git-history.test.ts +90 -73
  15. package/src/__tests__/app-git-service.test.ts +67 -53
  16. package/src/__tests__/app-open-proxy.test.ts +29 -25
  17. package/src/__tests__/approval-conversation-turn.test.ts +100 -81
  18. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
  19. package/src/__tests__/approval-message-composer.test.ts +119 -119
  20. package/src/__tests__/approval-primitive.test.ts +264 -233
  21. package/src/__tests__/approval-routes-http.test.ts +4 -3
  22. package/src/__tests__/asset-materialize-tool.test.ts +250 -178
  23. package/src/__tests__/asset-search-tool.test.ts +251 -191
  24. package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
  25. package/src/__tests__/assistant-attachments.test.ts +254 -186
  26. package/src/__tests__/assistant-event-hub.test.ts +105 -63
  27. package/src/__tests__/assistant-event.test.ts +66 -58
  28. package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
  29. package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
  30. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
  32. package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
  33. package/src/__tests__/attachments-store.test.ts +240 -183
  34. package/src/__tests__/attachments.test.ts +70 -62
  35. package/src/__tests__/audit-log-rotation.test.ts +50 -35
  36. package/src/__tests__/browser-fill-credential.test.ts +169 -101
  37. package/src/__tests__/browser-manager.test.ts +97 -75
  38. package/src/__tests__/browser-runtime-check.test.ts +16 -15
  39. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
  40. package/src/__tests__/browser-skill-endstate.test.ts +97 -72
  41. package/src/__tests__/bundle-scanner.test.ts +47 -22
  42. package/src/__tests__/bundled-asset.test.ts +74 -47
  43. package/src/__tests__/call-constants.test.ts +19 -19
  44. package/src/__tests__/call-controller.test.ts +0 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +90 -65
  46. package/src/__tests__/call-domain.test.ts +149 -121
  47. package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
  48. package/src/__tests__/call-pointer-messages.test.ts +213 -154
  49. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
  50. package/src/__tests__/call-recovery.test.ts +232 -212
  51. package/src/__tests__/call-routes-http.test.ts +0 -1
  52. package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
  53. package/src/__tests__/call-state-machine.test.ts +62 -51
  54. package/src/__tests__/call-state.test.ts +89 -75
  55. package/src/__tests__/call-store.test.ts +387 -316
  56. package/src/__tests__/callback-handoff-copy.test.ts +84 -82
  57. package/src/__tests__/canonical-guardian-store.test.ts +331 -280
  58. package/src/__tests__/channel-approval-routes.test.ts +1643 -1115
  59. package/src/__tests__/channel-approval.test.ts +139 -137
  60. package/src/__tests__/channel-approvals.test.ts +7 -2
  61. package/src/__tests__/channel-delivery-store.test.ts +232 -194
  62. package/src/__tests__/channel-guardian.test.ts +5 -3
  63. package/src/__tests__/channel-invite-transport.test.ts +107 -92
  64. package/src/__tests__/channel-policy.test.ts +42 -38
  65. package/src/__tests__/channel-readiness-service.test.ts +119 -102
  66. package/src/__tests__/channel-reply-delivery.test.ts +147 -118
  67. package/src/__tests__/channel-retry-sweep.test.ts +153 -110
  68. package/src/__tests__/checker.test.ts +3309 -1850
  69. package/src/__tests__/clarification-resolver.test.ts +91 -79
  70. package/src/__tests__/classifier.test.ts +64 -54
  71. package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
  72. package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
  73. package/src/__tests__/clawhub.test.ts +92 -82
  74. package/src/__tests__/cli.test.ts +30 -30
  75. package/src/__tests__/clipboard.test.ts +53 -46
  76. package/src/__tests__/commit-guarantee.test.ts +59 -52
  77. package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
  78. package/src/__tests__/compaction.benchmark.test.ts +33 -31
  79. package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
  80. package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
  81. package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
  82. package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
  83. package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
  84. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
  85. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
  86. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
  87. package/src/__tests__/computer-use-tools.test.ts +121 -98
  88. package/src/__tests__/config-schema.test.ts +443 -347
  89. package/src/__tests__/config-watcher.test.ts +96 -81
  90. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
  91. package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
  92. package/src/__tests__/conflict-policy.test.ts +151 -80
  93. package/src/__tests__/conflict-store.test.ts +203 -157
  94. package/src/__tests__/connection-policy.test.ts +89 -59
  95. package/src/__tests__/contacts-tools.test.ts +247 -178
  96. package/src/__tests__/context-memory-e2e.test.ts +306 -214
  97. package/src/__tests__/context-token-estimator.test.ts +114 -74
  98. package/src/__tests__/context-window-manager.test.ts +269 -167
  99. package/src/__tests__/contradiction-checker.test.ts +161 -135
  100. package/src/__tests__/conversation-attention-store.test.ts +350 -290
  101. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  102. package/src/__tests__/conversation-pairing.test.ts +220 -113
  103. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  104. package/src/__tests__/conversation-store.test.ts +390 -235
  105. package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
  106. package/src/__tests__/credential-broker-server-use.test.ts +283 -243
  107. package/src/__tests__/credential-broker.test.ts +128 -74
  108. package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
  109. package/src/__tests__/credential-metadata-store.test.ts +360 -311
  110. package/src/__tests__/credential-policy-validate.test.ts +81 -65
  111. package/src/__tests__/credential-resolve.test.ts +212 -145
  112. package/src/__tests__/credential-security-e2e.test.ts +144 -103
  113. package/src/__tests__/credential-security-invariants.test.ts +253 -208
  114. package/src/__tests__/credential-selection.test.ts +254 -146
  115. package/src/__tests__/credential-vault-unit.test.ts +531 -341
  116. package/src/__tests__/credential-vault.test.ts +761 -484
  117. package/src/__tests__/daemon-assistant-events.test.ts +91 -66
  118. package/src/__tests__/daemon-lifecycle.test.ts +258 -190
  119. package/src/__tests__/daemon-server-session-init.test.ts +2 -1
  120. package/src/__tests__/date-context.test.ts +314 -249
  121. package/src/__tests__/db-migration-rollback.test.ts +259 -130
  122. package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
  123. package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
  124. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
  125. package/src/__tests__/dictation-mode-detection.test.ts +77 -55
  126. package/src/__tests__/dictation-profile-store.test.ts +70 -56
  127. package/src/__tests__/dictation-text-processing.test.ts +53 -35
  128. package/src/__tests__/diff.test.ts +102 -98
  129. package/src/__tests__/domain-normalize.test.ts +54 -54
  130. package/src/__tests__/domain-policy.test.ts +71 -55
  131. package/src/__tests__/dynamic-page-surface.test.ts +31 -33
  132. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
  133. package/src/__tests__/edit-engine.test.ts +56 -56
  134. package/src/__tests__/elevenlabs-client.test.ts +117 -91
  135. package/src/__tests__/elevenlabs-config.test.ts +32 -31
  136. package/src/__tests__/email-classifier.test.ts +15 -12
  137. package/src/__tests__/email-cli.test.ts +121 -108
  138. package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
  139. package/src/__tests__/encrypted-store.test.ts +180 -154
  140. package/src/__tests__/entity-extractor.test.ts +108 -87
  141. package/src/__tests__/entity-search.test.ts +664 -258
  142. package/src/__tests__/ephemeral-permissions.test.ts +224 -188
  143. package/src/__tests__/event-bus.test.ts +81 -77
  144. package/src/__tests__/extract-email.test.ts +29 -20
  145. package/src/__tests__/file-edit-tool.test.ts +62 -44
  146. package/src/__tests__/file-ops-service.test.ts +131 -114
  147. package/src/__tests__/file-read-tool.test.ts +48 -31
  148. package/src/__tests__/file-write-tool.test.ts +43 -37
  149. package/src/__tests__/filesystem-tools.test.ts +238 -209
  150. package/src/__tests__/followup-tools.test.ts +237 -162
  151. package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
  152. package/src/__tests__/frontmatter.test.ts +96 -81
  153. package/src/__tests__/fuzzy-match-property.test.ts +75 -81
  154. package/src/__tests__/fuzzy-match.test.ts +71 -65
  155. package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
  156. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  157. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  158. package/src/__tests__/gemini-image-service.test.ts +113 -100
  159. package/src/__tests__/gemini-provider.test.ts +297 -220
  160. package/src/__tests__/get-weather.test.ts +188 -114
  161. package/src/__tests__/gmail-integration.test.ts +13 -5
  162. package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
  163. package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
  164. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  165. package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
  166. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
  167. package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
  168. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
  169. package/src/__tests__/guardian-action-store.test.ts +158 -109
  170. package/src/__tests__/guardian-action-sweep.test.ts +114 -100
  171. package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
  172. package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
  173. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
  174. package/src/__tests__/guardian-dispatch.test.ts +316 -256
  175. package/src/__tests__/guardian-grant-minting.test.ts +247 -178
  176. package/src/__tests__/guardian-outbound-http.test.ts +5 -3
  177. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
  178. package/src/__tests__/guardian-question-copy.test.ts +17 -17
  179. package/src/__tests__/guardian-question-mode.test.ts +134 -100
  180. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  181. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  182. package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
  183. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  184. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
  185. package/src/__tests__/handle-user-message-secret-resume.test.ts +7 -2
  186. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
  187. package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
  188. package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
  189. package/src/__tests__/handlers-slack-config.test.ts +63 -54
  190. package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
  191. package/src/__tests__/handlers-telegram-config.test.ts +662 -329
  192. package/src/__tests__/handlers-twitter-config.test.ts +525 -298
  193. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +5 -2
  194. package/src/__tests__/headless-browser-interactions.test.ts +444 -280
  195. package/src/__tests__/headless-browser-navigate.test.ts +116 -79
  196. package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
  197. package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
  198. package/src/__tests__/heartbeat-service.test.ts +76 -58
  199. package/src/__tests__/history-repair-observability.test.ts +14 -14
  200. package/src/__tests__/history-repair.test.ts +171 -167
  201. package/src/__tests__/home-base-bootstrap.test.ts +30 -27
  202. package/src/__tests__/hooks-blocking.test.ts +86 -37
  203. package/src/__tests__/hooks-cli.test.ts +104 -68
  204. package/src/__tests__/hooks-config.test.ts +81 -43
  205. package/src/__tests__/hooks-discovery.test.ts +106 -96
  206. package/src/__tests__/hooks-integration.test.ts +78 -72
  207. package/src/__tests__/hooks-manager.test.ts +99 -61
  208. package/src/__tests__/hooks-runner.test.ts +94 -71
  209. package/src/__tests__/hooks-settings.test.ts +69 -64
  210. package/src/__tests__/hooks-templates.test.ts +85 -54
  211. package/src/__tests__/hooks-ts-runner.test.ts +82 -45
  212. package/src/__tests__/hooks-watch.test.ts +32 -22
  213. package/src/__tests__/host-file-edit-tool.test.ts +190 -148
  214. package/src/__tests__/host-file-read-tool.test.ts +86 -63
  215. package/src/__tests__/host-file-write-tool.test.ts +98 -64
  216. package/src/__tests__/host-shell-tool.test.ts +342 -233
  217. package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
  218. package/src/__tests__/ingress-member-store.test.ts +163 -159
  219. package/src/__tests__/ingress-reconcile.test.ts +13 -6
  220. package/src/__tests__/ingress-routes-http.test.ts +441 -356
  221. package/src/__tests__/ingress-url-consistency.test.ts +125 -64
  222. package/src/__tests__/integration-status.test.ts +93 -73
  223. package/src/__tests__/intent-routing.test.ts +148 -118
  224. package/src/__tests__/invite-redemption-service.test.ts +163 -121
  225. package/src/__tests__/ipc-blob-store.test.ts +104 -91
  226. package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
  227. package/src/__tests__/ipc-contract.test.ts +24 -23
  228. package/src/__tests__/ipc-protocol.test.ts +52 -46
  229. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
  230. package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
  231. package/src/__tests__/ipc-validate.test.ts +240 -179
  232. package/src/__tests__/key-migration.test.ts +123 -90
  233. package/src/__tests__/keychain.test.ts +150 -123
  234. package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
  235. package/src/__tests__/llm-usage-store.test.ts +112 -87
  236. package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
  237. package/src/__tests__/managed-store.test.ts +411 -360
  238. package/src/__tests__/mcp-cli.test.ts +190 -124
  239. package/src/__tests__/mcp-health-check.test.ts +26 -21
  240. package/src/__tests__/media-generate-image.test.ts +122 -99
  241. package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
  242. package/src/__tests__/media-visibility-policy.test.ts +86 -38
  243. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
  244. package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
  245. package/src/__tests__/memory-query-builder.test.ts +32 -33
  246. package/src/__tests__/memory-recall-quality.test.ts +761 -407
  247. package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
  248. package/src/__tests__/memory-regressions.test.ts +3725 -2642
  249. package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
  250. package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
  251. package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
  252. package/src/__tests__/messaging-send-tool.test.ts +36 -29
  253. package/src/__tests__/migration-cli-flows.test.ts +69 -53
  254. package/src/__tests__/migration-ordering.test.ts +103 -86
  255. package/src/__tests__/mime-builder.test.ts +55 -32
  256. package/src/__tests__/mock-signup-server.test.ts +384 -246
  257. package/src/__tests__/model-intents.test.ts +61 -37
  258. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
  259. package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
  260. package/src/__tests__/non-member-access-request.test.ts +3 -2
  261. package/src/__tests__/notification-broadcaster.test.ts +99 -81
  262. package/src/__tests__/notification-decision-fallback.test.ts +223 -178
  263. package/src/__tests__/notification-decision-strategy.test.ts +375 -337
  264. package/src/__tests__/notification-deep-link.test.ts +67 -61
  265. package/src/__tests__/notification-guardian-path.test.ts +248 -206
  266. package/src/__tests__/notification-routing-intent.test.ts +166 -93
  267. package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
  268. package/src/__tests__/notification-thread-candidates.test.ts +64 -61
  269. package/src/__tests__/oauth-callback-registry.test.ts +40 -30
  270. package/src/__tests__/oauth-connect-handler.test.ts +109 -89
  271. package/src/__tests__/oauth-scope-policy.test.ts +63 -55
  272. package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
  273. package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
  274. package/src/__tests__/onboarding-template-contract.test.ts +93 -94
  275. package/src/__tests__/openai-provider.test.ts +366 -274
  276. package/src/__tests__/pairing-concurrent.test.ts +18 -12
  277. package/src/__tests__/pairing-routes.test.ts +45 -41
  278. package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
  279. package/src/__tests__/parser.test.ts +316 -226
  280. package/src/__tests__/path-classifier.test.ts +24 -25
  281. package/src/__tests__/path-policy.test.ts +187 -147
  282. package/src/__tests__/phone.test.ts +36 -36
  283. package/src/__tests__/platform-move-helper.test.ts +48 -40
  284. package/src/__tests__/platform-socket-path.test.ts +23 -24
  285. package/src/__tests__/platform-workspace-migration.test.ts +464 -414
  286. package/src/__tests__/platform.test.ts +61 -53
  287. package/src/__tests__/playbook-execution.test.ts +397 -265
  288. package/src/__tests__/playbook-tools.test.ts +267 -196
  289. package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
  290. package/src/__tests__/pricing.test.ts +316 -136
  291. package/src/__tests__/profile-compiler.test.ts +206 -188
  292. package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
  293. package/src/__tests__/provider-error-scenarios.test.ts +212 -158
  294. package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
  295. package/src/__tests__/provider-registry-ollama.test.ts +13 -9
  296. package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
  297. package/src/__tests__/proxy-approval-callback.test.ts +180 -119
  298. package/src/__tests__/public-ingress-urls.test.ts +112 -94
  299. package/src/__tests__/qdrant-manager.test.ts +147 -98
  300. package/src/__tests__/ratelimit.test.ts +152 -82
  301. package/src/__tests__/recording-handler.test.ts +273 -151
  302. package/src/__tests__/recording-intent-fallback.test.ts +94 -75
  303. package/src/__tests__/recording-intent-handler.test.ts +9 -2
  304. package/src/__tests__/recording-intent.test.ts +578 -379
  305. package/src/__tests__/recording-state-machine.test.ts +530 -316
  306. package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
  307. package/src/__tests__/recurrence-engine.test.ts +81 -41
  308. package/src/__tests__/recurrence-types.test.ts +63 -44
  309. package/src/__tests__/relay-server.test.ts +2131 -1602
  310. package/src/__tests__/reminder-store.test.ts +158 -80
  311. package/src/__tests__/reminder.test.ts +113 -109
  312. package/src/__tests__/remote-skill-policy.test.ts +96 -72
  313. package/src/__tests__/request-file-tool.test.ts +74 -67
  314. package/src/__tests__/response-tier.test.ts +131 -74
  315. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  316. package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
  317. package/src/__tests__/runtime-events-sse.test.ts +0 -1
  318. package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
  319. package/src/__tests__/sandbox-host-parity.test.ts +377 -301
  320. package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
  321. package/src/__tests__/schedule-store.test.ts +268 -205
  322. package/src/__tests__/schedule-tools.test.ts +702 -524
  323. package/src/__tests__/scheduler-recurrence.test.ts +240 -130
  324. package/src/__tests__/scoped-approval-grants.test.ts +258 -168
  325. package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
  326. package/src/__tests__/script-proxy-certs.test.ts +38 -35
  327. package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
  328. package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
  329. package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
  330. package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
  331. package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
  332. package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
  333. package/src/__tests__/script-proxy-policy.test.ts +308 -153
  334. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
  335. package/src/__tests__/script-proxy-router.test.ts +111 -77
  336. package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
  337. package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
  338. package/src/__tests__/secret-allowlist.test.ts +105 -90
  339. package/src/__tests__/secret-ingress-handler.test.ts +41 -30
  340. package/src/__tests__/secret-onetime-send.test.ts +67 -50
  341. package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
  342. package/src/__tests__/secret-response-routing.test.ts +50 -41
  343. package/src/__tests__/secret-scanner-executor.test.ts +152 -111
  344. package/src/__tests__/secret-scanner.test.ts +495 -413
  345. package/src/__tests__/secure-keys.test.ts +132 -121
  346. package/src/__tests__/send-endpoint-busy.test.ts +8 -3
  347. package/src/__tests__/send-notification-tool.test.ts +43 -42
  348. package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
  349. package/src/__tests__/sequence-store.test.ts +335 -167
  350. package/src/__tests__/server-history-render.test.ts +341 -202
  351. package/src/__tests__/session-abort-tool-results.test.ts +133 -70
  352. package/src/__tests__/session-confirmation-signals.test.ts +252 -160
  353. package/src/__tests__/session-conflict-gate.test.ts +775 -585
  354. package/src/__tests__/session-error.test.ts +222 -191
  355. package/src/__tests__/session-evictor.test.ts +79 -62
  356. package/src/__tests__/session-init.benchmark.test.ts +170 -108
  357. package/src/__tests__/session-load-history-repair.test.ts +273 -139
  358. package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
  359. package/src/__tests__/session-pre-run-repair.test.ts +106 -59
  360. package/src/__tests__/session-profile-injection.test.ts +198 -130
  361. package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
  362. package/src/__tests__/session-queue.test.ts +624 -321
  363. package/src/__tests__/session-runtime-assembly.test.ts +425 -329
  364. package/src/__tests__/session-runtime-workspace.test.ts +69 -61
  365. package/src/__tests__/session-skill-tools.test.ts +973 -678
  366. package/src/__tests__/session-slash-known.test.ts +185 -133
  367. package/src/__tests__/session-slash-queue.test.ts +147 -81
  368. package/src/__tests__/session-slash-unknown.test.ts +135 -90
  369. package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
  370. package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
  371. package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
  372. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
  373. package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
  374. package/src/__tests__/session-undo.test.ts +43 -30
  375. package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
  376. package/src/__tests__/session-workspace-injection.test.ts +245 -117
  377. package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
  378. package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
  379. package/src/__tests__/shell-credential-ref.test.ts +126 -90
  380. package/src/__tests__/shell-identity.test.ts +134 -111
  381. package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
  382. package/src/__tests__/shell-parser-property.test.ts +435 -288
  383. package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
  384. package/src/__tests__/size-guard.test.ts +42 -44
  385. package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
  386. package/src/__tests__/skill-feature-flags.test.ts +75 -47
  387. package/src/__tests__/skill-include-graph.test.ts +143 -148
  388. package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
  389. package/src/__tests__/skill-load-tool.test.ts +371 -199
  390. package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
  391. package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
  392. package/src/__tests__/skill-script-runner-host.test.ts +460 -250
  393. package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
  394. package/src/__tests__/skill-script-runner.test.ts +115 -74
  395. package/src/__tests__/skill-tool-factory.test.ts +140 -96
  396. package/src/__tests__/skill-tool-manifest.test.ts +306 -210
  397. package/src/__tests__/skill-version-hash.test.ts +70 -56
  398. package/src/__tests__/skills.test.ts +0 -1
  399. package/src/__tests__/slack-channel-config.test.ts +127 -84
  400. package/src/__tests__/slack-skill.test.ts +60 -47
  401. package/src/__tests__/slash-commands-catalog.test.ts +37 -31
  402. package/src/__tests__/slash-commands-parser.test.ts +71 -64
  403. package/src/__tests__/slash-commands-resolver.test.ts +143 -107
  404. package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
  405. package/src/__tests__/sms-messaging-provider.test.ts +4 -0
  406. package/src/__tests__/speaker-identification.test.ts +28 -25
  407. package/src/__tests__/starter-bundle.test.ts +27 -23
  408. package/src/__tests__/starter-task-flow.test.ts +67 -52
  409. package/src/__tests__/subagent-manager-notify.test.ts +154 -108
  410. package/src/__tests__/subagent-tools.test.ts +311 -270
  411. package/src/__tests__/subagent-types.test.ts +40 -40
  412. package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
  413. package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
  414. package/src/__tests__/swarm-orchestrator.test.ts +135 -101
  415. package/src/__tests__/swarm-plan-validator.test.ts +125 -73
  416. package/src/__tests__/swarm-recursion.test.ts +58 -46
  417. package/src/__tests__/swarm-router-planner.test.ts +99 -74
  418. package/src/__tests__/swarm-session-integration.test.ts +148 -91
  419. package/src/__tests__/swarm-tool.test.ts +65 -45
  420. package/src/__tests__/swarm-worker-backend.test.ts +59 -45
  421. package/src/__tests__/swarm-worker-runner.test.ts +133 -118
  422. package/src/__tests__/system-prompt.test.ts +311 -256
  423. package/src/__tests__/task-compiler.test.ts +176 -120
  424. package/src/__tests__/task-management-tools.test.ts +561 -456
  425. package/src/__tests__/task-memory-cleanup.test.ts +627 -362
  426. package/src/__tests__/task-runner.test.ts +117 -94
  427. package/src/__tests__/task-scheduler.test.ts +113 -84
  428. package/src/__tests__/task-tools.test.ts +349 -264
  429. package/src/__tests__/terminal-sandbox.test.ts +138 -108
  430. package/src/__tests__/terminal-tools.test.ts +350 -305
  431. package/src/__tests__/thread-seed-composer.test.ts +307 -180
  432. package/src/__tests__/tool-approval-handler.test.ts +238 -137
  433. package/src/__tests__/tool-audit-listener.test.ts +69 -69
  434. package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
  435. package/src/__tests__/tool-execution-abort-cleanup.test.ts +155 -146
  436. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
  437. package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
  438. package/src/__tests__/tool-executor-redaction.test.ts +112 -109
  439. package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
  440. package/src/__tests__/tool-executor.test.ts +1274 -674
  441. package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
  442. package/src/__tests__/tool-metrics-listener.test.ts +97 -85
  443. package/src/__tests__/tool-notification-listener.test.ts +42 -25
  444. package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
  445. package/src/__tests__/tool-policy.test.ts +44 -25
  446. package/src/__tests__/tool-profiling-listener.test.ts +99 -93
  447. package/src/__tests__/tool-result-truncation.test.ts +5 -4
  448. package/src/__tests__/tool-trace-listener.test.ts +131 -111
  449. package/src/__tests__/top-level-renderer.test.ts +62 -58
  450. package/src/__tests__/top-level-scanner.test.ts +68 -64
  451. package/src/__tests__/trace-emitter.test.ts +56 -56
  452. package/src/__tests__/trust-context-guards.test.ts +65 -65
  453. package/src/__tests__/trust-store.test.ts +1239 -806
  454. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  455. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  456. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
  457. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
  458. package/src/__tests__/trusted-contact-verification.test.ts +251 -231
  459. package/src/__tests__/turn-commit.test.ts +259 -200
  460. package/src/__tests__/twilio-provider.test.ts +140 -126
  461. package/src/__tests__/twilio-rest.test.ts +22 -18
  462. package/src/__tests__/twilio-routes-elevenlabs.test.ts +0 -1
  463. package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
  464. package/src/__tests__/twilio-routes.test.ts +0 -1
  465. package/src/__tests__/twitter-auth-handler.test.ts +184 -139
  466. package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
  467. package/src/__tests__/twitter-cli-routing.test.ts +146 -99
  468. package/src/__tests__/twitter-oauth-client.test.ts +82 -65
  469. package/src/__tests__/update-bulletin-format.test.ts +69 -66
  470. package/src/__tests__/update-bulletin-state.test.ts +66 -60
  471. package/src/__tests__/update-bulletin.test.ts +150 -114
  472. package/src/__tests__/update-template-contract.test.ts +15 -10
  473. package/src/__tests__/url-safety.test.ts +288 -265
  474. package/src/__tests__/user-reference.test.ts +32 -32
  475. package/src/__tests__/view-image-tool.test.ts +118 -96
  476. package/src/__tests__/voice-invite-redemption.test.ts +111 -106
  477. package/src/__tests__/voice-quality.test.ts +117 -102
  478. package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
  479. package/src/__tests__/voice-session-bridge.test.ts +351 -216
  480. package/src/__tests__/weather-skill-regression.test.ts +170 -120
  481. package/src/__tests__/web-fetch.test.ts +664 -526
  482. package/src/__tests__/web-search.test.ts +379 -213
  483. package/src/__tests__/work-item-output.test.ts +90 -53
  484. package/src/__tests__/workspace-git-service.test.ts +437 -356
  485. package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
  486. package/src/__tests__/workspace-lifecycle.test.ts +98 -64
  487. package/src/__tests__/workspace-policy.test.ts +139 -71
  488. package/src/cli/mcp.ts +81 -28
  489. package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
  490. package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
  491. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +25 -10
  492. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
  493. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +6 -11
  494. package/src/config/bundled-skills/messaging/SKILL.md +4 -3
  495. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
  496. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
  497. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -2
  498. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
  499. package/src/config/bundled-skills/sms-setup/SKILL.md +8 -16
  500. package/src/config/bundled-skills/telegram-setup/SKILL.md +3 -3
  501. package/src/config/bundled-skills/trusted-contacts/SKILL.md +13 -25
  502. package/src/config/bundled-skills/twilio-setup/SKILL.md +13 -23
  503. package/src/config/bundled-tool-registry.ts +2 -0
  504. package/src/config/env.ts +3 -4
  505. package/src/config/system-prompt.ts +32 -0
  506. package/src/mcp/client.ts +2 -7
  507. package/src/memory/db-connection.ts +16 -10
  508. package/src/messaging/providers/gmail/adapter.ts +10 -3
  509. package/src/messaging/providers/gmail/client.ts +280 -72
  510. package/src/runtime/auth/__tests__/context.test.ts +75 -65
  511. package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
  512. package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
  513. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
  514. package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
  515. package/src/runtime/auth/__tests__/policy.test.ts +9 -9
  516. package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
  517. package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
  518. package/src/runtime/auth/__tests__/subject.test.ts +54 -54
  519. package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
  520. package/src/runtime/auth/scopes.ts +3 -0
  521. package/src/runtime/auth/token-service.ts +4 -1
  522. package/src/runtime/auth/types.ts +2 -1
  523. package/src/runtime/http-server.ts +2 -1
  524. package/src/security/secure-keys.ts +120 -54
  525. package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
  526. package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
  527. package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
  528. package/src/tools/terminal/safe-env.ts +7 -0
@@ -1,40 +1,47 @@
1
- import { mkdirSync,mkdtempSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
-
5
- import { afterEach, beforeAll, beforeEach, describe, expect, mock,test } from 'bun:test';
1
+ import { mkdirSync, mkdtempSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import {
5
+ afterEach,
6
+ beforeAll,
7
+ beforeEach,
8
+ describe,
9
+ expect,
10
+ mock,
11
+ test,
12
+ } from "bun:test";
6
13
 
7
14
  // Use a temp directory so trust-store doesn't touch ~/.vellum
8
- const testDir = mkdtempSync(join(tmpdir(), 'ephemeral-perm-test-'));
15
+ const testDir = mkdtempSync(join(tmpdir(), "ephemeral-perm-test-"));
9
16
 
10
- mock.module('../util/platform.js', () => ({
17
+ mock.module("../util/platform.js", () => ({
11
18
  getRootDir: () => testDir,
12
- getDataDir: () => join(testDir, 'data'),
13
- getWorkspaceSkillsDir: () => join(testDir, 'skills'),
14
- isMacOS: () => process.platform === 'darwin',
15
- isLinux: () => process.platform === 'linux',
16
- isWindows: () => process.platform === 'win32',
17
- getSocketPath: () => join(testDir, 'test.sock'),
18
- getPidPath: () => join(testDir, 'test.pid'),
19
- getDbPath: () => join(testDir, 'test.db'),
20
- getLogPath: () => join(testDir, 'test.log'),
19
+ getDataDir: () => join(testDir, "data"),
20
+ getWorkspaceSkillsDir: () => join(testDir, "skills"),
21
+ isMacOS: () => process.platform === "darwin",
22
+ isLinux: () => process.platform === "linux",
23
+ isWindows: () => process.platform === "win32",
24
+ getSocketPath: () => join(testDir, "test.sock"),
25
+ getPidPath: () => join(testDir, "test.pid"),
26
+ getDbPath: () => join(testDir, "test.db"),
27
+ getLogPath: () => join(testDir, "test.log"),
21
28
  ensureDataDir: () => {},
22
29
  }));
23
30
 
24
- mock.module('../util/logger.js', () => ({
25
- getLogger: () => new Proxy({} as Record<string, unknown>, {
26
- get: () => () => {},
27
- }),
31
+ mock.module("../util/logger.js", () => ({
32
+ getLogger: () =>
33
+ new Proxy({} as Record<string, unknown>, {
34
+ get: () => () => {},
35
+ }),
28
36
  }));
29
37
 
30
-
31
38
  const testConfig: Record<string, any> = {
32
- permissions: { mode: 'legacy' as 'legacy' | 'strict' | 'workspace' },
39
+ permissions: { mode: "legacy" as "legacy" | "strict" | "workspace" },
33
40
  skills: { load: { extraDirs: [] as string[] } },
34
41
  sandbox: { enabled: false },
35
42
  };
36
43
 
37
- mock.module('../config/loader.js', () => ({
44
+ mock.module("../config/loader.js", () => ({
38
45
  getConfig: () => testConfig,
39
46
  loadConfig: () => testConfig,
40
47
  invalidateConfigCache: () => {},
@@ -45,25 +52,34 @@ mock.module('../config/loader.js', () => ({
45
52
  setNestedValue: () => {},
46
53
  }));
47
54
 
48
- import { check, classifyRisk } from '../permissions/checker.js';
49
- import { addRule, clearCache,findHighestPriorityRule } from '../permissions/trust-store.js';
50
- import type { PolicyContext,TrustRule } from '../permissions/types.js';
51
- import { buildTaskRules,clearTaskRunRules, getTaskRunRules, setTaskRunRules } from '../tasks/ephemeral-permissions.js';
55
+ import { check, classifyRisk } from "../permissions/checker.js";
56
+ import {
57
+ addRule,
58
+ clearCache,
59
+ findHighestPriorityRule,
60
+ } from "../permissions/trust-store.js";
61
+ import type { PolicyContext, TrustRule } from "../permissions/types.js";
62
+ import {
63
+ buildTaskRules,
64
+ clearTaskRunRules,
65
+ getTaskRunRules,
66
+ setTaskRunRules,
67
+ } from "../tasks/ephemeral-permissions.js";
52
68
 
53
69
  // Ensure the protected directory exists for trust-store disk operations
54
- mkdirSync(join(testDir, 'protected'), { recursive: true });
70
+ mkdirSync(join(testDir, "protected"), { recursive: true });
55
71
 
56
- describe('ephemeral-permissions', () => {
72
+ describe("ephemeral-permissions", () => {
57
73
  // Warm up the shell parser (loads WASM) — required before any check() call
58
74
  // that involves bash commands, otherwise the parser init may hang.
59
75
  beforeAll(async () => {
60
- await classifyRisk('bash', { command: 'echo warmup' });
76
+ await classifyRisk("bash", { command: "echo warmup" });
61
77
  });
62
- describe('buildTaskRules', () => {
63
- test('generates correct rule structure for each required tool', () => {
64
- const taskRunId = 'run-123';
65
- const requiredTools = ['file_read', 'bash', 'file_write'];
66
- const workingDir = '/home/user/project';
78
+ describe("buildTaskRules", () => {
79
+ test("generates correct rule structure for each required tool", () => {
80
+ const taskRunId = "run-123";
81
+ const requiredTools = ["file_read", "bash", "file_write"];
82
+ const workingDir = "/home/user/project";
67
83
 
68
84
  const rules = buildTaskRules(taskRunId, requiredTools, workingDir);
69
85
 
@@ -71,11 +87,11 @@ describe('ephemeral-permissions', () => {
71
87
 
72
88
  // Check the first rule in detail
73
89
  const fileReadRule = rules[0];
74
- expect(fileReadRule.id).toBe('ephemeral:run-123:file_read');
75
- expect(fileReadRule.tool).toBe('file_read');
76
- expect(fileReadRule.pattern).toBe('**');
77
- expect(fileReadRule.scope).toBe('everywhere');
78
- expect(fileReadRule.decision).toBe('allow');
90
+ expect(fileReadRule.id).toBe("ephemeral:run-123:file_read");
91
+ expect(fileReadRule.tool).toBe("file_read");
92
+ expect(fileReadRule.pattern).toBe("**");
93
+ expect(fileReadRule.scope).toBe("everywhere");
94
+ expect(fileReadRule.decision).toBe("allow");
79
95
  expect(fileReadRule.priority).toBe(75);
80
96
  expect(fileReadRule.createdAt).toBeGreaterThan(0);
81
97
 
@@ -84,135 +100,145 @@ describe('ephemeral-permissions', () => {
84
100
  expect(fileReadRule.allowHighRisk).toBe(true);
85
101
 
86
102
  // Check other rules have correct tool names
87
- expect(rules[1].tool).toBe('bash');
88
- expect(rules[1].id).toBe('ephemeral:run-123:bash');
89
- expect(rules[2].tool).toBe('file_write');
90
- expect(rules[2].id).toBe('ephemeral:run-123:file_write');
103
+ expect(rules[1].tool).toBe("bash");
104
+ expect(rules[1].id).toBe("ephemeral:run-123:bash");
105
+ expect(rules[2].tool).toBe("file_write");
106
+ expect(rules[2].id).toBe("ephemeral:run-123:file_write");
91
107
  });
92
108
 
93
- test('returns empty array for empty required tools', () => {
94
- const rules = buildTaskRules('run-456', [], '/tmp');
109
+ test("returns empty array for empty required tools", () => {
110
+ const rules = buildTaskRules("run-456", [], "/tmp");
95
111
  expect(rules).toHaveLength(0);
96
112
  });
97
113
  });
98
114
 
99
- describe('setTaskRunRules / getTaskRunRules / clearTaskRunRules', () => {
115
+ describe("setTaskRunRules / getTaskRunRules / clearTaskRunRules", () => {
100
116
  beforeEach(() => {
101
117
  // Clean up any leftover state
102
- clearTaskRunRules('test-run-1');
103
- clearTaskRunRules('test-run-2');
118
+ clearTaskRunRules("test-run-1");
119
+ clearTaskRunRules("test-run-2");
104
120
  });
105
121
 
106
- test('returns empty array for unknown task run', () => {
107
- expect(getTaskRunRules('nonexistent')).toEqual([]);
122
+ test("returns empty array for unknown task run", () => {
123
+ expect(getTaskRunRules("nonexistent")).toEqual([]);
108
124
  });
109
125
 
110
- test('stores and retrieves rules for a task run', () => {
111
- const rules = buildTaskRules('test-run-1', ['file_read'], '/tmp');
112
- setTaskRunRules('test-run-1', rules);
126
+ test("stores and retrieves rules for a task run", () => {
127
+ const rules = buildTaskRules("test-run-1", ["file_read"], "/tmp");
128
+ setTaskRunRules("test-run-1", rules);
113
129
 
114
- const retrieved = getTaskRunRules('test-run-1');
130
+ const retrieved = getTaskRunRules("test-run-1");
115
131
  expect(retrieved).toHaveLength(1);
116
- expect(retrieved[0].tool).toBe('file_read');
132
+ expect(retrieved[0].tool).toBe("file_read");
117
133
  });
118
134
 
119
- test('clears rules for a task run', () => {
120
- const rules = buildTaskRules('test-run-1', ['file_read'], '/tmp');
121
- setTaskRunRules('test-run-1', rules);
122
- expect(getTaskRunRules('test-run-1')).toHaveLength(1);
135
+ test("clears rules for a task run", () => {
136
+ const rules = buildTaskRules("test-run-1", ["file_read"], "/tmp");
137
+ setTaskRunRules("test-run-1", rules);
138
+ expect(getTaskRunRules("test-run-1")).toHaveLength(1);
123
139
 
124
- clearTaskRunRules('test-run-1');
125
- expect(getTaskRunRules('test-run-1')).toEqual([]);
140
+ clearTaskRunRules("test-run-1");
141
+ expect(getTaskRunRules("test-run-1")).toEqual([]);
126
142
  });
127
143
 
128
- test('isolates rules between task runs', () => {
129
- const rules1 = buildTaskRules('test-run-1', ['file_read'], '/tmp');
130
- const rules2 = buildTaskRules('test-run-2', ['bash', 'file_write'], '/home');
144
+ test("isolates rules between task runs", () => {
145
+ const rules1 = buildTaskRules("test-run-1", ["file_read"], "/tmp");
146
+ const rules2 = buildTaskRules(
147
+ "test-run-2",
148
+ ["bash", "file_write"],
149
+ "/home",
150
+ );
131
151
 
132
- setTaskRunRules('test-run-1', rules1);
133
- setTaskRunRules('test-run-2', rules2);
152
+ setTaskRunRules("test-run-1", rules1);
153
+ setTaskRunRules("test-run-2", rules2);
134
154
 
135
- expect(getTaskRunRules('test-run-1')).toHaveLength(1);
136
- expect(getTaskRunRules('test-run-2')).toHaveLength(2);
155
+ expect(getTaskRunRules("test-run-1")).toHaveLength(1);
156
+ expect(getTaskRunRules("test-run-2")).toHaveLength(2);
137
157
 
138
- clearTaskRunRules('test-run-1');
139
- expect(getTaskRunRules('test-run-1')).toEqual([]);
140
- expect(getTaskRunRules('test-run-2')).toHaveLength(2);
158
+ clearTaskRunRules("test-run-1");
159
+ expect(getTaskRunRules("test-run-1")).toEqual([]);
160
+ expect(getTaskRunRules("test-run-2")).toHaveLength(2);
141
161
  });
142
162
  });
143
163
 
144
- describe('findHighestPriorityRule with ephemeral rules', () => {
164
+ describe("findHighestPriorityRule with ephemeral rules", () => {
145
165
  beforeEach(() => {
146
166
  clearCache();
147
167
  });
148
168
 
149
- test('ephemeral rules are found by findHighestPriorityRule', () => {
150
- const ephemeralRules: TrustRule[] = [{
151
- id: 'ephemeral:run-1:file_read',
152
- tool: 'file_read',
153
- pattern: '**',
154
- scope: '/home/user/project',
155
- decision: 'allow',
156
- priority: 50,
157
- createdAt: Date.now(),
158
- }];
169
+ test("ephemeral rules are found by findHighestPriorityRule", () => {
170
+ const ephemeralRules: TrustRule[] = [
171
+ {
172
+ id: "ephemeral:run-1:file_read",
173
+ tool: "file_read",
174
+ pattern: "**",
175
+ scope: "/home/user/project",
176
+ decision: "allow",
177
+ priority: 50,
178
+ createdAt: Date.now(),
179
+ },
180
+ ];
159
181
 
160
182
  const ctx: PolicyContext = {
161
183
  ephemeralRules,
162
184
  };
163
185
 
164
186
  const result = findHighestPriorityRule(
165
- 'file_read',
166
- ['file_read:/home/user/project/foo.txt'],
167
- '/home/user/project',
187
+ "file_read",
188
+ ["file_read:/home/user/project/foo.txt"],
189
+ "/home/user/project",
168
190
  ctx,
169
191
  );
170
192
 
171
193
  expect(result).not.toBeNull();
172
- expect(result!.id).toBe('ephemeral:run-1:file_read');
173
- expect(result!.decision).toBe('allow');
194
+ expect(result!.id).toBe("ephemeral:run-1:file_read");
195
+ expect(result!.decision).toBe("allow");
174
196
  });
175
197
 
176
- test('user deny rules at higher priority override ephemeral allow rules', () => {
198
+ test("user deny rules at higher priority override ephemeral allow rules", () => {
177
199
  // Add a persistent user deny rule with priority 100
178
- addRule('file_read', '**', '/home/user/project', 'deny', 100);
179
-
180
- const ephemeralRules: TrustRule[] = [{
181
- id: 'ephemeral:run-1:file_read',
182
- tool: 'file_read',
183
- pattern: '**',
184
- scope: '/home/user/project',
185
- decision: 'allow',
186
- priority: 50,
187
- createdAt: Date.now(),
188
- }];
200
+ addRule("file_read", "**", "/home/user/project", "deny", 100);
201
+
202
+ const ephemeralRules: TrustRule[] = [
203
+ {
204
+ id: "ephemeral:run-1:file_read",
205
+ tool: "file_read",
206
+ pattern: "**",
207
+ scope: "/home/user/project",
208
+ decision: "allow",
209
+ priority: 50,
210
+ createdAt: Date.now(),
211
+ },
212
+ ];
189
213
 
190
214
  const ctx: PolicyContext = {
191
215
  ephemeralRules,
192
216
  };
193
217
 
194
218
  const result = findHighestPriorityRule(
195
- 'file_read',
196
- ['file_read:/home/user/project/foo.txt'],
197
- '/home/user/project',
219
+ "file_read",
220
+ ["file_read:/home/user/project/foo.txt"],
221
+ "/home/user/project",
198
222
  ctx,
199
223
  );
200
224
 
201
225
  expect(result).not.toBeNull();
202
226
  // The user deny rule (priority 100) should win over the ephemeral allow (priority 50)
203
- expect(result!.decision).toBe('deny');
227
+ expect(result!.decision).toBe("deny");
204
228
  });
205
229
 
206
- test('ephemeral rules do not match when scope is outside working dir', () => {
207
- const ephemeralRules: TrustRule[] = [{
208
- id: 'ephemeral:run-1:file_read',
209
- tool: 'file_read',
210
- pattern: '**',
211
- scope: '/home/user/project',
212
- decision: 'allow',
213
- priority: 50,
214
- createdAt: Date.now(),
215
- }];
230
+ test("ephemeral rules do not match when scope is outside working dir", () => {
231
+ const ephemeralRules: TrustRule[] = [
232
+ {
233
+ id: "ephemeral:run-1:file_read",
234
+ tool: "file_read",
235
+ pattern: "**",
236
+ scope: "/home/user/project",
237
+ decision: "allow",
238
+ priority: 50,
239
+ createdAt: Date.now(),
240
+ },
241
+ ];
216
242
 
217
243
  const ctx: PolicyContext = {
218
244
  ephemeralRules,
@@ -220,64 +246,63 @@ describe('ephemeral-permissions', () => {
220
246
 
221
247
  // Query with a different scope that doesn't match the ephemeral rule's scope
222
248
  const result = findHighestPriorityRule(
223
- 'file_read',
224
- ['file_read:/other/path/foo.txt'],
225
- '/other/path',
249
+ "file_read",
250
+ ["file_read:/other/path/foo.txt"],
251
+ "/other/path",
226
252
  ctx,
227
253
  );
228
254
 
229
255
  // Should not match the ephemeral rule (scope mismatch)
230
256
  // May or may not match a default rule
231
257
  if (result) {
232
- expect(result.id).not.toBe('ephemeral:run-1:file_read');
258
+ expect(result.id).not.toBe("ephemeral:run-1:file_read");
233
259
  }
234
260
  });
235
261
  });
236
262
 
237
- describe('check() with ephemeral rules', () => {
263
+ describe("check() with ephemeral rules", () => {
238
264
  beforeEach(() => {
239
265
  clearCache();
240
- testConfig.permissions.mode = 'legacy';
266
+ testConfig.permissions.mode = "legacy";
241
267
  });
242
268
 
243
- test('ephemeral allow rule auto-allows non-high-risk tool', async () => {
244
- const ephemeralRules: TrustRule[] = [{
245
- id: 'ephemeral:run-1:file_read',
246
- tool: 'file_read',
247
- pattern: '**',
248
- scope: 'everywhere',
249
- decision: 'allow',
250
- priority: 50,
251
- createdAt: Date.now(),
252
- }];
269
+ test("ephemeral allow rule auto-allows non-high-risk tool", async () => {
270
+ const ephemeralRules: TrustRule[] = [
271
+ {
272
+ id: "ephemeral:run-1:file_read",
273
+ tool: "file_read",
274
+ pattern: "**",
275
+ scope: "everywhere",
276
+ decision: "allow",
277
+ priority: 50,
278
+ createdAt: Date.now(),
279
+ },
280
+ ];
253
281
 
254
282
  const ctx: PolicyContext = {
255
283
  ephemeralRules,
256
284
  };
257
285
 
258
286
  // Use testDir (a real temp path) to avoid EPERM on macOS /home
259
- const fakePath = join(testDir, 'foo.txt');
260
- const result = await check(
261
- 'file_read',
262
- { path: fakePath },
263
- testDir,
264
- ctx,
265
- );
287
+ const fakePath = join(testDir, "foo.txt");
288
+ const result = await check("file_read", { path: fakePath }, testDir, ctx);
266
289
 
267
- expect(result.decision).toBe('allow');
290
+ expect(result.decision).toBe("allow");
268
291
  });
269
292
 
270
- test('high-risk tool still prompts even with ephemeral allow rule (no allowHighRisk)', async () => {
271
- const ephemeralRules: TrustRule[] = [{
272
- id: 'ephemeral:run-1:bash',
273
- tool: 'bash',
274
- pattern: '**',
275
- scope: 'everywhere',
276
- decision: 'allow',
277
- priority: 50,
278
- createdAt: Date.now(),
279
- // Note: allowHighRisk is NOT set
280
- }];
293
+ test("high-risk tool still prompts even with ephemeral allow rule (no allowHighRisk)", async () => {
294
+ const ephemeralRules: TrustRule[] = [
295
+ {
296
+ id: "ephemeral:run-1:bash",
297
+ tool: "bash",
298
+ pattern: "**",
299
+ scope: "everywhere",
300
+ decision: "allow",
301
+ priority: 50,
302
+ createdAt: Date.now(),
303
+ // Note: allowHighRisk is NOT set
304
+ },
305
+ ];
281
306
 
282
307
  const ctx: PolicyContext = {
283
308
  ephemeralRules,
@@ -285,79 +310,90 @@ describe('ephemeral-permissions', () => {
285
310
 
286
311
  // sudo is high-risk
287
312
  const result = await check(
288
- 'bash',
289
- { command: 'sudo rm -rf /' },
290
- '/home/user/project',
313
+ "bash",
314
+ { command: "sudo rm -rf /" },
315
+ "/home/user/project",
291
316
  ctx,
292
317
  );
293
318
 
294
- expect(result.decision).toBe('prompt');
319
+ expect(result.decision).toBe("prompt");
295
320
  });
296
321
  });
297
322
 
298
- describe('workspace mode interactions', () => {
323
+ describe("workspace mode interactions", () => {
299
324
  beforeEach(() => {
300
325
  clearCache();
301
- testConfig.permissions.mode = 'workspace';
326
+ testConfig.permissions.mode = "workspace";
302
327
  });
303
328
 
304
329
  afterEach(() => {
305
- testConfig.permissions.mode = 'legacy';
330
+ testConfig.permissions.mode = "legacy";
306
331
  });
307
332
 
308
- test('workspace mode auto-allows workspace-scoped file_write (medium risk)', async () => {
309
- const filePath = join(testDir, 'workspace-test-file.txt');
310
- const result = await check('file_write', { path: filePath }, testDir);
311
- expect(result.decision).toBe('allow');
312
- expect(result.reason).toContain('Workspace mode');
333
+ test("workspace mode auto-allows workspace-scoped file_write (medium risk)", async () => {
334
+ const filePath = join(testDir, "workspace-test-file.txt");
335
+ const result = await check("file_write", { path: filePath }, testDir);
336
+ expect(result.decision).toBe("allow");
337
+ expect(result.reason).toContain("Workspace mode");
313
338
  });
314
339
 
315
- test('workspace mode still prompts for file_write outside workspace', async () => {
316
- const result = await check('file_write', { path: '/etc/config' }, testDir);
317
- expect(result.decision).toBe('prompt');
340
+ test("workspace mode still prompts for file_write outside workspace", async () => {
341
+ const result = await check(
342
+ "file_write",
343
+ { path: "/etc/config" },
344
+ testDir,
345
+ );
346
+ expect(result.decision).toBe("prompt");
318
347
  });
319
348
 
320
- test('explicit deny rule overrides workspace mode auto-allow', async () => {
321
- addRule('file_write', '**', testDir, 'deny', 100);
322
- const filePath = join(testDir, 'should-be-denied.txt');
323
- const result = await check('file_write', { path: filePath }, testDir);
324
- expect(result.decision).toBe('deny');
349
+ test("explicit deny rule overrides workspace mode auto-allow", async () => {
350
+ addRule("file_write", "**", testDir, "deny", 100);
351
+ const filePath = join(testDir, "should-be-denied.txt");
352
+ const result = await check("file_write", { path: filePath }, testDir);
353
+ expect(result.decision).toBe("deny");
325
354
  });
326
355
 
327
- test('proxied bash still prompts in workspace mode', async () => {
356
+ test("proxied bash still prompts in workspace mode", async () => {
328
357
  const result = await check(
329
- 'bash',
330
- { command: 'echo hello', network_mode: 'proxied' },
358
+ "bash",
359
+ { command: "echo hello", network_mode: "proxied" },
331
360
  testDir,
332
361
  );
333
- expect(result.decision).toBe('prompt');
334
- expect(result.reason).toContain('Proxied');
362
+ expect(result.decision).toBe("prompt");
363
+ expect(result.reason).toContain("Proxied");
335
364
  });
336
365
 
337
- test('ephemeral task rules + workspace mode: deny rule wins', async () => {
366
+ test("ephemeral task rules + workspace mode: deny rule wins", async () => {
338
367
  // Add a persistent deny rule for file_write in the workspace
339
- addRule('file_write', '**', testDir, 'deny', 100);
368
+ addRule("file_write", "**", testDir, "deny", 100);
340
369
 
341
370
  // Create ephemeral allow rules (lower priority than deny)
342
- const ephemeralRules: TrustRule[] = [{
343
- id: 'ephemeral:run-ws:file_write',
344
- tool: 'file_write',
345
- pattern: '**',
346
- scope: testDir,
347
- decision: 'allow',
348
- priority: 50,
349
- createdAt: Date.now(),
350
- }];
371
+ const ephemeralRules: TrustRule[] = [
372
+ {
373
+ id: "ephemeral:run-ws:file_write",
374
+ tool: "file_write",
375
+ pattern: "**",
376
+ scope: testDir,
377
+ decision: "allow",
378
+ priority: 50,
379
+ createdAt: Date.now(),
380
+ },
381
+ ];
351
382
 
352
383
  const ctx: PolicyContext = {
353
384
  ephemeralRules,
354
385
  };
355
386
 
356
- const filePath = join(testDir, 'task-file.txt');
357
- const result = await check('file_write', { path: filePath }, testDir, ctx);
387
+ const filePath = join(testDir, "task-file.txt");
388
+ const result = await check(
389
+ "file_write",
390
+ { path: filePath },
391
+ testDir,
392
+ ctx,
393
+ );
358
394
  // The persistent deny rule (priority 100) should override
359
395
  // both the ephemeral allow (priority 50) and workspace mode auto-allow
360
- expect(result.decision).toBe('deny');
396
+ expect(result.decision).toBe("deny");
361
397
  });
362
398
  });
363
399
  });