@vellumai/assistant 0.4.17 → 0.4.18

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 (515) hide show
  1. package/eslint.config.mjs +2 -2
  2. package/package.json +1 -1
  3. package/src/__tests__/access-request-decision.test.ts +128 -120
  4. package/src/__tests__/account-registry.test.ts +121 -110
  5. package/src/__tests__/active-skill-tools.test.ts +200 -172
  6. package/src/__tests__/actor-token-service.test.ts +341 -274
  7. package/src/__tests__/agent-loop-thinking.test.ts +28 -19
  8. package/src/__tests__/agent-loop.test.ts +798 -378
  9. package/src/__tests__/anthropic-provider.test.ts +405 -247
  10. package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
  11. package/src/__tests__/app-bundler.test.ts +112 -79
  12. package/src/__tests__/app-executors.test.ts +205 -178
  13. package/src/__tests__/app-git-history.test.ts +90 -73
  14. package/src/__tests__/app-git-service.test.ts +67 -53
  15. package/src/__tests__/app-open-proxy.test.ts +29 -25
  16. package/src/__tests__/approval-conversation-turn.test.ts +100 -81
  17. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
  18. package/src/__tests__/approval-message-composer.test.ts +119 -119
  19. package/src/__tests__/approval-primitive.test.ts +264 -233
  20. package/src/__tests__/approval-routes-http.test.ts +4 -3
  21. package/src/__tests__/asset-materialize-tool.test.ts +250 -178
  22. package/src/__tests__/asset-search-tool.test.ts +251 -191
  23. package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
  24. package/src/__tests__/assistant-attachments.test.ts +254 -186
  25. package/src/__tests__/assistant-event-hub.test.ts +105 -63
  26. package/src/__tests__/assistant-event.test.ts +66 -58
  27. package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
  28. package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
  29. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
  31. package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
  32. package/src/__tests__/attachments-store.test.ts +240 -183
  33. package/src/__tests__/attachments.test.ts +70 -62
  34. package/src/__tests__/audit-log-rotation.test.ts +50 -35
  35. package/src/__tests__/browser-fill-credential.test.ts +169 -101
  36. package/src/__tests__/browser-manager.test.ts +97 -75
  37. package/src/__tests__/browser-runtime-check.test.ts +16 -15
  38. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
  39. package/src/__tests__/browser-skill-endstate.test.ts +97 -72
  40. package/src/__tests__/bundle-scanner.test.ts +47 -22
  41. package/src/__tests__/bundled-asset.test.ts +74 -47
  42. package/src/__tests__/call-constants.test.ts +19 -19
  43. package/src/__tests__/call-controller.test.ts +0 -1
  44. package/src/__tests__/call-conversation-messages.test.ts +90 -65
  45. package/src/__tests__/call-domain.test.ts +149 -121
  46. package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
  47. package/src/__tests__/call-pointer-messages.test.ts +213 -154
  48. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
  49. package/src/__tests__/call-recovery.test.ts +232 -212
  50. package/src/__tests__/call-routes-http.test.ts +0 -1
  51. package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
  52. package/src/__tests__/call-state-machine.test.ts +62 -51
  53. package/src/__tests__/call-state.test.ts +89 -75
  54. package/src/__tests__/call-store.test.ts +387 -316
  55. package/src/__tests__/callback-handoff-copy.test.ts +84 -82
  56. package/src/__tests__/canonical-guardian-store.test.ts +331 -280
  57. package/src/__tests__/channel-approval-routes.test.ts +1643 -1115
  58. package/src/__tests__/channel-approval.test.ts +139 -137
  59. package/src/__tests__/channel-approvals.test.ts +0 -1
  60. package/src/__tests__/channel-delivery-store.test.ts +232 -194
  61. package/src/__tests__/channel-guardian.test.ts +5 -3
  62. package/src/__tests__/channel-invite-transport.test.ts +107 -92
  63. package/src/__tests__/channel-policy.test.ts +42 -38
  64. package/src/__tests__/channel-readiness-service.test.ts +119 -102
  65. package/src/__tests__/channel-reply-delivery.test.ts +147 -118
  66. package/src/__tests__/channel-retry-sweep.test.ts +153 -110
  67. package/src/__tests__/checker.test.ts +3309 -1850
  68. package/src/__tests__/clarification-resolver.test.ts +91 -79
  69. package/src/__tests__/classifier.test.ts +64 -54
  70. package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
  71. package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
  72. package/src/__tests__/clawhub.test.ts +92 -82
  73. package/src/__tests__/cli.test.ts +30 -30
  74. package/src/__tests__/clipboard.test.ts +53 -46
  75. package/src/__tests__/commit-guarantee.test.ts +59 -52
  76. package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
  77. package/src/__tests__/compaction.benchmark.test.ts +33 -31
  78. package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
  79. package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
  80. package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
  81. package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
  82. package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
  83. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
  84. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
  85. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
  86. package/src/__tests__/computer-use-tools.test.ts +121 -98
  87. package/src/__tests__/config-schema.test.ts +443 -347
  88. package/src/__tests__/config-watcher.test.ts +96 -81
  89. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
  90. package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
  91. package/src/__tests__/conflict-policy.test.ts +151 -80
  92. package/src/__tests__/conflict-store.test.ts +203 -157
  93. package/src/__tests__/connection-policy.test.ts +89 -59
  94. package/src/__tests__/contacts-tools.test.ts +247 -178
  95. package/src/__tests__/context-memory-e2e.test.ts +306 -214
  96. package/src/__tests__/context-token-estimator.test.ts +114 -74
  97. package/src/__tests__/context-window-manager.test.ts +269 -167
  98. package/src/__tests__/contradiction-checker.test.ts +161 -135
  99. package/src/__tests__/conversation-attention-store.test.ts +350 -290
  100. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  101. package/src/__tests__/conversation-pairing.test.ts +220 -113
  102. package/src/__tests__/conversation-store.test.ts +390 -235
  103. package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
  104. package/src/__tests__/credential-broker-server-use.test.ts +283 -243
  105. package/src/__tests__/credential-broker.test.ts +128 -74
  106. package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
  107. package/src/__tests__/credential-metadata-store.test.ts +360 -311
  108. package/src/__tests__/credential-policy-validate.test.ts +81 -65
  109. package/src/__tests__/credential-resolve.test.ts +212 -145
  110. package/src/__tests__/credential-security-e2e.test.ts +144 -103
  111. package/src/__tests__/credential-security-invariants.test.ts +253 -208
  112. package/src/__tests__/credential-selection.test.ts +254 -146
  113. package/src/__tests__/credential-vault-unit.test.ts +531 -341
  114. package/src/__tests__/credential-vault.test.ts +761 -484
  115. package/src/__tests__/daemon-assistant-events.test.ts +91 -66
  116. package/src/__tests__/daemon-lifecycle.test.ts +258 -190
  117. package/src/__tests__/daemon-server-session-init.test.ts +0 -1
  118. package/src/__tests__/date-context.test.ts +314 -249
  119. package/src/__tests__/db-migration-rollback.test.ts +259 -130
  120. package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
  121. package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
  122. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
  123. package/src/__tests__/dictation-mode-detection.test.ts +77 -55
  124. package/src/__tests__/dictation-profile-store.test.ts +70 -56
  125. package/src/__tests__/dictation-text-processing.test.ts +53 -35
  126. package/src/__tests__/diff.test.ts +102 -98
  127. package/src/__tests__/domain-normalize.test.ts +54 -54
  128. package/src/__tests__/domain-policy.test.ts +71 -55
  129. package/src/__tests__/dynamic-page-surface.test.ts +31 -33
  130. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
  131. package/src/__tests__/edit-engine.test.ts +56 -56
  132. package/src/__tests__/elevenlabs-client.test.ts +117 -91
  133. package/src/__tests__/elevenlabs-config.test.ts +32 -31
  134. package/src/__tests__/email-classifier.test.ts +15 -12
  135. package/src/__tests__/email-cli.test.ts +121 -108
  136. package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
  137. package/src/__tests__/encrypted-store.test.ts +180 -154
  138. package/src/__tests__/entity-extractor.test.ts +108 -87
  139. package/src/__tests__/entity-search.test.ts +664 -258
  140. package/src/__tests__/ephemeral-permissions.test.ts +224 -188
  141. package/src/__tests__/event-bus.test.ts +81 -77
  142. package/src/__tests__/extract-email.test.ts +29 -20
  143. package/src/__tests__/file-edit-tool.test.ts +62 -44
  144. package/src/__tests__/file-ops-service.test.ts +131 -114
  145. package/src/__tests__/file-read-tool.test.ts +48 -31
  146. package/src/__tests__/file-write-tool.test.ts +43 -37
  147. package/src/__tests__/filesystem-tools.test.ts +238 -209
  148. package/src/__tests__/followup-tools.test.ts +237 -162
  149. package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
  150. package/src/__tests__/frontmatter.test.ts +96 -81
  151. package/src/__tests__/fuzzy-match-property.test.ts +75 -81
  152. package/src/__tests__/fuzzy-match.test.ts +71 -65
  153. package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
  154. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  155. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  156. package/src/__tests__/gemini-image-service.test.ts +113 -100
  157. package/src/__tests__/gemini-provider.test.ts +297 -220
  158. package/src/__tests__/get-weather.test.ts +188 -114
  159. package/src/__tests__/gmail-integration.test.ts +0 -1
  160. package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
  161. package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
  162. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  163. package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
  164. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
  165. package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
  166. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
  167. package/src/__tests__/guardian-action-store.test.ts +158 -109
  168. package/src/__tests__/guardian-action-sweep.test.ts +114 -100
  169. package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
  170. package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
  171. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
  172. package/src/__tests__/guardian-dispatch.test.ts +316 -256
  173. package/src/__tests__/guardian-grant-minting.test.ts +247 -178
  174. package/src/__tests__/guardian-outbound-http.test.ts +5 -3
  175. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
  176. package/src/__tests__/guardian-question-copy.test.ts +17 -17
  177. package/src/__tests__/guardian-question-mode.test.ts +134 -100
  178. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  179. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  180. package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
  181. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  182. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
  183. package/src/__tests__/handle-user-message-secret-resume.test.ts +0 -1
  184. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
  185. package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
  186. package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
  187. package/src/__tests__/handlers-slack-config.test.ts +63 -54
  188. package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
  189. package/src/__tests__/handlers-telegram-config.test.ts +662 -329
  190. package/src/__tests__/handlers-twitter-config.test.ts +525 -298
  191. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -2
  192. package/src/__tests__/headless-browser-interactions.test.ts +444 -280
  193. package/src/__tests__/headless-browser-navigate.test.ts +116 -79
  194. package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
  195. package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
  196. package/src/__tests__/heartbeat-service.test.ts +76 -58
  197. package/src/__tests__/history-repair-observability.test.ts +14 -14
  198. package/src/__tests__/history-repair.test.ts +171 -167
  199. package/src/__tests__/home-base-bootstrap.test.ts +30 -27
  200. package/src/__tests__/hooks-blocking.test.ts +86 -37
  201. package/src/__tests__/hooks-cli.test.ts +104 -68
  202. package/src/__tests__/hooks-config.test.ts +81 -43
  203. package/src/__tests__/hooks-discovery.test.ts +106 -96
  204. package/src/__tests__/hooks-integration.test.ts +78 -72
  205. package/src/__tests__/hooks-manager.test.ts +99 -61
  206. package/src/__tests__/hooks-runner.test.ts +94 -71
  207. package/src/__tests__/hooks-settings.test.ts +69 -64
  208. package/src/__tests__/hooks-templates.test.ts +85 -54
  209. package/src/__tests__/hooks-ts-runner.test.ts +82 -45
  210. package/src/__tests__/hooks-watch.test.ts +32 -22
  211. package/src/__tests__/host-file-edit-tool.test.ts +190 -148
  212. package/src/__tests__/host-file-read-tool.test.ts +86 -63
  213. package/src/__tests__/host-file-write-tool.test.ts +98 -64
  214. package/src/__tests__/host-shell-tool.test.ts +342 -233
  215. package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
  216. package/src/__tests__/ingress-member-store.test.ts +163 -159
  217. package/src/__tests__/ingress-reconcile.test.ts +0 -1
  218. package/src/__tests__/ingress-routes-http.test.ts +441 -356
  219. package/src/__tests__/ingress-url-consistency.test.ts +125 -64
  220. package/src/__tests__/integration-status.test.ts +93 -73
  221. package/src/__tests__/intent-routing.test.ts +148 -118
  222. package/src/__tests__/invite-redemption-service.test.ts +163 -121
  223. package/src/__tests__/ipc-blob-store.test.ts +104 -91
  224. package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
  225. package/src/__tests__/ipc-contract.test.ts +24 -23
  226. package/src/__tests__/ipc-protocol.test.ts +52 -46
  227. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
  228. package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
  229. package/src/__tests__/ipc-validate.test.ts +240 -179
  230. package/src/__tests__/key-migration.test.ts +123 -90
  231. package/src/__tests__/keychain.test.ts +150 -123
  232. package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
  233. package/src/__tests__/llm-usage-store.test.ts +112 -87
  234. package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
  235. package/src/__tests__/managed-store.test.ts +411 -360
  236. package/src/__tests__/mcp-cli.test.ts +189 -123
  237. package/src/__tests__/mcp-health-check.test.ts +26 -21
  238. package/src/__tests__/media-generate-image.test.ts +122 -99
  239. package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
  240. package/src/__tests__/media-visibility-policy.test.ts +86 -38
  241. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
  242. package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
  243. package/src/__tests__/memory-query-builder.test.ts +32 -33
  244. package/src/__tests__/memory-recall-quality.test.ts +761 -407
  245. package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
  246. package/src/__tests__/memory-regressions.test.ts +3725 -2642
  247. package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
  248. package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
  249. package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
  250. package/src/__tests__/messaging-send-tool.test.ts +36 -29
  251. package/src/__tests__/migration-cli-flows.test.ts +69 -53
  252. package/src/__tests__/migration-ordering.test.ts +103 -86
  253. package/src/__tests__/mime-builder.test.ts +55 -32
  254. package/src/__tests__/mock-signup-server.test.ts +384 -246
  255. package/src/__tests__/model-intents.test.ts +61 -37
  256. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
  257. package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
  258. package/src/__tests__/non-member-access-request.test.ts +3 -2
  259. package/src/__tests__/notification-broadcaster.test.ts +99 -81
  260. package/src/__tests__/notification-decision-fallback.test.ts +223 -178
  261. package/src/__tests__/notification-decision-strategy.test.ts +375 -337
  262. package/src/__tests__/notification-deep-link.test.ts +67 -61
  263. package/src/__tests__/notification-guardian-path.test.ts +248 -206
  264. package/src/__tests__/notification-routing-intent.test.ts +166 -93
  265. package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
  266. package/src/__tests__/notification-thread-candidates.test.ts +64 -61
  267. package/src/__tests__/oauth-callback-registry.test.ts +40 -30
  268. package/src/__tests__/oauth-connect-handler.test.ts +109 -89
  269. package/src/__tests__/oauth-scope-policy.test.ts +63 -55
  270. package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
  271. package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
  272. package/src/__tests__/onboarding-template-contract.test.ts +93 -94
  273. package/src/__tests__/openai-provider.test.ts +366 -274
  274. package/src/__tests__/pairing-concurrent.test.ts +18 -12
  275. package/src/__tests__/pairing-routes.test.ts +45 -41
  276. package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
  277. package/src/__tests__/parser.test.ts +316 -226
  278. package/src/__tests__/path-classifier.test.ts +24 -25
  279. package/src/__tests__/path-policy.test.ts +187 -147
  280. package/src/__tests__/phone.test.ts +36 -36
  281. package/src/__tests__/platform-move-helper.test.ts +48 -40
  282. package/src/__tests__/platform-socket-path.test.ts +23 -24
  283. package/src/__tests__/platform-workspace-migration.test.ts +464 -414
  284. package/src/__tests__/platform.test.ts +61 -53
  285. package/src/__tests__/playbook-execution.test.ts +397 -265
  286. package/src/__tests__/playbook-tools.test.ts +267 -196
  287. package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
  288. package/src/__tests__/pricing.test.ts +316 -136
  289. package/src/__tests__/profile-compiler.test.ts +206 -188
  290. package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
  291. package/src/__tests__/provider-error-scenarios.test.ts +212 -158
  292. package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
  293. package/src/__tests__/provider-registry-ollama.test.ts +13 -9
  294. package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
  295. package/src/__tests__/proxy-approval-callback.test.ts +180 -119
  296. package/src/__tests__/public-ingress-urls.test.ts +112 -94
  297. package/src/__tests__/qdrant-manager.test.ts +147 -98
  298. package/src/__tests__/ratelimit.test.ts +152 -82
  299. package/src/__tests__/recording-handler.test.ts +273 -151
  300. package/src/__tests__/recording-intent-fallback.test.ts +94 -75
  301. package/src/__tests__/recording-intent-handler.test.ts +0 -1
  302. package/src/__tests__/recording-intent.test.ts +578 -379
  303. package/src/__tests__/recording-state-machine.test.ts +530 -316
  304. package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
  305. package/src/__tests__/recurrence-engine.test.ts +81 -41
  306. package/src/__tests__/recurrence-types.test.ts +63 -44
  307. package/src/__tests__/relay-server.test.ts +2131 -1602
  308. package/src/__tests__/reminder-store.test.ts +158 -80
  309. package/src/__tests__/reminder.test.ts +113 -109
  310. package/src/__tests__/remote-skill-policy.test.ts +96 -72
  311. package/src/__tests__/request-file-tool.test.ts +74 -67
  312. package/src/__tests__/response-tier.test.ts +131 -74
  313. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  314. package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
  315. package/src/__tests__/runtime-events-sse.test.ts +0 -1
  316. package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
  317. package/src/__tests__/sandbox-host-parity.test.ts +377 -301
  318. package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
  319. package/src/__tests__/schedule-store.test.ts +268 -205
  320. package/src/__tests__/schedule-tools.test.ts +702 -524
  321. package/src/__tests__/scheduler-recurrence.test.ts +240 -130
  322. package/src/__tests__/scoped-approval-grants.test.ts +258 -168
  323. package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
  324. package/src/__tests__/script-proxy-certs.test.ts +38 -35
  325. package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
  326. package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
  327. package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
  328. package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
  329. package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
  330. package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
  331. package/src/__tests__/script-proxy-policy.test.ts +308 -153
  332. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
  333. package/src/__tests__/script-proxy-router.test.ts +111 -77
  334. package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
  335. package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
  336. package/src/__tests__/secret-allowlist.test.ts +105 -90
  337. package/src/__tests__/secret-ingress-handler.test.ts +41 -30
  338. package/src/__tests__/secret-onetime-send.test.ts +67 -50
  339. package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
  340. package/src/__tests__/secret-response-routing.test.ts +50 -41
  341. package/src/__tests__/secret-scanner-executor.test.ts +152 -111
  342. package/src/__tests__/secret-scanner.test.ts +495 -413
  343. package/src/__tests__/secure-keys.test.ts +132 -121
  344. package/src/__tests__/send-endpoint-busy.test.ts +0 -1
  345. package/src/__tests__/send-notification-tool.test.ts +43 -42
  346. package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
  347. package/src/__tests__/sequence-store.test.ts +335 -167
  348. package/src/__tests__/server-history-render.test.ts +341 -202
  349. package/src/__tests__/session-abort-tool-results.test.ts +133 -70
  350. package/src/__tests__/session-confirmation-signals.test.ts +252 -160
  351. package/src/__tests__/session-conflict-gate.test.ts +775 -585
  352. package/src/__tests__/session-error.test.ts +222 -191
  353. package/src/__tests__/session-evictor.test.ts +79 -62
  354. package/src/__tests__/session-init.benchmark.test.ts +170 -108
  355. package/src/__tests__/session-load-history-repair.test.ts +273 -139
  356. package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
  357. package/src/__tests__/session-pre-run-repair.test.ts +106 -59
  358. package/src/__tests__/session-profile-injection.test.ts +198 -130
  359. package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
  360. package/src/__tests__/session-queue.test.ts +624 -321
  361. package/src/__tests__/session-runtime-assembly.test.ts +425 -329
  362. package/src/__tests__/session-runtime-workspace.test.ts +69 -61
  363. package/src/__tests__/session-skill-tools.test.ts +973 -678
  364. package/src/__tests__/session-slash-known.test.ts +185 -133
  365. package/src/__tests__/session-slash-queue.test.ts +147 -81
  366. package/src/__tests__/session-slash-unknown.test.ts +135 -90
  367. package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
  368. package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
  369. package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
  370. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
  371. package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
  372. package/src/__tests__/session-undo.test.ts +43 -30
  373. package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
  374. package/src/__tests__/session-workspace-injection.test.ts +245 -117
  375. package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
  376. package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
  377. package/src/__tests__/shell-credential-ref.test.ts +126 -90
  378. package/src/__tests__/shell-identity.test.ts +134 -111
  379. package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
  380. package/src/__tests__/shell-parser-property.test.ts +435 -288
  381. package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
  382. package/src/__tests__/size-guard.test.ts +42 -44
  383. package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
  384. package/src/__tests__/skill-feature-flags.test.ts +75 -47
  385. package/src/__tests__/skill-include-graph.test.ts +143 -148
  386. package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
  387. package/src/__tests__/skill-load-tool.test.ts +371 -199
  388. package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
  389. package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
  390. package/src/__tests__/skill-script-runner-host.test.ts +460 -250
  391. package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
  392. package/src/__tests__/skill-script-runner.test.ts +115 -74
  393. package/src/__tests__/skill-tool-factory.test.ts +140 -96
  394. package/src/__tests__/skill-tool-manifest.test.ts +306 -210
  395. package/src/__tests__/skill-version-hash.test.ts +70 -56
  396. package/src/__tests__/skills.test.ts +0 -1
  397. package/src/__tests__/slack-channel-config.test.ts +127 -84
  398. package/src/__tests__/slack-skill.test.ts +60 -47
  399. package/src/__tests__/slash-commands-catalog.test.ts +37 -31
  400. package/src/__tests__/slash-commands-parser.test.ts +71 -64
  401. package/src/__tests__/slash-commands-resolver.test.ts +143 -107
  402. package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
  403. package/src/__tests__/speaker-identification.test.ts +28 -25
  404. package/src/__tests__/starter-bundle.test.ts +27 -23
  405. package/src/__tests__/starter-task-flow.test.ts +67 -52
  406. package/src/__tests__/subagent-manager-notify.test.ts +154 -108
  407. package/src/__tests__/subagent-tools.test.ts +311 -270
  408. package/src/__tests__/subagent-types.test.ts +40 -40
  409. package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
  410. package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
  411. package/src/__tests__/swarm-orchestrator.test.ts +135 -101
  412. package/src/__tests__/swarm-plan-validator.test.ts +125 -73
  413. package/src/__tests__/swarm-recursion.test.ts +58 -46
  414. package/src/__tests__/swarm-router-planner.test.ts +99 -74
  415. package/src/__tests__/swarm-session-integration.test.ts +148 -91
  416. package/src/__tests__/swarm-tool.test.ts +65 -45
  417. package/src/__tests__/swarm-worker-backend.test.ts +59 -45
  418. package/src/__tests__/swarm-worker-runner.test.ts +133 -118
  419. package/src/__tests__/system-prompt.test.ts +290 -256
  420. package/src/__tests__/task-compiler.test.ts +176 -120
  421. package/src/__tests__/task-management-tools.test.ts +561 -456
  422. package/src/__tests__/task-memory-cleanup.test.ts +627 -362
  423. package/src/__tests__/task-runner.test.ts +117 -94
  424. package/src/__tests__/task-scheduler.test.ts +113 -84
  425. package/src/__tests__/task-tools.test.ts +349 -264
  426. package/src/__tests__/terminal-sandbox.test.ts +138 -108
  427. package/src/__tests__/terminal-tools.test.ts +350 -305
  428. package/src/__tests__/thread-seed-composer.test.ts +307 -180
  429. package/src/__tests__/tool-approval-handler.test.ts +238 -137
  430. package/src/__tests__/tool-audit-listener.test.ts +69 -69
  431. package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
  432. package/src/__tests__/tool-execution-abort-cleanup.test.ts +153 -146
  433. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
  434. package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
  435. package/src/__tests__/tool-executor-redaction.test.ts +112 -109
  436. package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
  437. package/src/__tests__/tool-executor.test.ts +1274 -674
  438. package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
  439. package/src/__tests__/tool-metrics-listener.test.ts +97 -85
  440. package/src/__tests__/tool-notification-listener.test.ts +42 -25
  441. package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
  442. package/src/__tests__/tool-policy.test.ts +44 -25
  443. package/src/__tests__/tool-profiling-listener.test.ts +99 -93
  444. package/src/__tests__/tool-result-truncation.test.ts +5 -4
  445. package/src/__tests__/tool-trace-listener.test.ts +131 -111
  446. package/src/__tests__/top-level-renderer.test.ts +62 -58
  447. package/src/__tests__/top-level-scanner.test.ts +68 -64
  448. package/src/__tests__/trace-emitter.test.ts +56 -56
  449. package/src/__tests__/trust-context-guards.test.ts +65 -65
  450. package/src/__tests__/trust-store.test.ts +1239 -806
  451. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  452. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  453. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
  454. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
  455. package/src/__tests__/trusted-contact-verification.test.ts +251 -231
  456. package/src/__tests__/turn-commit.test.ts +259 -200
  457. package/src/__tests__/twilio-provider.test.ts +140 -126
  458. package/src/__tests__/twilio-rest.test.ts +22 -18
  459. package/src/__tests__/twilio-routes-elevenlabs.test.ts +0 -1
  460. package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
  461. package/src/__tests__/twilio-routes.test.ts +0 -1
  462. package/src/__tests__/twitter-auth-handler.test.ts +184 -139
  463. package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
  464. package/src/__tests__/twitter-cli-routing.test.ts +146 -99
  465. package/src/__tests__/twitter-oauth-client.test.ts +82 -65
  466. package/src/__tests__/update-bulletin-format.test.ts +69 -66
  467. package/src/__tests__/update-bulletin-state.test.ts +66 -60
  468. package/src/__tests__/update-bulletin.test.ts +150 -114
  469. package/src/__tests__/update-template-contract.test.ts +15 -10
  470. package/src/__tests__/url-safety.test.ts +288 -265
  471. package/src/__tests__/user-reference.test.ts +32 -32
  472. package/src/__tests__/view-image-tool.test.ts +118 -96
  473. package/src/__tests__/voice-invite-redemption.test.ts +111 -106
  474. package/src/__tests__/voice-quality.test.ts +117 -102
  475. package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
  476. package/src/__tests__/voice-session-bridge.test.ts +351 -216
  477. package/src/__tests__/weather-skill-regression.test.ts +170 -120
  478. package/src/__tests__/web-fetch.test.ts +664 -526
  479. package/src/__tests__/web-search.test.ts +379 -213
  480. package/src/__tests__/work-item-output.test.ts +90 -53
  481. package/src/__tests__/workspace-git-service.test.ts +437 -356
  482. package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
  483. package/src/__tests__/workspace-lifecycle.test.ts +98 -64
  484. package/src/__tests__/workspace-policy.test.ts +139 -71
  485. package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
  486. package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
  487. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +25 -10
  488. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
  489. package/src/config/bundled-skills/messaging/SKILL.md +4 -3
  490. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
  491. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
  492. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
  493. package/src/config/bundled-tool-registry.ts +2 -0
  494. package/src/config/env.ts +3 -4
  495. package/src/memory/db-connection.ts +16 -10
  496. package/src/messaging/providers/gmail/adapter.ts +10 -3
  497. package/src/messaging/providers/gmail/client.ts +280 -72
  498. package/src/runtime/auth/__tests__/context.test.ts +75 -65
  499. package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
  500. package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
  501. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
  502. package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
  503. package/src/runtime/auth/__tests__/policy.test.ts +9 -9
  504. package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
  505. package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
  506. package/src/runtime/auth/__tests__/subject.test.ts +54 -54
  507. package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
  508. package/src/runtime/auth/scopes.ts +3 -0
  509. package/src/runtime/auth/token-service.ts +4 -1
  510. package/src/runtime/auth/types.ts +2 -1
  511. package/src/runtime/http-server.ts +2 -1
  512. package/src/security/secure-keys.ts +103 -53
  513. package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
  514. package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
  515. package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
