@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,7 +1,7 @@
1
- import { describe, expect,test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
- import type { CredentialMetadata } from '../tools/credentials/metadata-store.js';
4
- import { rankCredentialsForEndpoint } from '../tools/credentials/selection.js';
3
+ import type { CredentialMetadata } from "../tools/credentials/metadata-store.js";
4
+ import { rankCredentialsForEndpoint } from "../tools/credentials/selection.js";
5
5
 
6
6
  // Realistic epoch-millisecond timestamps (similar to Date.now())
7
7
  const NOW = 1_770_000_000_000;
@@ -9,10 +9,12 @@ const ONE_HOUR_AGO = NOW - 3_600_000;
9
9
  const ONE_DAY_AGO = NOW - 86_400_000;
10
10
  const ONE_WEEK_AGO = NOW - 604_800_000;
11
11
 
12
- function makeCred(overrides: Partial<CredentialMetadata> & { credentialId: string }): CredentialMetadata {
12
+ function makeCred(
13
+ overrides: Partial<CredentialMetadata> & { credentialId: string },
14
+ ): CredentialMetadata {
13
15
  return {
14
- service: 'test',
15
- field: 'api_key',
16
+ service: "test",
17
+ field: "api_key",
16
18
  allowedTools: [],
17
19
  allowedDomains: [],
18
20
  createdAt: ONE_DAY_AGO,
@@ -21,333 +23,439 @@ function makeCred(overrides: Partial<CredentialMetadata> & { credentialId: strin
21
23
  };
22
24
  }
23
25
 
24
- describe('rankCredentialsForEndpoint', () => {
25
- test('returns null topChoice for empty credentials list', () => {
26
- const result = rankCredentialsForEndpoint([], 'api.example.com');
26
+ describe("rankCredentialsForEndpoint", () => {
27
+ test("returns null topChoice for empty credentials list", () => {
28
+ const result = rankCredentialsForEndpoint([], "api.example.com");
27
29
  expect(result.topChoice).toBeNull();
28
30
  expect(result.candidates).toHaveLength(0);
29
31
  expect(result.ambiguous).toBe(false);
30
32
  });
31
33
 
32
- test('exact host match ranks higher than wildcard', () => {
34
+ test("exact host match ranks higher than wildcard", () => {
33
35
  const creds = [
34
36
  makeCred({
35
- credentialId: 'wildcard',
36
- injectionTemplates: [{ hostPattern: '*.fal.ai', injectionType: 'header', headerName: 'Authorization' }],
37
+ credentialId: "wildcard",
38
+ injectionTemplates: [
39
+ {
40
+ hostPattern: "*.fal.ai",
41
+ injectionType: "header",
42
+ headerName: "Authorization",
43
+ },
44
+ ],
37
45
  updatedAt: NOW,
38
46
  }),
39
47
  makeCred({
40
- credentialId: 'exact',
41
- injectionTemplates: [{ hostPattern: 'queue.fal.ai', injectionType: 'header', headerName: 'Authorization' }],
48
+ credentialId: "exact",
49
+ injectionTemplates: [
50
+ {
51
+ hostPattern: "queue.fal.ai",
52
+ injectionType: "header",
53
+ headerName: "Authorization",
54
+ },
55
+ ],
42
56
  updatedAt: ONE_WEEK_AGO,
43
57
  }),
44
58
  ];
45
59
 
46
- const result = rankCredentialsForEndpoint(creds, 'queue.fal.ai');
47
- expect(result.topChoice?.credentialId).toBe('exact');
48
- expect(result.topChoice?.confidence).toBe('high');
60
+ const result = rankCredentialsForEndpoint(creds, "queue.fal.ai");
61
+ expect(result.topChoice?.credentialId).toBe("exact");
62
+ expect(result.topChoice?.confidence).toBe("high");
49
63
  expect(result.ambiguous).toBe(false);
50
64
  });
51
65
 
52
- test('wildcard match ranks higher than no template match', () => {
66
+ test("wildcard match ranks higher than no template match", () => {
53
67
  const creds = [
54
- makeCred({ credentialId: 'no-template', updatedAt: NOW }),
68
+ makeCred({ credentialId: "no-template", updatedAt: NOW }),
55
69
  makeCred({
56
- credentialId: 'wildcard',
57
- injectionTemplates: [{ hostPattern: '*.openai.com', injectionType: 'header', headerName: 'Authorization' }],
70
+ credentialId: "wildcard",
71
+ injectionTemplates: [
72
+ {
73
+ hostPattern: "*.openai.com",
74
+ injectionType: "header",
75
+ headerName: "Authorization",
76
+ },
77
+ ],
58
78
  updatedAt: ONE_WEEK_AGO,
59
79
  }),
60
80
  ];
61
81
 
62
- const result = rankCredentialsForEndpoint(creds, 'api.openai.com');
63
- expect(result.topChoice?.credentialId).toBe('wildcard');
64
- expect(result.topChoice?.confidence).toBe('medium');
82
+ const result = rankCredentialsForEndpoint(creds, "api.openai.com");
83
+ expect(result.topChoice?.credentialId).toBe("wildcard");
84
+ expect(result.topChoice?.confidence).toBe("medium");
65
85
  });
66
86
 
67
- test('wildcard *.example.com also matches bare example.com', () => {
87
+ test("wildcard *.example.com also matches bare example.com", () => {
68
88
  const creds = [
69
89
  makeCred({
70
- credentialId: 'wild',
71
- injectionTemplates: [{ hostPattern: '*.example.com', injectionType: 'header' }],
90
+ credentialId: "wild",
91
+ injectionTemplates: [
92
+ { hostPattern: "*.example.com", injectionType: "header" },
93
+ ],
72
94
  }),
73
95
  ];
74
96
 
75
- const result = rankCredentialsForEndpoint(creds, 'example.com');
76
- expect(result.topChoice?.credentialId).toBe('wild');
77
- expect(result.topChoice?.confidence).toBe('medium');
97
+ const result = rankCredentialsForEndpoint(creds, "example.com");
98
+ expect(result.topChoice?.credentialId).toBe("wild");
99
+ expect(result.topChoice?.confidence).toBe("medium");
78
100
  });
79
101
 
80
- test('alias set boosts score', () => {
102
+ test("alias set boosts score", () => {
81
103
  const creds = [
82
- makeCred({ credentialId: 'no-alias', updatedAt: NOW }),
83
- makeCred({ credentialId: 'with-alias', alias: 'primary-key', updatedAt: ONE_WEEK_AGO }),
104
+ makeCred({ credentialId: "no-alias", updatedAt: NOW }),
105
+ makeCred({
106
+ credentialId: "with-alias",
107
+ alias: "primary-key",
108
+ updatedAt: ONE_WEEK_AGO,
109
+ }),
84
110
  ];
85
111
 
86
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
87
- expect(result.topChoice?.credentialId).toBe('with-alias');
112
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
113
+ expect(result.topChoice?.credentialId).toBe("with-alias");
88
114
  });
89
115
 
90
- test('recency breaks ties when host specificity and alias are equal', () => {
116
+ test("recency breaks ties when host specificity and alias are equal", () => {
91
117
  const creds = [
92
- makeCred({ credentialId: 'older', updatedAt: ONE_DAY_AGO }),
93
- makeCred({ credentialId: 'newer', updatedAt: NOW }),
118
+ makeCred({ credentialId: "older", updatedAt: ONE_DAY_AGO }),
119
+ makeCred({ credentialId: "newer", updatedAt: NOW }),
94
120
  ];
95
121
 
96
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
97
- expect(result.topChoice?.credentialId).toBe('newer');
122
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
123
+ expect(result.topChoice?.credentialId).toBe("newer");
98
124
  });
99
125
 
100
- test('filters out credentials with non-matching allowedDomains', () => {
126
+ test("filters out credentials with non-matching allowedDomains", () => {
101
127
  const creds = [
102
128
  makeCred({
103
- credentialId: 'restricted',
104
- allowedDomains: ['other.com'],
129
+ credentialId: "restricted",
130
+ allowedDomains: ["other.com"],
105
131
  }),
106
132
  makeCred({
107
- credentialId: 'unrestricted',
133
+ credentialId: "unrestricted",
108
134
  // empty allowedDomains = no restriction
109
135
  }),
110
136
  ];
111
137
 
112
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
138
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
113
139
  expect(result.candidates).toHaveLength(1);
114
- expect(result.topChoice?.credentialId).toBe('unrestricted');
140
+ expect(result.topChoice?.credentialId).toBe("unrestricted");
115
141
  });
116
142
 
117
- test('allowedDomains with registrable-domain match allows subdomains', () => {
143
+ test("allowedDomains with registrable-domain match allows subdomains", () => {
118
144
  const creds = [
119
145
  makeCred({
120
- credentialId: 'domain-match',
121
- allowedDomains: ['fal.ai'],
122
- injectionTemplates: [{ hostPattern: '*.fal.ai', injectionType: 'header', headerName: 'Authorization' }],
146
+ credentialId: "domain-match",
147
+ allowedDomains: ["fal.ai"],
148
+ injectionTemplates: [
149
+ {
150
+ hostPattern: "*.fal.ai",
151
+ injectionType: "header",
152
+ headerName: "Authorization",
153
+ },
154
+ ],
123
155
  }),
124
156
  ];
125
157
 
126
- const result = rankCredentialsForEndpoint(creds, 'queue.fal.ai');
158
+ const result = rankCredentialsForEndpoint(creds, "queue.fal.ai");
127
159
  expect(result.candidates).toHaveLength(1);
128
- expect(result.topChoice?.credentialId).toBe('domain-match');
160
+ expect(result.topChoice?.credentialId).toBe("domain-match");
129
161
  });
130
162
 
131
- test('ambiguous is true when top two candidates are in the same scoring tier', () => {
163
+ test("ambiguous is true when top two candidates are in the same scoring tier", () => {
132
164
  const creds = [
133
165
  makeCred({
134
- credentialId: 'a',
135
- injectionTemplates: [{ hostPattern: '*.api.com', injectionType: 'header' }],
166
+ credentialId: "a",
167
+ injectionTemplates: [
168
+ { hostPattern: "*.api.com", injectionType: "header" },
169
+ ],
136
170
  updatedAt: NOW,
137
171
  }),
138
172
  makeCred({
139
- credentialId: 'b',
140
- injectionTemplates: [{ hostPattern: '*.api.com', injectionType: 'header' }],
173
+ credentialId: "b",
174
+ injectionTemplates: [
175
+ { hostPattern: "*.api.com", injectionType: "header" },
176
+ ],
141
177
  updatedAt: ONE_HOUR_AGO,
142
178
  }),
143
179
  ];
144
180
 
145
- const result = rankCredentialsForEndpoint(creds, 'v1.api.com');
181
+ const result = rankCredentialsForEndpoint(creds, "v1.api.com");
146
182
  expect(result.ambiguous).toBe(true);
147
- expect(result.topChoice?.confidence).toBe('low');
183
+ expect(result.topChoice?.confidence).toBe("low");
148
184
  });
149
185
 
150
- test('ambiguous is false when top candidate is in a strictly higher tier', () => {
186
+ test("ambiguous is false when top candidate is in a strictly higher tier", () => {
151
187
  const creds = [
152
188
  makeCred({
153
- credentialId: 'exact',
154
- injectionTemplates: [{ hostPattern: 'api.example.com', injectionType: 'header' }],
189
+ credentialId: "exact",
190
+ injectionTemplates: [
191
+ { hostPattern: "api.example.com", injectionType: "header" },
192
+ ],
155
193
  updatedAt: ONE_WEEK_AGO,
156
194
  }),
157
195
  makeCred({
158
- credentialId: 'wildcard',
159
- injectionTemplates: [{ hostPattern: '*.example.com', injectionType: 'header' }],
196
+ credentialId: "wildcard",
197
+ injectionTemplates: [
198
+ { hostPattern: "*.example.com", injectionType: "header" },
199
+ ],
160
200
  updatedAt: NOW,
161
201
  }),
162
202
  ];
163
203
 
164
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
204
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
165
205
  expect(result.ambiguous).toBe(false);
166
- expect(result.topChoice?.credentialId).toBe('exact');
206
+ expect(result.topChoice?.credentialId).toBe("exact");
167
207
  });
168
208
 
169
- test('candidates are sorted descending by score', () => {
209
+ test("candidates are sorted descending by score", () => {
170
210
  const creds = [
171
- makeCred({ credentialId: 'low', updatedAt: NOW }),
211
+ makeCred({ credentialId: "low", updatedAt: NOW }),
172
212
  makeCred({
173
- credentialId: 'high',
174
- injectionTemplates: [{ hostPattern: 'api.test.com', injectionType: 'header' }],
175
- alias: 'primary',
213
+ credentialId: "high",
214
+ injectionTemplates: [
215
+ { hostPattern: "api.test.com", injectionType: "header" },
216
+ ],
217
+ alias: "primary",
176
218
  updatedAt: ONE_WEEK_AGO,
177
219
  }),
178
220
  makeCred({
179
- credentialId: 'mid',
180
- injectionTemplates: [{ hostPattern: '*.test.com', injectionType: 'header' }],
221
+ credentialId: "mid",
222
+ injectionTemplates: [
223
+ { hostPattern: "*.test.com", injectionType: "header" },
224
+ ],
181
225
  updatedAt: ONE_DAY_AGO,
182
226
  }),
183
227
  ];
184
228
 
185
- const result = rankCredentialsForEndpoint(creds, 'api.test.com');
186
- expect(result.candidates.map((c) => c.credentialId)).toEqual(['high', 'mid', 'low']);
229
+ const result = rankCredentialsForEndpoint(creds, "api.test.com");
230
+ expect(result.candidates.map((c) => c.credentialId)).toEqual([
231
+ "high",
232
+ "mid",
233
+ "low",
234
+ ]);
187
235
  });
188
236
 
189
- test('match reasons reflect actual matching criteria', () => {
237
+ test("match reasons reflect actual matching criteria", () => {
190
238
  const creds = [
191
239
  makeCred({
192
- credentialId: 'full',
193
- injectionTemplates: [{ hostPattern: 'api.test.com', injectionType: 'header' }],
194
- alias: 'my-key',
240
+ credentialId: "full",
241
+ injectionTemplates: [
242
+ { hostPattern: "api.test.com", injectionType: "header" },
243
+ ],
244
+ alias: "my-key",
195
245
  }),
196
246
  ];
197
247
 
198
- const result = rankCredentialsForEndpoint(creds, 'api.test.com');
199
- expect(result.candidates[0].matchReason).toContain('exact host match');
200
- expect(result.candidates[0].matchReason).toContain('alias set');
248
+ const result = rankCredentialsForEndpoint(creds, "api.test.com");
249
+ expect(result.candidates[0].matchReason).toContain("exact host match");
250
+ expect(result.candidates[0].matchReason).toContain("alias set");
201
251
  });
202
252
 
203
- test('credential with no templates and no alias gets domain allowed reason', () => {
204
- const creds = [makeCred({ credentialId: 'basic' })];
205
- const result = rankCredentialsForEndpoint(creds, 'api.test.com');
206
- expect(result.candidates[0].matchReason).toBe('domain allowed');
253
+ test("credential with no templates and no alias gets domain allowed reason", () => {
254
+ const creds = [makeCred({ credentialId: "basic" })];
255
+ const result = rankCredentialsForEndpoint(creds, "api.test.com");
256
+ expect(result.candidates[0].matchReason).toBe("domain allowed");
207
257
  });
208
258
 
209
- test('single credential returns non-ambiguous result', () => {
259
+ test("single credential returns non-ambiguous result", () => {
210
260
  const creds = [
211
261
  makeCred({
212
- credentialId: 'only',
213
- injectionTemplates: [{ hostPattern: '*.example.com', injectionType: 'query', queryParamName: 'key' }],
262
+ credentialId: "only",
263
+ injectionTemplates: [
264
+ {
265
+ hostPattern: "*.example.com",
266
+ injectionType: "query",
267
+ queryParamName: "key",
268
+ },
269
+ ],
214
270
  }),
215
271
  ];
216
272
 
217
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
273
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
218
274
  expect(result.ambiguous).toBe(false);
219
- expect(result.topChoice?.credentialId).toBe('only');
220
- expect(result.topChoice?.confidence).toBe('medium');
275
+ expect(result.topChoice?.credentialId).toBe("only");
276
+ expect(result.topChoice?.confidence).toBe("medium");
221
277
  expect(result.candidates).toHaveLength(1);
222
278
  });
223
279
 
224
- test('host matching is case-insensitive', () => {
280
+ test("host matching is case-insensitive", () => {
225
281
  const creds = [
226
282
  makeCred({
227
- credentialId: 'case',
228
- injectionTemplates: [{ hostPattern: 'API.Example.COM', injectionType: 'header' }],
283
+ credentialId: "case",
284
+ injectionTemplates: [
285
+ { hostPattern: "API.Example.COM", injectionType: "header" },
286
+ ],
229
287
  }),
230
288
  ];
231
289
 
232
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
233
- expect(result.topChoice?.credentialId).toBe('case');
234
- expect(result.topChoice?.confidence).toBe('high');
290
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
291
+ expect(result.topChoice?.credentialId).toBe("case");
292
+ expect(result.topChoice?.confidence).toBe("high");
235
293
  });
236
294
 
237
- test('tier score always dominates recency even with real timestamps', () => {
295
+ test("tier score always dominates recency even with real timestamps", () => {
238
296
  const creds = [
239
297
  makeCred({
240
- credentialId: 'old-exact',
241
- injectionTemplates: [{ hostPattern: 'api.example.com', injectionType: 'header' }],
298
+ credentialId: "old-exact",
299
+ injectionTemplates: [
300
+ { hostPattern: "api.example.com", injectionType: "header" },
301
+ ],
242
302
  updatedAt: ONE_WEEK_AGO,
243
303
  }),
244
304
  makeCred({
245
- credentialId: 'new-no-match',
305
+ credentialId: "new-no-match",
246
306
  updatedAt: NOW,
247
307
  }),
248
308
  ];
249
309
 
250
- const result = rankCredentialsForEndpoint(creds, 'api.example.com');
310
+ const result = rankCredentialsForEndpoint(creds, "api.example.com");
251
311
  // Exact host match must always win over recency
252
- expect(result.topChoice?.credentialId).toBe('old-exact');
253
- expect(result.topChoice?.confidence).toBe('high');
312
+ expect(result.topChoice?.credentialId).toBe("old-exact");
313
+ expect(result.topChoice?.confidence).toBe("high");
254
314
  });
255
315
  });
256
316
 
257
- describe('multi-key same-service selection', () => {
258
- test('two OpenAI credentials targeting the same endpoint — deterministic chosen credential_id', () => {
317
+ describe("multi-key same-service selection", () => {
318
+ test("two OpenAI credentials targeting the same endpoint — deterministic chosen credential_id", () => {
259
319
  const creds = [
260
320
  makeCred({
261
- credentialId: 'openai-key-1',
262
- service: 'openai',
263
- injectionTemplates: [{ hostPattern: 'api.openai.com', injectionType: 'header', headerName: 'Authorization' }],
321
+ credentialId: "openai-key-1",
322
+ service: "openai",
323
+ injectionTemplates: [
324
+ {
325
+ hostPattern: "api.openai.com",
326
+ injectionType: "header",
327
+ headerName: "Authorization",
328
+ },
329
+ ],
264
330
  updatedAt: ONE_DAY_AGO,
265
331
  }),
266
332
  makeCred({
267
- credentialId: 'openai-key-2',
268
- service: 'openai',
269
- injectionTemplates: [{ hostPattern: 'api.openai.com', injectionType: 'header', headerName: 'Authorization' }],
333
+ credentialId: "openai-key-2",
334
+ service: "openai",
335
+ injectionTemplates: [
336
+ {
337
+ hostPattern: "api.openai.com",
338
+ injectionType: "header",
339
+ headerName: "Authorization",
340
+ },
341
+ ],
270
342
  updatedAt: NOW,
271
343
  }),
272
344
  ];
273
345
 
274
- const result = rankCredentialsForEndpoint(creds, 'api.openai.com');
346
+ const result = rankCredentialsForEndpoint(creds, "api.openai.com");
275
347
  // Both have exact host match (tier score 100) — same tier, so ambiguous
276
348
  expect(result.ambiguous).toBe(true);
277
- expect(result.topChoice?.confidence).toBe('low');
349
+ expect(result.topChoice?.confidence).toBe("low");
278
350
  // Despite ambiguity, topChoice is deterministic: the more recent key wins.
279
- expect(result.topChoice?.credentialId).toBe('openai-key-2');
351
+ expect(result.topChoice?.credentialId).toBe("openai-key-2");
280
352
  expect(result.candidates).toHaveLength(2);
281
353
  });
282
354
 
283
- test('ambiguity fallback path when two credentials have identical scores', () => {
355
+ test("ambiguity fallback path when two credentials have identical scores", () => {
284
356
  const creds = [
285
357
  makeCred({
286
- credentialId: 'key-a',
287
- service: 'openai',
288
- injectionTemplates: [{ hostPattern: '*.openai.com', injectionType: 'header', headerName: 'Authorization' }],
358
+ credentialId: "key-a",
359
+ service: "openai",
360
+ injectionTemplates: [
361
+ {
362
+ hostPattern: "*.openai.com",
363
+ injectionType: "header",
364
+ headerName: "Authorization",
365
+ },
366
+ ],
289
367
  updatedAt: ONE_DAY_AGO,
290
368
  }),
291
369
  makeCred({
292
- credentialId: 'key-b',
293
- service: 'openai',
294
- injectionTemplates: [{ hostPattern: '*.openai.com', injectionType: 'header', headerName: 'Authorization' }],
370
+ credentialId: "key-b",
371
+ service: "openai",
372
+ injectionTemplates: [
373
+ {
374
+ hostPattern: "*.openai.com",
375
+ injectionType: "header",
376
+ headerName: "Authorization",
377
+ },
378
+ ],
295
379
  updatedAt: ONE_DAY_AGO,
296
380
  }),
297
381
  ];
298
382
 
299
- const result = rankCredentialsForEndpoint(creds, 'api.openai.com');
383
+ const result = rankCredentialsForEndpoint(creds, "api.openai.com");
300
384
  expect(result.ambiguous).toBe(true);
301
- expect(result.topChoice?.confidence).toBe('low');
385
+ expect(result.topChoice?.confidence).toBe("low");
302
386
  // Both candidates are present
303
387
  expect(result.candidates).toHaveLength(2);
304
388
  });
305
389
 
306
- test('one credential with specific host template wins over one with generic template', () => {
390
+ test("one credential with specific host template wins over one with generic template", () => {
307
391
  const creds = [
308
392
  makeCred({
309
- credentialId: 'generic-key',
310
- service: 'openai',
311
- injectionTemplates: [{ hostPattern: '*.openai.com', injectionType: 'header', headerName: 'Authorization' }],
393
+ credentialId: "generic-key",
394
+ service: "openai",
395
+ injectionTemplates: [
396
+ {
397
+ hostPattern: "*.openai.com",
398
+ injectionType: "header",
399
+ headerName: "Authorization",
400
+ },
401
+ ],
312
402
  updatedAt: NOW,
313
403
  }),
314
404
  makeCred({
315
- credentialId: 'specific-key',
316
- service: 'openai',
317
- injectionTemplates: [{ hostPattern: 'api.openai.com', injectionType: 'header', headerName: 'Authorization' }],
405
+ credentialId: "specific-key",
406
+ service: "openai",
407
+ injectionTemplates: [
408
+ {
409
+ hostPattern: "api.openai.com",
410
+ injectionType: "header",
411
+ headerName: "Authorization",
412
+ },
413
+ ],
318
414
  updatedAt: ONE_WEEK_AGO,
319
415
  }),
320
416
  ];
321
417
 
322
- const result = rankCredentialsForEndpoint(creds, 'api.openai.com');
418
+ const result = rankCredentialsForEndpoint(creds, "api.openai.com");
323
419
  // exact host (100) vs wildcard (50) — not ambiguous, specific key wins even though it's older
324
- expect(result.topChoice?.credentialId).toBe('specific-key');
325
- expect(result.topChoice?.confidence).toBe('high');
420
+ expect(result.topChoice?.credentialId).toBe("specific-key");
421
+ expect(result.topChoice?.confidence).toBe("high");
326
422
  expect(result.ambiguous).toBe(false);
327
423
  });
328
424
 
329
- test('both credentials have aliases — alias alone does not break ties', () => {
425
+ test("both credentials have aliases — alias alone does not break ties", () => {
330
426
  const creds = [
331
427
  makeCred({
332
- credentialId: 'aliased-1',
333
- service: 'openai',
334
- alias: 'production-key',
335
- injectionTemplates: [{ hostPattern: 'api.openai.com', injectionType: 'header', headerName: 'Authorization' }],
428
+ credentialId: "aliased-1",
429
+ service: "openai",
430
+ alias: "production-key",
431
+ injectionTemplates: [
432
+ {
433
+ hostPattern: "api.openai.com",
434
+ injectionType: "header",
435
+ headerName: "Authorization",
436
+ },
437
+ ],
336
438
  updatedAt: ONE_DAY_AGO,
337
439
  }),
338
440
  makeCred({
339
- credentialId: 'aliased-2',
340
- service: 'openai',
341
- alias: 'staging-key',
342
- injectionTemplates: [{ hostPattern: 'api.openai.com', injectionType: 'header', headerName: 'Authorization' }],
441
+ credentialId: "aliased-2",
442
+ service: "openai",
443
+ alias: "staging-key",
444
+ injectionTemplates: [
445
+ {
446
+ hostPattern: "api.openai.com",
447
+ injectionType: "header",
448
+ headerName: "Authorization",
449
+ },
450
+ ],
343
451
  updatedAt: ONE_DAY_AGO,
344
452
  }),
345
453
  ];
346
454
 
347
- const result = rankCredentialsForEndpoint(creds, 'api.openai.com');
455
+ const result = rankCredentialsForEndpoint(creds, "api.openai.com");
348
456
  // Both have exact host (100) + alias (10) = 110 tier score + identical recency
349
457
  expect(result.ambiguous).toBe(true);
350
- expect(result.topChoice?.confidence).toBe('low');
458
+ expect(result.topChoice?.confidence).toBe("low");
351
459
  expect(result.candidates).toHaveLength(2);
352
460
  // Both candidates have same tier score
353
461
  expect(result.candidates[0].score).toBe(result.candidates[1].score);