@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,78 +1,85 @@
1
- import { mkdirSync, rmSync,writeFileSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
-
5
- import { afterEach,beforeEach, describe, expect, test } from 'bun:test';
1
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
6
5
 
7
6
  import {
8
7
  loadConfig,
9
8
  resetCache,
10
9
  resolveProfile,
11
10
  setStorePathOverride,
12
- } from '../daemon/dictation-profile-store.js';
11
+ } from "../daemon/dictation-profile-store.js";
13
12
 
14
13
  let testDir: string;
15
14
  let testFilePath: string;
16
15
 
17
16
  beforeEach(() => {
18
- testDir = join(tmpdir(), `vellum-test-profiles-${Date.now()}-${Math.random().toString(36).slice(2)}`);
17
+ testDir = join(
18
+ tmpdir(),
19
+ `vellum-test-profiles-${Date.now()}-${Math.random().toString(36).slice(2)}`,
20
+ );
19
21
  mkdirSync(testDir, { recursive: true });
20
- testFilePath = join(testDir, 'dictation-profiles.json');
22
+ testFilePath = join(testDir, "dictation-profiles.json");
21
23
  setStorePathOverride(testFilePath);
22
24
  });
23
25
 
24
26
  afterEach(() => {
25
27
  setStorePathOverride(null);
26
- try { rmSync(testDir, { recursive: true, force: true }); } catch {}
28
+ try {
29
+ rmSync(testDir, { recursive: true, force: true });
30
+ } catch {}
27
31
  });
28
32
 
29
33
  function writeConfig(config: unknown): void {
30
34
  writeFileSync(testFilePath, JSON.stringify(config, null, 2));
31
35
  }
32
36
 