@@ -1,50 +1,55 @@
1
- import { mkdtempSync, rmSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
1
+ import { mkdtempSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
4
5
 
5
- import { afterAll, beforeEach, describe, expect, mock,test } from 'bun:test';
6
+ const testDir = mkdtempSync(join(tmpdir(), "contacts-tools-test-"));
6
7
 
7
- const testDir = mkdtempSync(join(tmpdir(), 'contacts-tools-test-'));
8
-
9
- mock.module('../util/platform.js', () => ({
8
+ mock.module("../util/platform.js", () => ({
10
9
  getDataDir: () => testDir,
11
- isMacOS: () => process.platform === 'darwin',
12
- isLinux: () => process.platform === 'linux',
13
- isWindows: () => process.platform === 'win32',
14
- getSocketPath: () => join(testDir, 'test.sock'),
15
- getPidPath: () => join(testDir, 'test.pid'),
16
- getDbPath: () => join(testDir, 'test.db'),
17
- getLogPath: () => join(testDir, 'test.log'),
10
+ isMacOS: () => process.platform === "darwin",
11
+ isLinux: () => process.platform === "linux",
12
+ isWindows: () => process.platform === "win32",
13
+ getSocketPath: () => join(testDir, "test.sock"),
14
+ getPidPath: () => join(testDir, "test.pid"),
15
+ getDbPath: () => join(testDir, "test.db"),
16
+ getLogPath: () => join(testDir, "test.log"),
18
17
  ensureDataDir: () => {},
19
18
  migrateToDataLayout: () => {},
20
19
  migrateToWorkspaceLayout: () => {},
21
20
  }));
22
21
 
23
- mock.module('../util/logger.js', () => ({
24
- getLogger: () => new Proxy({} as Record<string, unknown>, {
25
- get: () => () => {},
26
- }),
22
+ mock.module("../util/logger.js", () => ({
23
+ getLogger: () =>
24
+ new Proxy({} as Record<string, unknown>, {
25
+ get: () => () => {},
26
+ }),
27
27
  }));
28
28
 
29
- mock.module('../config/loader.js', () => ({
29
+ mock.module("../config/loader.js", () => ({
30
30
  getConfig: () => ({
31
31
  ui: {},
32
- memory: {} }),
32
+ memory: {},
33
+ }),
33
34
  }));
34
35
 
35
- import type { Database } from 'bun:sqlite';
36
+ import type { Database } from "bun:sqlite";
36
37
 
37
- import { executeContactMerge } from '../config/bundled-skills/contacts/tools/contact-merge.js';
38
- import { executeContactSearch } from '../config/bundled-skills/contacts/tools/contact-search.js';
39
- import { executeContactUpsert } from '../config/bundled-skills/contacts/tools/contact-upsert.js';
40
- import { getDb, initializeDb, resetDb } from '../memory/db.js';
41
- import type { ToolContext } from '../tools/types.js';
38
+ import { executeContactMerge } from "../config/bundled-skills/contacts/tools/contact-merge.js";
39
+ import { executeContactSearch } from "../config/bundled-skills/contacts/tools/contact-search.js";
40
+ import { executeContactUpsert } from "../config/bundled-skills/contacts/tools/contact-upsert.js";
41
+ import { getDb, initializeDb, resetDb } from "../memory/db.js";
42
+ import type { ToolContext } from "../tools/types.js";
42
43
 
43
44
  initializeDb();
44
45
 
45
46
  afterAll(() => {
46
47
  resetDb();
47
- try { rmSync(testDir, { recursive: true }); } catch { /* best effort */ }
48
+ try {
49
+ rmSync(testDir, { recursive: true });
50
+ } catch {
51
+ /* best effort */
52
+ }
48
53
  });
49
54
 
50
55
  function getRawDb(): Database {
@@ -52,56 +57,62 @@ function getRawDb(): Database {
52
57
  }
53
58
 
54
59
  const ctx: ToolContext = {
55
- workingDir: '/tmp',
56
- sessionId: 'test-session',
57
- conversationId: 'test-conversation',
58
- guardianTrustClass: 'guardian',
60
+ workingDir: "/tmp",
61
+ sessionId: "test-session",
62
+ conversationId: "test-conversation",
63
+ guardianTrustClass: "guardian",
59
64
  };
60
65
 
61
66
  function clearContacts(): void {
62
- getRawDb().run('DELETE FROM contact_channels');
63
- getRawDb().run('DELETE FROM contacts');
67
+ getRawDb().run("DELETE FROM contact_channels");
68
+ getRawDb().run("DELETE FROM contacts");
64
69
  }
65
70
 
66
71
  // ── contact_upsert ──────────────────────────────────────────────────
67
72
 
68
- describe('contact_upsert tool', () => {
73
+ describe("contact_upsert tool", () => {
69
74
  beforeEach(clearContacts);
70
75
 
71
- test('creates a new contact with display name only', async () => {
72
- const result = await executeContactUpsert({ display_name: 'Alice' }, ctx);
76
+ test("creates a new contact with display name only", async () => {
77
+ const result = await executeContactUpsert({ display_name: "Alice" }, ctx);
73
78
 
74
79
  expect(result.isError).toBe(false);
75
- expect(result.content).toContain('Created contact');
76
- expect(result.content).toContain('Alice');
77
- expect(result.content).toContain('Importance: 0.50');
80
+ expect(result.content).toContain("Created contact");
81
+ expect(result.content).toContain("Alice");
82
+ expect(result.content).toContain("Importance: 0.50");
78
83
  });
79
84
 
80
- test('creates a contact with all fields', async () => {
81
- const result = await executeContactUpsert({
82
- display_name: 'Bob',
83
- relationship: 'colleague',
84
- importance: 0.8,
85
- response_expectation: 'within_hours',
86
- preferred_tone: 'professional',
87
- channels: [
88
- { type: 'email', address: 'bob@example.com', is_primary: true },
89
- { type: 'slack', address: '@bob' },
90
- ],
91
- }, ctx);
85
+ test("creates a contact with all fields", async () => {
86
+ const result = await executeContactUpsert(
87
+ {
88
+ display_name: "Bob",
89
+ relationship: "colleague",
90
+ importance: 0.8,
91
+ response_expectation: "within_hours",
92
+ preferred_tone: "professional",
93
+ channels: [
94
+ { type: "email", address: "bob@example.com", is_primary: true },
95
+ { type: "slack", address: "@bob" },
96
+ ],
97
+ },
98
+ ctx,
99
+ );
92
100
 
93
101
  expect(result.isError).toBe(false);
94
- expect(result.content).toContain('Bob');
95
- expect(result.content).toContain('colleague');
96
- expect(result.content).toContain('0.80');
97
- expect(result.content).toContain('within_hours');
98
- expect(result.content).toContain('professional');
99
- expect(result.content).toContain('email: bob@example.com');
100
- expect(result.content).toContain('slack: @bob');
102
+ expect(result.content).toContain("Bob");
103
+ expect(result.content).toContain("colleague");
104
+ expect(result.content).toContain("0.80");
105
+ expect(result.content).toContain("within_hours");
106
+ expect(result.content).toContain("professional");
107
+ expect(result.content).toContain("email: bob@example.com");
108
+ expect(result.content).toContain("slack: @bob");
101
109
  });
102
110
 
103
- test('updates an existing contact by ID', async () => {
104
- const createResult = await executeContactUpsert({ display_name: 'Charlie' }, ctx);
111
+ test("updates an existing contact by ID", async () => {
112
+ const createResult = await executeContactUpsert(
113
+ { display_name: "Charlie" },
114
+ ctx,
115
+ );
105
116
  expect(createResult.isError).toBe(false);
106
117
 
107
118
  // Extract ID from output
@@ -109,152 +120,193 @@ describe('contact_upsert tool', () => {
109
120
  expect(idMatch).not.toBeNull();
110
121
  const contactId = idMatch![1];
111
122
 
112
- const updateResult = await executeContactUpsert({
113
- id: contactId,
114
- display_name: 'Charlie Updated',
115
- importance: 0.9,
116
- }, ctx);
123
+ const updateResult = await executeContactUpsert(
124
+ {
125
+ id: contactId,
126
+ display_name: "Charlie Updated",
127
+ importance: 0.9,
128
+ },
129
+ ctx,
130
+ );
117
131
 
118
132
  expect(updateResult.isError).toBe(false);
119
- expect(updateResult.content).toContain('Updated contact');
120
- expect(updateResult.content).toContain('Charlie Updated');
121
- expect(updateResult.content).toContain('0.90');
133
+ expect(updateResult.content).toContain("Updated contact");
134
+ expect(updateResult.content).toContain("Charlie Updated");
135
+ expect(updateResult.content).toContain("0.90");
122
136
  });
123
137
 
124
- test('auto-matches by channel address on create', async () => {
138
+ test("auto-matches by channel address on create", async () => {
125
139
  // Create a contact with an email
126
- await executeContactUpsert({
127
- display_name: 'Diana',
128
- channels: [{ type: 'email', address: 'diana@example.com' }],
129
- }, ctx);
140
+ await executeContactUpsert(
141
+ {
142
+ display_name: "Diana",
143
+ channels: [{ type: "email", address: "diana@example.com" }],
144
+ },
145
+ ctx,
146
+ );
130
147
 
131
148
  // Upsert with same email but different display name
132
- const result = await executeContactUpsert({
133
- display_name: 'Diana Updated',
134
- channels: [{ type: 'email', address: 'diana@example.com' }],
135
- }, ctx);
149
+ const result = await executeContactUpsert(
150
+ {
151
+ display_name: "Diana Updated",
152
+ channels: [{ type: "email", address: "diana@example.com" }],
153
+ },
154
+ ctx,
155
+ );
136
156
 
137
157
  expect(result.isError).toBe(false);
138
- expect(result.content).toContain('Updated contact');
139
- expect(result.content).toContain('Diana Updated');
158
+ expect(result.content).toContain("Updated contact");
159
+ expect(result.content).toContain("Diana Updated");
140
160
 
141
161
  // Should still be just 1 contact
142
- const count = getRawDb().query('SELECT COUNT(*) as c FROM contacts').get() as { c: number };
162
+ const count = getRawDb()
163
+ .query("SELECT COUNT(*) as c FROM contacts")
164
+ .get() as { c: number };
143
165
  expect(count.c).toBe(1);
144
166
  });
145
167
 
146
- test('rejects missing display_name', async () => {
168
+ test("rejects missing display_name", async () => {
147
169
  const result = await executeContactUpsert({}, ctx);
148
170
 
149
171
  expect(result.isError).toBe(true);
150
- expect(result.content).toContain('display_name is required');
172
+ expect(result.content).toContain("display_name is required");
151
173
  });
152
174
 
153
- test('rejects empty display_name', async () => {
154
- const result = await executeContactUpsert({ display_name: ' ' }, ctx);
175
+ test("rejects empty display_name", async () => {
176
+ const result = await executeContactUpsert({ display_name: " " }, ctx);
155
177
 
156
178
  expect(result.isError).toBe(true);
157
- expect(result.content).toContain('display_name is required');
179
+ expect(result.content).toContain("display_name is required");
158
180
  });
159
181
 
160
- test('rejects importance out of range', async () => {
161
- const result = await executeContactUpsert({
162
- display_name: 'Test',
163
- importance: 1.5,
164
- }, ctx);
182
+ test("rejects importance out of range", async () => {
183
+ const result = await executeContactUpsert(
184
+ {
185
+ display_name: "Test",
186
+ importance: 1.5,
187
+ },
188
+ ctx,
189
+ );
165
190
 
166
191
  expect(result.isError).toBe(true);
167
- expect(result.content).toContain('importance must be a number between 0 and 1');
192
+ expect(result.content).toContain(
193
+ "importance must be a number between 0 and 1",
194
+ );
168
195
  });
169
196
 
170
- test('rejects negative importance', async () => {
171
- const result = await executeContactUpsert({
172
- display_name: 'Test',
173
- importance: -0.1,
174
- }, ctx);
197
+ test("rejects negative importance", async () => {
198
+ const result = await executeContactUpsert(
199
+ {
200
+ display_name: "Test",
201
+ importance: -0.1,
202
+ },
203
+ ctx,
204
+ );
175
205
 
176
206
  expect(result.isError).toBe(true);
177
- expect(result.content).toContain('importance must be a number between 0 and 1');
207
+ expect(result.content).toContain(
208
+ "importance must be a number between 0 and 1",
209
+ );
178
210
  });
179
211
  });
180
212
 
181
213
  // ── contact_search ──────────────────────────────────────────────────
182
214
 
183
- describe('contact_search tool', () => {
215
+ describe("contact_search tool", () => {
184
216
  beforeEach(clearContacts);
185
217
 
186
- test('searches by display name', async () => {
187
- await executeContactUpsert({ display_name: 'Alice Smith' }, ctx);
188
- await executeContactUpsert({ display_name: 'Bob Jones' }, ctx);
218
+ test("searches by display name", async () => {
219
+ await executeContactUpsert({ display_name: "Alice Smith" }, ctx);
220
+ await executeContactUpsert({ display_name: "Bob Jones" }, ctx);
189
221
 
190
- const result = await executeContactSearch({ query: 'Alice' }, ctx);
222
+ const result = await executeContactSearch({ query: "Alice" }, ctx);
191
223
 
192
224
  expect(result.isError).toBe(false);
193
- expect(result.content).toContain('Alice Smith');
194
- expect(result.content).not.toContain('Bob Jones');
225
+ expect(result.content).toContain("Alice Smith");
226
+ expect(result.content).not.toContain("Bob Jones");
195
227
  });
196
228
 
197
- test('searches by channel address', async () => {
198
- await executeContactUpsert({
199
- display_name: 'Charlie',
200
- channels: [{ type: 'email', address: 'charlie@example.com' }],
201
- }, ctx);
229
+ test("searches by channel address", async () => {
230
+ await executeContactUpsert(
231
+ {
232
+ display_name: "Charlie",
233
+ channels: [{ type: "email", address: "charlie@example.com" }],
234
+ },
235
+ ctx,
236
+ );
202
237
 
203
- const result = await executeContactSearch({ channel_address: 'charlie@example' }, ctx);
238
+ const result = await executeContactSearch(
239
+ { channel_address: "charlie@example" },
240
+ ctx,
241
+ );
204
242
 
205
243
  expect(result.isError).toBe(false);
206
- expect(result.content).toContain('Charlie');
244
+ expect(result.content).toContain("Charlie");
207
245
  });
208
246
 
209
- test('searches by relationship', async () => {
210
- await executeContactUpsert({ display_name: 'Diana', relationship: 'friend' }, ctx);
211
- await executeContactUpsert({ display_name: 'Eve', relationship: 'colleague' }, ctx);
247
+ test("searches by relationship", async () => {
248
+ await executeContactUpsert(
249
+ { display_name: "Diana", relationship: "friend" },
250
+ ctx,
251
+ );
252
+ await executeContactUpsert(
253
+ { display_name: "Eve", relationship: "colleague" },
254
+ ctx,
255
+ );
212
256
 
213
- const result = await executeContactSearch({ relationship: 'friend' }, ctx);
257
+ const result = await executeContactSearch({ relationship: "friend" }, ctx);
214
258
 
215
259
  expect(result.isError).toBe(false);
216
- expect(result.content).toContain('Diana');
217
- expect(result.content).not.toContain('Eve');
260
+ expect(result.content).toContain("Diana");
261
+ expect(result.content).not.toContain("Eve");
218
262
  });
219
263
 
220
- test('returns no results message when nothing matches', async () => {
221
- await executeContactUpsert({ display_name: 'Existing' }, ctx);
264
+ test("returns no results message when nothing matches", async () => {
265
+ await executeContactUpsert({ display_name: "Existing" }, ctx);
222
266
 
223
- const result = await executeContactSearch({ query: 'Nonexistent' }, ctx);
267
+ const result = await executeContactSearch({ query: "Nonexistent" }, ctx);
224
268
 
225
269
  expect(result.isError).toBe(false);
226
- expect(result.content).toContain('No contacts found');
270
+ expect(result.content).toContain("No contacts found");
227
271
  });
228
272
 
229
- test('rejects search with no criteria', async () => {
273
+ test("rejects search with no criteria", async () => {
230
274
  const result = await executeContactSearch({}, ctx);
231
275
 
232
276
  expect(result.isError).toBe(true);
233
- expect(result.content).toContain('At least one search criterion is required');
277
+ expect(result.content).toContain(
278
+ "At least one search criterion is required",
279
+ );
234
280
  });
235
281
 
236
- test('searches by channel address with type filter', async () => {
237
- await executeContactUpsert({
238
- display_name: 'Frank',
239
- channels: [
240
- { type: 'email', address: 'frank@example.com' },
241
- { type: 'slack', address: 'frank@example.com' },
242
- ],
243
- }, ctx);
244
-
245
- const result = await executeContactSearch({
246
- channel_address: 'frank@example',
247
- channel_type: 'slack',
248
- }, ctx);
282
+ test("searches by channel address with type filter", async () => {
283
+ await executeContactUpsert(
284
+ {
285
+ display_name: "Frank",
286
+ channels: [
287
+ { type: "email", address: "frank@example.com" },
288
+ { type: "slack", address: "frank@example.com" },
289
+ ],
290
+ },
291
+ ctx,
292
+ );
293
+
294
+ const result = await executeContactSearch(
295
+ {
296
+ channel_address: "frank@example",
297
+ channel_type: "slack",
298
+ },
299
+ ctx,
300
+ );
249
301
 
250
302
  expect(result.isError).toBe(false);
251
- expect(result.content).toContain('Frank');
303
+ expect(result.content).toContain("Frank");
252
304
  });
253
305
  });
254
306
 
255
307
  // ── contact_merge ───────────────────────────────────────────────────
256
308
 
257
- describe('contact_merge tool', () => {
309
+ describe("contact_merge tool", () => {
258
310
  beforeEach(clearContacts);
259
311
 
260
312
  function extractContactId(result: { content: string }): string {
@@ -263,74 +315,91 @@ describe('contact_merge tool', () => {
263
315
  return match![1];
264
316
  }
265
317
 
266
- test('merges two contacts', async () => {
267
- const r1 = await executeContactUpsert({
268
- display_name: 'Alice (Email)',
269
- importance: 0.7,
270
- channels: [{ type: 'email', address: 'alice@example.com' }],
271
- }, ctx);
272
- const r2 = await executeContactUpsert({
273
- display_name: 'Alice (Slack)',
274
- importance: 0.9,
275
- channels: [{ type: 'slack', address: '@alice' }],
276
- }, ctx);
318
+ test("merges two contacts", async () => {
319
+ const r1 = await executeContactUpsert(
320
+ {
321
+ display_name: "Alice (Email)",
322
+ importance: 0.7,
323
+ channels: [{ type: "email", address: "alice@example.com" }],
324
+ },
325
+ ctx,
326
+ );
327
+ const r2 = await executeContactUpsert(
328
+ {
329
+ display_name: "Alice (Slack)",
330
+ importance: 0.9,
331
+ channels: [{ type: "slack", address: "@alice" }],
332
+ },
333
+ ctx,
334
+ );
277
335
 
278
336
  const keepId = extractContactId(r1);
279
337
  const mergeId = extractContactId(r2);
280
338
 
281
- const result = await executeContactMerge({
282
- keep_id: keepId,
283
- merge_id: mergeId,
284
- }, ctx);
339
+ const result = await executeContactMerge(
340
+ {
341
+ keep_id: keepId,
342
+ merge_id: mergeId,
343
+ },
344
+ ctx,
345
+ );
285
346
 
286
347
  expect(result.isError).toBe(false);
287
- expect(result.content).toContain('Merged');
288
- expect(result.content).toContain('Importance: 0.90'); // takes higher importance
289
- expect(result.content).toContain('email: alice@example.com');
290
- expect(result.content).toContain('slack: @alice');
348
+ expect(result.content).toContain("Merged");
349
+ expect(result.content).toContain("Importance: 0.90"); // takes higher importance
350
+ expect(result.content).toContain("email: alice@example.com");
351
+ expect(result.content).toContain("slack: @alice");
291
352
 
292
353
  // Verify donor is deleted
293
- const count = getRawDb().query('SELECT COUNT(*) as c FROM contacts').get() as { c: number };
354
+ const count = getRawDb()
355
+ .query("SELECT COUNT(*) as c FROM contacts")
356
+ .get() as { c: number };
294
357
  expect(count.c).toBe(1);
295
358
  });
296
359
 
297
- test('rejects missing keep_id', async () => {
298
- const result = await executeContactMerge({ merge_id: 'some-id' }, ctx);
360
+ test("rejects missing keep_id", async () => {
361
+ const result = await executeContactMerge({ merge_id: "some-id" }, ctx);
299
362
 
300
363
  expect(result.isError).toBe(true);
301
- expect(result.content).toContain('keep_id is required');
364
+ expect(result.content).toContain("keep_id is required");
302
365
  });
303
366
 
304
- test('rejects missing merge_id', async () => {
305
- const result = await executeContactMerge({ keep_id: 'some-id' }, ctx);
367
+ test("rejects missing merge_id", async () => {
368
+ const result = await executeContactMerge({ keep_id: "some-id" }, ctx);
306
369
 
307
370
  expect(result.isError).toBe(true);
308
- expect(result.content).toContain('merge_id is required');
371
+ expect(result.content).toContain("merge_id is required");
309
372
  });
310
373
 
311
- test('returns error for nonexistent keep_id', async () => {
312
- const r = await executeContactUpsert({ display_name: 'Exists' }, ctx);
374
+ test("returns error for nonexistent keep_id", async () => {
375
+ const r = await executeContactUpsert({ display_name: "Exists" }, ctx);
313
376
  const existingId = extractContactId(r);
314
377
 
315
- const result = await executeContactMerge({
316
- keep_id: 'nonexistent',
317
- merge_id: existingId,
318
- }, ctx);
378
+ const result = await executeContactMerge(
379
+ {
380
+ keep_id: "nonexistent",
381
+ merge_id: existingId,
382
+ },
383
+ ctx,
384
+ );
319
385
 
320
386
  expect(result.isError).toBe(true);
321
- expect(result.content).toContain('not found');
387
+ expect(result.content).toContain("not found");
322
388
  });
323
389
 
324
- test('returns error for nonexistent merge_id', async () => {
325
- const r = await executeContactUpsert({ display_name: 'Exists' }, ctx);
390
+ test("returns error for nonexistent merge_id", async () => {
391
+ const r = await executeContactUpsert({ display_name: "Exists" }, ctx);
326
392
  const existingId = extractContactId(r);
327
393
 
328
- const result = await executeContactMerge({
329
- keep_id: existingId,
330
- merge_id: 'nonexistent',
331
- }, ctx);
394
+ const result = await executeContactMerge(
395
+ {
396
+ keep_id: existingId,
397
+ merge_id: "nonexistent",
398
+ },
399
+ ctx,
400
+ );
332
401
 
333
402
  expect(result.isError).toBe(true);
334
- expect(result.content).toContain('not found');
403
+ expect(result.content).toContain("not found");
335
404
  });
336
405
  });