33
- describe('loadConfig', () => {
34
- test('returns default config when file is missing or malformed', () => {
37
+ describe("loadConfig", () => {
38
+ test("returns default config when file is missing or malformed", () => {
35
39
  // Missing file
36
40
  let config = loadConfig();
37
41
  expect(config.profiles).toHaveLength(1);
38
- expect(config.profiles[0].id).toBe('general');
42
+ expect(config.profiles[0].id).toBe("general");
39
43
 
40
44
  // Malformed JSON
41
45
  resetCache();
42
- writeFileSync(testFilePath, 'not json');
46
+ writeFileSync(testFilePath, "not json");
43
47
  config = loadConfig();
44
- expect(config.profiles[0].id).toBe('general');
48
+ expect(config.profiles[0].id).toBe("general");
45
49
  });
46
50
 
47
- test('loads valid config from disk', () => {
51
+ test("loads valid config from disk", () => {
48
52
  writeConfig({
49
53
  version: 1,
50
- defaultProfileId: 'work',
54
+ defaultProfileId: "work",
51
55
  profiles: [
52
- { id: 'work', name: 'Work', stylePrompt: 'Be professional' },
53
- { id: 'casual', name: 'Casual' },
56
+ { id: "work", name: "Work", stylePrompt: "Be professional" },
57
+ { id: "casual", name: "Casual" },
54
58
  ],
55
59
  });
56
60
  const config = loadConfig();
57
61
  expect(config.profiles).toHaveLength(2);
58
- expect(config.defaultProfileId).toBe('work');
62
+ expect(config.defaultProfileId).toBe("work");
59
63
  });
60
64
 
61
- test('enforces validation limits', () => {
65
+ test("enforces validation limits", () => {
62
66
  writeConfig({
63
67
  version: 1,
64
- profiles: [{
65
- id: 'test', name: 'Test',
66
- stylePrompt: 'x'.repeat(3000),
67
- dictionary: [
68
- { spoken: 'ok', written: 'okay' },
69
- { spoken: 'x'.repeat(201), written: 'bad' },
70
- ],
71
- snippets: [
72
- { trigger: 'brb', expansion: 'be right back' },
73
- { trigger: 'good', expansion: 'y'.repeat(5001) },
74
- ],
75
- }],
68
+ profiles: [
69
+ {
70
+ id: "test",
71
+ name: "Test",
72
+ stylePrompt: "x".repeat(3000),
73
+ dictionary: [
74
+ { spoken: "ok", written: "okay" },
75
+ { spoken: "x".repeat(201), written: "bad" },
76
+ ],
77
+ snippets: [
78
+ { trigger: "brb", expansion: "be right back" },
79
+ { trigger: "good", expansion: "y".repeat(5001) },
80
+ ],
81
+ },
82
+ ],
76
83
  });
77
84
  const config = loadConfig();
78
85
  expect(config.profiles[0].stylePrompt!.length).toBe(2000);
@@ -81,57 +88,64 @@ describe('loadConfig', () => {
81
88
  });
82
89
  });
83
90
 
84
- describe('resolveProfile', () => {
85
- test('resolution precedence: request > app_mapping > default > fallback', () => {
91
+ describe("resolveProfile", () => {
92
+ test("resolution precedence: request > app_mapping > default > fallback", () => {
86
93
  writeConfig({
87
94
  version: 1,
88
- defaultProfileId: 'default-one',
89
- appMappings: [{ profileId: 'mapped', bundleIdentifier: 'com.test.app' }],
95
+ defaultProfileId: "default-one",
96
+ appMappings: [{ profileId: "mapped", bundleIdentifier: "com.test.app" }],
90
97
  profiles: [
91
- { id: 'requested', name: 'Requested' },
92
- { id: 'mapped', name: 'Mapped' },
93
- { id: 'default-one', name: 'Default' },
98
+ { id: "requested", name: "Requested" },
99
+ { id: "mapped", name: "Mapped" },
100
+ { id: "default-one", name: "Default" },
94
101
  ],
95
102
  });
96
103
 
97
104
  // Explicit request wins
98
- expect(resolveProfile('com.test.app', 'Test', 'requested').source).toBe('request');
105
+ expect(resolveProfile("com.test.app", "Test", "requested").source).toBe(
106
+ "request",
107
+ );
99
108
 
100
109
  // App mapping next
101
- expect(resolveProfile('com.test.app', 'Test').source).toBe('app_mapping');
110
+ expect(resolveProfile("com.test.app", "Test").source).toBe("app_mapping");
102
111
 
103
112
  // Default when no mapping
104
- expect(resolveProfile('com.other.app', 'Other').source).toBe('default');
113
+ expect(resolveProfile("com.other.app", "Other").source).toBe("default");
105
114
 
106
115
  // Fallback when nothing configured
107
116
  resetCache();
108
- writeConfig({ version: 1, profiles: [{ id: 'unused', name: 'Unused' }] });
109
- expect(resolveProfile('com.other.app', 'Other').source).toBe('fallback');
117
+ writeConfig({ version: 1, profiles: [{ id: "unused", name: "Unused" }] });
118
+ expect(resolveProfile("com.other.app", "Other").source).toBe("fallback");
110
119
  });
111
120
 
112
- test('bundleIdentifier match beats appName match', () => {
121
+ test("bundleIdentifier match beats appName match", () => {
113
122
  writeConfig({
114
123
  version: 1,
115
124
  appMappings: [
116
- { profileId: 'by-name', appName: 'Slack' },
117
- { profileId: 'by-bundle', bundleIdentifier: 'com.tinyspeck.slackmacgap' },
125
+ { profileId: "by-name", appName: "Slack" },
126
+ {
127
+ profileId: "by-bundle",
128
+ bundleIdentifier: "com.tinyspeck.slackmacgap",
129
+ },
118
130
  ],
119
131
  profiles: [
120
- { id: 'by-name', name: 'By Name' },
121
- { id: 'by-bundle', name: 'By Bundle' },
132
+ { id: "by-name", name: "By Name" },
133
+ { id: "by-bundle", name: "By Bundle" },
122
134
  ],
123
135
  });
124
- expect(resolveProfile('com.tinyspeck.slackmacgap', 'Slack').profile.id).toBe('by-bundle');
136
+ expect(
137
+ resolveProfile("com.tinyspeck.slackmacgap", "Slack").profile.id,
138
+ ).toBe("by-bundle");
125
139
  });
126
140
 
127
- test('skips disabled profiles', () => {
141
+ test("skips disabled profiles", () => {
128
142
  writeConfig({
129
143
  version: 1,
130
- defaultProfileId: 'disabled',
131
- profiles: [{ id: 'disabled', name: 'Disabled', enabled: false }],
144
+ defaultProfileId: "disabled",
145
+ profiles: [{ id: "disabled", name: "Disabled", enabled: false }],
132
146
  });
133
- const result = resolveProfile('com.test.app', 'Test', 'disabled');
134
- expect(result.profile.id).toBe('general');
135
- expect(result.source).toBe('fallback');
147
+ const result = resolveProfile("com.test.app", "Test", "disabled");
148
+ expect(result.profile.id).toBe("general");
149
+ expect(result.source).toBe("fallback");
136
150
  });
137
151
  });
@@ -1,61 +1,79 @@
1
- import { describe, expect, test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
- import type { DictationDictionaryEntry,DictationSnippet } from '../daemon/dictation-profile-store.js';
4
- import { applyDictionary,expandSnippets } from '../daemon/dictation-text-processing.js';
3
+ import type {
4
+ DictationDictionaryEntry,
5
+ DictationSnippet,
6
+ } from "../daemon/dictation-profile-store.js";
7
+ import {
8
+ applyDictionary,
9
+ expandSnippets,
10
+ } from "../daemon/dictation-text-processing.js";
5
11
 
6
- describe('expandSnippets', () => {
7
- test('expands triggers case-insensitively with longest match winning', () => {
12
+ describe("expandSnippets", () => {
13
+ test("expands triggers case-insensitively with longest match winning", () => {
8
14
  const snippets: DictationSnippet[] = [
9
- { trigger: 'brb', expansion: 'be right back' },
10
- { trigger: 'ttyl', expansion: 'talk to you later' },
15
+ { trigger: "brb", expansion: "be right back" },
16
+ { trigger: "ttyl", expansion: "talk to you later" },
11
17
  ];
12
- expect(expandSnippets('BRB and ttyl', snippets)).toBe('be right back and talk to you later');
18
+ expect(expandSnippets("BRB and ttyl", snippets)).toBe(
19
+ "be right back and talk to you later",
20
+ );
13
21
  });
14
22
 
15
- test('skips disabled snippets', () => {
23
+ test("skips disabled snippets", () => {
16
24
  const snippets: DictationSnippet[] = [
17
- { trigger: 'brb', expansion: 'be right back', enabled: false },
25
+ { trigger: "brb", expansion: "be right back", enabled: false },
18
26
  ];
19
- expect(expandSnippets('brb soon', snippets)).toBe('brb soon');
27
+ expect(expandSnippets("brb soon", snippets)).toBe("brb soon");
20
28
  });
21
29
 
22
- test('no recursive expansion', () => {
30
+ test("no recursive expansion", () => {
23
31
  const snippets: DictationSnippet[] = [
24
- { trigger: 'a', expansion: 'b' },
25
- { trigger: 'b', expansion: 'c' },
32
+ { trigger: "a", expansion: "b" },
33
+ { trigger: "b", expansion: "c" },
26
34
  ];
27
- expect(expandSnippets('a test', snippets)).toBe('b test');
35
+ expect(expandSnippets("a test", snippets)).toBe("b test");
28
36
  });
29
37
 
30
- test('handles regex special chars and empty inputs', () => {
31
- expect(expandSnippets('I love C++ programming', [{ trigger: 'C++', expansion: 'CPP' }])).toBe('I love CPP programming');
32
- expect(expandSnippets('', [{ trigger: 'a', expansion: 'b' }])).toBe('');
33
- expect(expandSnippets('hello', undefined)).toBe('hello');
38
+ test("handles regex special chars and empty inputs", () => {
39
+ expect(
40
+ expandSnippets("I love C++ programming", [
41
+ { trigger: "C++", expansion: "CPP" },
42
+ ]),
43
+ ).toBe("I love CPP programming");
44
+ expect(expandSnippets("", [{ trigger: "a", expansion: "b" }])).toBe("");
45
+ expect(expandSnippets("hello", undefined)).toBe("hello");
34
46
  });
35
47
  });
36
48
 
37
- describe('applyDictionary', () => {
38
- test('replaces whole words case-insensitively by default', () => {
49
+ describe("applyDictionary", () => {
50
+ test("replaces whole words case-insensitively by default", () => {
39
51
  const dict: DictationDictionaryEntry[] = [
40
- { spoken: 'gonna', written: 'going to' },
41
- { spoken: 'the', written: 'THE' },
52
+ { spoken: "gonna", written: "going to" },
53
+ { spoken: "the", written: "THE" },
42
54
  ];
43
- expect(applyDictionary('Gonna do it', dict)).toBe('going to do it');
44
- expect(applyDictionary('the cat is there', dict)).toBe('THE cat is there');
55
+ expect(applyDictionary("Gonna do it", dict)).toBe("going to do it");
56
+ expect(applyDictionary("the cat is there", dict)).toBe("THE cat is there");
45
57
  });
46
58
 
47
- test('respects caseSensitive and wholeWord options', () => {
48
- expect(applyDictionary('The api is ready', [
49
- { spoken: 'API', written: 'Interface', caseSensitive: true },
50
- ])).toBe('The api is ready');
59
+ test("respects caseSensitive and wholeWord options", () => {
60
+ expect(
61
+ applyDictionary("The api is ready", [
62
+ { spoken: "API", written: "Interface", caseSensitive: true },
63
+ ]),
64
+ ).toBe("The api is ready");
51
65
 
52
- expect(applyDictionary('colorful', [
53
- { spoken: 'color', written: 'colour', wholeWord: false },
54
- ])).toBe('colourful');
66
+ expect(
67
+ applyDictionary("colorful", [
68
+ { spoken: "color", written: "colour", wholeWord: false },
69
+ ]),
70
+ ).toBe("colourful");
55
71
  });
56
72
 
57
- test('handles regex special chars and empty inputs', () => {
58
- expect(applyDictionary('Use C++ here', [{ spoken: 'C++', written: 'CPP' }])).toBe('Use CPP here');
59
- expect(applyDictionary('hello', undefined)).toBe('hello');
73
+ test("handles regex special chars and empty inputs", () => {
74
+ expect(
75
+ applyDictionary("Use C++ here", [{ spoken: "C++", written: "CPP" }]),
76
+ ).toBe("Use CPP here");
77
+ expect(applyDictionary("hello", undefined)).toBe("hello");
60
78
  });
61
79
  });
@@ -1,144 +1,148 @@
1
- import { describe, expect, test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
- import { formatDiff, formatNewFileDiff } from '../util/diff.js';
3
+ import { formatDiff, formatNewFileDiff } from "../util/diff.js";
4
4
 
5
5
  // Strip ANSI codes for easier assertion
6
- const stripAnsi = (str: string) => str.replace(/\x1b\[[0-9;]*m/g, '');
6
+ const stripAnsi = (str: string) => str.replace(/\x1b\[[0-9;]*m/g, "");
7
7
 
8
- describe('formatDiff', () => {
9
- test('returns empty string for identical content', () => {
10
- const result = formatDiff('hello\nworld\n', 'hello\nworld\n', 'test.ts');
11
- expect(result).toBe('');
8
+ describe("formatDiff", () => {
9
+ test("returns empty string for identical content", () => {
10
+ const result = formatDiff("hello\nworld\n", "hello\nworld\n", "test.ts");
11
+ expect(result).toBe("");
12
12
  });
13
13
 
14
- test('shows single line addition', () => {
15
- const old = 'line1\nline2\nline3';
16
- const updated = 'line1\nline2\nnew line\nline3';
17
- const result = stripAnsi(formatDiff(old, updated, 'test.ts'));
18
- expect(result).toContain('--- a/test.ts');
19
- expect(result).toContain('+++ b/test.ts');
20
- expect(result).toContain('+new line');
21
- expect(result).not.toContain('-new line');
14
+ test("shows single line addition", () => {
15
+ const old = "line1\nline2\nline3";
16
+ const updated = "line1\nline2\nnew line\nline3";
17
+ const result = stripAnsi(formatDiff(old, updated, "test.ts"));
18
+ expect(result).toContain("--- a/test.ts");
19
+ expect(result).toContain("+++ b/test.ts");
20
+ expect(result).toContain("+new line");
21
+ expect(result).not.toContain("-new line");
22
22
  });
23
23
 
24
- test('shows single line removal', () => {
25
- const old = 'line1\nline2\nline3';
26
- const updated = 'line1\nline3';
27
- const result = stripAnsi(formatDiff(old, updated, 'test.ts'));
28
- expect(result).toContain('-line2');
29
- expect(result).not.toContain('+line2');
24
+ test("shows single line removal", () => {
25
+ const old = "line1\nline2\nline3";
26
+ const updated = "line1\nline3";
27
+ const result = stripAnsi(formatDiff(old, updated, "test.ts"));
28
+ expect(result).toContain("-line2");
29
+ expect(result).not.toContain("+line2");
30
30
  });
31
31
 
32
- test('shows line replacement', () => {
33
- const old = 'const x = 1;\nconst y = 2;\nconst z = 3;';
34
- const updated = 'const x = 1;\nconst y = 42;\nconst z = 3;';
35
- const result = stripAnsi(formatDiff(old, updated, 'file.ts'));
36
- expect(result).toContain('-const y = 2;');
37
- expect(result).toContain('+const y = 42;');
32
+ test("shows line replacement", () => {
33
+ const old = "const x = 1;\nconst y = 2;\nconst z = 3;";
34
+ const updated = "const x = 1;\nconst y = 42;\nconst z = 3;";
35
+ const result = stripAnsi(formatDiff(old, updated, "file.ts"));
36
+ expect(result).toContain("-const y = 2;");
37
+ expect(result).toContain("+const y = 42;");
38
38
  });
39
39
 
40
- test('includes context lines', () => {
40
+ test("includes context lines", () => {
41
41
  const lines = Array.from({ length: 10 }, (_, i) => `line${i + 1}`);
42
- const old = lines.join('\n');
42
+ const old = lines.join("\n");
43
43
  const newLines = [...lines];
44
- newLines[5] = 'CHANGED';
45
- const updated = newLines.join('\n');
46
- const result = stripAnsi(formatDiff(old, updated, 'ctx.ts'));
44
+ newLines[5] = "CHANGED";
45
+ const updated = newLines.join("\n");
46
+ const result = stripAnsi(formatDiff(old, updated, "ctx.ts"));
47
47
  // Should include context before and after the change
48
- expect(result).toContain(' line4');
49
- expect(result).toContain(' line5');
50
- expect(result).toContain('-line6');
51
- expect(result).toContain('+CHANGED');
52
- expect(result).toContain(' line7');
53
- expect(result).toContain(' line8');
48
+ expect(result).toContain(" line4");
49
+ expect(result).toContain(" line5");
50
+ expect(result).toContain("-line6");
51
+ expect(result).toContain("+CHANGED");
52
+ expect(result).toContain(" line7");
53
+ expect(result).toContain(" line8");
54
54
  });
55
55
 
56
- test('handles multi-hunk diffs', () => {
56
+ test("handles multi-hunk diffs", () => {
57
57
  const lines = Array.from({ length: 20 }, (_, i) => `line${i + 1}`);
58
- const old = lines.join('\n');
58
+ const old = lines.join("\n");
59
59
  const newLines = [...lines];
60
- newLines[2] = 'CHANGED_A';
61
- newLines[17] = 'CHANGED_B';
62
- const updated = newLines.join('\n');
63
- const result = stripAnsi(formatDiff(old, updated, 'multi.ts'));
64
- expect(result).toContain('-line3');
65
- expect(result).toContain('+CHANGED_A');
66
- expect(result).toContain('-line18');
67
- expect(result).toContain('+CHANGED_B');
60
+ newLines[2] = "CHANGED_A";
61
+ newLines[17] = "CHANGED_B";
62
+ const updated = newLines.join("\n");
63
+ const result = stripAnsi(formatDiff(old, updated, "multi.ts"));
64
+ expect(result).toContain("-line3");
65
+ expect(result).toContain("+CHANGED_A");
66
+ expect(result).toContain("-line18");
67
+ expect(result).toContain("+CHANGED_B");
68
68
  // Should have two @@ hunk headers
69
69
  const hunkHeaders = result.match(/@@/g);
70
70
  expect(hunkHeaders!.length).toBeGreaterThanOrEqual(4); // 2 hunks, each with @@ ... @@
71
71
  });
72
72
 
73
- test('uses ANSI colors for added/removed lines', () => {
74
- const old = 'old line';
75
- const updated = 'new line';
76
- const result = formatDiff(old, updated, 'test.ts');
73
+ test("uses ANSI colors for added/removed lines", () => {
74
+ const old = "old line";
75
+ const updated = "new line";
76
+ const result = formatDiff(old, updated, "test.ts");
77
77
  // Red for removed
78
- expect(result).toContain('\x1b[31m-old line\x1b[0m');
78
+ expect(result).toContain("\x1b[31m-old line\x1b[0m");
79
79
  // Green for added
80
- expect(result).toContain('\x1b[32m+new line\x1b[0m');
80
+ expect(result).toContain("\x1b[32m+new line\x1b[0m");
81
81
  });
82
82
 
83
- test('handles empty old content (new file)', () => {
84
- const result = stripAnsi(formatDiff('', 'new content\nline 2', 'new.ts'));
85
- expect(result).toContain('+new content');
86
- expect(result).toContain('+line 2');
83
+ test("handles empty old content (new file)", () => {
84
+ const result = stripAnsi(formatDiff("", "new content\nline 2", "new.ts"));
85
+ expect(result).toContain("+new content");
86
+ expect(result).toContain("+line 2");
87
87
  });
88
88
 
89
- test('handles empty new content (file deleted)', () => {
90
- const result = stripAnsi(formatDiff('old content\nline 2', '', 'del.ts'));
91
- expect(result).toContain('-old content');
92
- expect(result).toContain('-line 2');
89
+ test("handles empty new content (file deleted)", () => {
90
+ const result = stripAnsi(formatDiff("old content\nline 2", "", "del.ts"));
91
+ expect(result).toContain("-old content");
92
+ expect(result).toContain("-line 2");
93
93
  });
94
94
 
95
- test('uses a full fallback diff for oversized files without truncation markers', () => {
96
- const old = Array.from({ length: 6 }, (_, i) => `old-${i + 1}`).join('\n');
97
- const updated = Array.from({ length: 6 }, (_, i) => (i === 3 ? 'new-4' : `old-${i + 1}`)).join('\n');
98
- const result = stripAnsi(formatDiff(old, updated, 'oversized.ts', { maxExactLines: 2 }));
99
-
100
- expect(result).toContain('--- a/oversized.ts');
101
- expect(result).toContain('+++ b/oversized.ts');
102
- expect(result).toContain('-old-4');
103
- expect(result).toContain('+new-4');
104
- expect(result).not.toContain('Diff too large to display');
95
+ test("uses a full fallback diff for oversized files without truncation markers", () => {
96
+ const old = Array.from({ length: 6 }, (_, i) => `old-${i + 1}`).join("\n");
97
+ const updated = Array.from({ length: 6 }, (_, i) =>
98
+ i === 3 ? "new-4" : `old-${i + 1}`,
99
+ ).join("\n");
100
+ const result = stripAnsi(
101
+ formatDiff(old, updated, "oversized.ts", { maxExactLines: 2 }),
102
+ );
103
+
104
+ expect(result).toContain("--- a/oversized.ts");
105
+ expect(result).toContain("+++ b/oversized.ts");
106
+ expect(result).toContain("-old-4");
107
+ expect(result).toContain("+new-4");
108
+ expect(result).not.toContain("Diff too large to display");
105
109
  });
106
110
  });
107
111
 
108
- describe('formatNewFileDiff', () => {
109
- test('shows all lines as additions', () => {
110
- const content = 'line1\nline2\nline3';
111
- const result = stripAnsi(formatNewFileDiff(content, 'new.ts'));
112
- expect(result).toContain('--- /dev/null');
113
- expect(result).toContain('+++ b/new.ts');
114
- expect(result).toContain('+line1');
115
- expect(result).toContain('+line2');
116
- expect(result).toContain('+line3');
112
+ describe("formatNewFileDiff", () => {
113
+ test("shows all lines as additions", () => {
114
+ const content = "line1\nline2\nline3";
115
+ const result = stripAnsi(formatNewFileDiff(content, "new.ts"));
116
+ expect(result).toContain("--- /dev/null");
117
+ expect(result).toContain("+++ b/new.ts");
118
+ expect(result).toContain("+line1");
119
+ expect(result).toContain("+line2");
120
+ expect(result).toContain("+line3");
117
121
  });
118
122
 
119
- test('truncates long files', () => {
123
+ test("truncates long files", () => {
120
124
  const lines = Array.from({ length: 50 }, (_, i) => `line${i + 1}`);
121
- const content = lines.join('\n');
122
- const result = stripAnsi(formatNewFileDiff(content, 'big.ts', 10));
123
- expect(result).toContain('+line1');
124
- expect(result).toContain('+line10');
125
- expect(result).not.toContain('+line11');
126
- expect(result).toContain('... 40 more lines');
125
+ const content = lines.join("\n");
126
+ const result = stripAnsi(formatNewFileDiff(content, "big.ts", 10));
127
+ expect(result).toContain("+line1");
128
+ expect(result).toContain("+line10");
129
+ expect(result).not.toContain("+line11");
130
+ expect(result).toContain("... 40 more lines");
127
131
  });
128
132
 
129
- test('does not truncate short files', () => {
130
- const content = 'a\nb\nc';
131
- const result = stripAnsi(formatNewFileDiff(content, 'small.ts'));
132
- expect(result).not.toContain('more lines');
133
+ test("does not truncate short files", () => {
134
+ const content = "a\nb\nc";
135
+ const result = stripAnsi(formatNewFileDiff(content, "small.ts"));
136
+ expect(result).not.toContain("more lines");
133
137
  });
134
138
 
135
- test('allows unbounded output when maxLines is null', () => {
139
+ test("allows unbounded output when maxLines is null", () => {
136
140
  const lines = Array.from({ length: 50 }, (_, i) => `line${i + 1}`);
137
- const content = lines.join('\n');
138
- const result = stripAnsi(formatNewFileDiff(content, 'all-lines.ts', null));
141
+ const content = lines.join("\n");
142
+ const result = stripAnsi(formatNewFileDiff(content, "all-lines.ts", null));
139
143
 
140
- expect(result).toContain('+line1');
141
- expect(result).toContain('+line50');
142
- expect(result).not.toContain('more lines');
144
+ expect(result).toContain("+line1");
145
+ expect(result).toContain("+line50");
146
+ expect(result).not.toContain("more lines");
143
147
  });
144
148
  });