@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,28 +1,46 @@
1
- import { execFileSync } from 'node:child_process';
2
- import { existsSync,mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
-
6
- import { afterAll,afterEach, beforeEach, describe, expect, test } from 'bun:test';
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import {
6
+ afterAll,
7
+ afterEach,
8
+ beforeEach,
9
+ describe,
10
+ expect,
11
+ test,
12
+ } from "bun:test";
7
13
 
8
- import { _resetEnrichmentService, getEnrichmentService } from '../workspace/commit-message-enrichment-service.js';
9
- import type { CommitContext, CommitMessageProvider, CommitMessageResult } from '../workspace/commit-message-provider.js';
14
+ import {
15
+ _resetEnrichmentService,
16
+ getEnrichmentService,
17
+ } from "../workspace/commit-message-enrichment-service.js";
18
+ import type {
19
+ CommitContext,
20
+ CommitMessageProvider,
21
+ CommitMessageResult,
22
+ } from "../workspace/commit-message-provider.js";
10
23
  import {
11
24
  _resetGitServiceRegistry,
12
25
  WorkspaceGitService,
13
- } from '../workspace/git-service.js';
26
+ } from "../workspace/git-service.js";
14
27
  import {
15
28
  _resetHeartbeatState,
16
29
  WorkspaceHeartbeatService,
17
- } from '../workspace/heartbeat-service.js';
30
+ } from "../workspace/heartbeat-service.js";
18
31
 
19
- describe('WorkspaceHeartbeatService', () => {
32
+ describe("WorkspaceHeartbeatService", () => {
20
33
  let testDir: string;
21
34
  let service: WorkspaceGitService;
22
35
  let services: Map<string, WorkspaceGitService>;
23
36
 
24
37
  beforeEach(async () => {
25
- testDir = join(tmpdir(), `vellum-heartbeat-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
38
+ testDir = join(
39
+ tmpdir(),
40
+ `vellum-heartbeat-test-${Date.now()}-${Math.random()
41
+ .toString(36)
42
+ .slice(2)}`,
43
+ );
26
44
  mkdirSync(testDir, { recursive: true });
27
45
  _resetGitServiceRegistry();
28
46
  _resetHeartbeatState();
@@ -36,7 +54,11 @@ describe('WorkspaceHeartbeatService', () => {
36
54
 
37
55
  afterEach(async () => {
38
56
  // Shut down any in-flight enrichment work before removing the test directory
39
- try { await getEnrichmentService().shutdown(); } catch { /* ignore */ }
57
+ try {
58
+ await getEnrichmentService().shutdown();
59
+ } catch {
60
+ /* ignore */
61
+ }
40
62
  _resetEnrichmentService();
41
63
  if (existsSync(testDir)) {
42
64
  rmSync(testDir, { recursive: true, force: true });
@@ -44,12 +66,16 @@ describe('WorkspaceHeartbeatService', () => {
44
66
  });
45
67
 
46
68
  afterAll(async () => {
47
- try { await getEnrichmentService().shutdown(); } catch { /* ignore */ }
69
+ try {
70
+ await getEnrichmentService().shutdown();
71
+ } catch {
72
+ /* ignore */
73
+ }
48
74
  _resetEnrichmentService();
49
75
  });
50
76
 
51
- describe('heartbeat check with age threshold', () => {
52
- test('does not commit when workspace is clean', async () => {
77
+ describe("heartbeat check with age threshold", () => {
78
+ test("does not commit when workspace is clean", async () => {
53
79
  const heartbeat = new WorkspaceHeartbeatService({
54
80
  ageThresholdMs: 0, // Immediate
55
81
  fileThreshold: 1,
@@ -63,8 +89,8 @@ describe('WorkspaceHeartbeatService', () => {
63
89
  expect(result.skipped).toBe(1);
64
90
  });
65
91
 
66
- test('does not commit when changes are below age and file thresholds', async () => {
67
- writeFileSync(join(testDir, 'file.txt'), 'content');
92
+ test("does not commit when changes are below age and file thresholds", async () => {
93
+ writeFileSync(join(testDir, "file.txt"), "content");
68
94
 
69
95
  const heartbeat = new WorkspaceHeartbeatService({
70
96
  ageThresholdMs: 10 * 60 * 1000, // 10 minutes
@@ -79,8 +105,8 @@ describe('WorkspaceHeartbeatService', () => {
79
105
  expect(result.skipped).toBe(1);
80
106
  });
81
107
 
82
- test('commits when changes exceed age threshold', async () => {
83
- writeFileSync(join(testDir, 'file.txt'), 'content');
108
+ test("commits when changes exceed age threshold", async () => {
109
+ writeFileSync(join(testDir, "file.txt"), "content");
84
110
 
85
111
  let currentTime = 1000000;
86
112
  const heartbeat = new WorkspaceHeartbeatService({
@@ -101,16 +127,16 @@ describe('WorkspaceHeartbeatService', () => {
101
127
  expect(secondResult.committed).toBe(1);
102
128
 
103
129
  // Verify commit message
104
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
130
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
105
131
  cwd: testDir,
106
- encoding: 'utf-8',
132
+ encoding: "utf-8",
107
133
  });
108
- expect(commitMsg).toContain('auto-commit');
109
- expect(commitMsg).toContain('heartbeat');
110
- expect(commitMsg).toContain('safety net');
134
+ expect(commitMsg).toContain("auto-commit");
135
+ expect(commitMsg).toContain("heartbeat");
136
+ expect(commitMsg).toContain("safety net");
111
137
  });
112
138
 
113
- test('commits when file count exceeds threshold', async () => {
139
+ test("commits when file count exceeds threshold", async () => {
114
140
  // Create enough files to exceed the threshold
115
141
  for (let i = 0; i < 25; i++) {
116
142
  writeFileSync(join(testDir, `file${i}.txt`), `content ${i}`);
@@ -127,16 +153,16 @@ describe('WorkspaceHeartbeatService', () => {
127
153
  expect(result.committed).toBe(1);
128
154
 
129
155
  // Verify commit message mentions file count
130
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
156
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
131
157
  cwd: testDir,
132
- encoding: 'utf-8',
158
+ encoding: "utf-8",
133
159
  });
134
- expect(commitMsg).toContain('25 files changed');
160
+ expect(commitMsg).toContain("25 files changed");
135
161
  });
136
162
  });
137
163
 
138
- describe('normal operation does not create spurious commits', () => {
139
- test('clean workspace produces no heartbeat commits', async () => {
164
+ describe("normal operation does not create spurious commits", () => {
165
+ test("clean workspace produces no heartbeat commits", async () => {
140
166
  const heartbeat = new WorkspaceHeartbeatService({
141
167
  ageThresholdMs: 0,
142
168
  fileThreshold: 1,
@@ -150,16 +176,16 @@ describe('WorkspaceHeartbeatService', () => {
150
176
  }
151
177
 
152
178
  // Only the initial commit should exist
153
- const commitCount = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
179
+ const commitCount = execFileSync("git", ["rev-list", "--count", "HEAD"], {
154
180
  cwd: testDir,
155
- encoding: 'utf-8',
181
+ encoding: "utf-8",
156
182
  }).trim();
157
183
  expect(parseInt(commitCount, 10)).toBe(1);
158
184
  });
159
185
 
160
- test('changes below both thresholds do not trigger heartbeat commit', async () => {
186
+ test("changes below both thresholds do not trigger heartbeat commit", async () => {
161
187
  // Create a small number of files (below file threshold)
162
- writeFileSync(join(testDir, 'small-change.txt'), 'content');
188
+ writeFileSync(join(testDir, "small-change.txt"), "content");
163
189
 
164
190
  const heartbeat = new WorkspaceHeartbeatService({
165
191
  ageThresholdMs: 10 * 60 * 1000, // 10 minutes
@@ -172,8 +198,8 @@ describe('WorkspaceHeartbeatService', () => {
172
198
  expect(result.skipped).toBe(1);
173
199
  });
174
200
 
175
- test('does not double-commit after turn-boundary commit clears changes', async () => {
176
- writeFileSync(join(testDir, 'file.txt'), 'content');
201
+ test("does not double-commit after turn-boundary commit clears changes", async () => {
202
+ writeFileSync(join(testDir, "file.txt"), "content");
177
203
 
178
204
  let currentTime = 1000000;
179
205
  const heartbeat = new WorkspaceHeartbeatService({
@@ -187,7 +213,7 @@ describe('WorkspaceHeartbeatService', () => {
187
213
  await heartbeat.check();
188
214
 
189
215
  // Simulate a turn-boundary commit that clears the changes
190
- await service.commitChanges('Turn-boundary commit');
216
+ await service.commitChanges("Turn-boundary commit");
191
217
 
192
218
  // Advance time past the threshold
193
219
  currentTime += 6 * 60 * 1000;
@@ -199,9 +225,9 @@ describe('WorkspaceHeartbeatService', () => {
199
225
  });
200
226
  });
201
227
 
202
- describe('shutdown commits', () => {
203
- test('commits pending changes on shutdown', async () => {
204
- writeFileSync(join(testDir, 'unsaved.txt'), 'uncommitted content');
228
+ describe("shutdown commits", () => {
229
+ test("commits pending changes on shutdown", async () => {
230
+ writeFileSync(join(testDir, "unsaved.txt"), "uncommitted content");
205
231
 
206
232
  const heartbeat = new WorkspaceHeartbeatService({
207
233
  getServices: () => services,
@@ -213,16 +239,16 @@ describe('WorkspaceHeartbeatService', () => {
213
239
  expect(result.committed).toBe(1);
214
240
 
215
241
  // Verify commit message
216
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
242
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
217
243
  cwd: testDir,
218
- encoding: 'utf-8',
244
+ encoding: "utf-8",
219
245
  });
220
- expect(commitMsg).toContain('auto-commit');
221
- expect(commitMsg).toContain('shutdown');
222
- expect(commitMsg).toContain('safety net');
246
+ expect(commitMsg).toContain("auto-commit");
247
+ expect(commitMsg).toContain("shutdown");
248
+ expect(commitMsg).toContain("safety net");
223
249
  });
224
250
 
225
- test('does not commit on shutdown when workspace is clean', async () => {
251
+ test("does not commit on shutdown when workspace is clean", async () => {
226
252
  const heartbeat = new WorkspaceHeartbeatService({
227
253
  getServices: () => services,
228
254
  });
@@ -234,15 +260,20 @@ describe('WorkspaceHeartbeatService', () => {
234
260
  expect(result.skipped).toBe(1);
235
261
  });
236
262
 
237
- test('shutdown commits multiple workspaces', async () => {
238
- const testDir2 = join(tmpdir(), `vellum-heartbeat-test2-${Date.now()}-${Math.random().toString(36).slice(2)}`);
263
+ test("shutdown commits multiple workspaces", async () => {
264
+ const testDir2 = join(
265
+ tmpdir(),
266
+ `vellum-heartbeat-test2-${Date.now()}-${Math.random()
267
+ .toString(36)
268
+ .slice(2)}`,
269
+ );
239
270
  mkdirSync(testDir2, { recursive: true });
240
271
  const service2 = new WorkspaceGitService(testDir2);
241
272
  await service2.ensureInitialized();
242
273
  services.set(testDir2, service2);
243
274
 
244
- writeFileSync(join(testDir, 'file1.txt'), 'content1');
245
- writeFileSync(join(testDir2, 'file2.txt'), 'content2');
275
+ writeFileSync(join(testDir, "file1.txt"), "content1");
276
+ writeFileSync(join(testDir2, "file2.txt"), "content2");
246
277
 
247
278
  const heartbeat = new WorkspaceHeartbeatService({
248
279
  getServices: () => services,
@@ -258,9 +289,12 @@ describe('WorkspaceHeartbeatService', () => {
258
289
  });
259
290
  });
260
291
 
261
- describe('uninitialized workspaces', () => {
262
- test('skips uninitialized workspaces', async () => {
263
- const uninitDir = join(tmpdir(), `vellum-uninit-${Date.now()}-${Math.random().toString(36).slice(2)}`);
292
+ describe("uninitialized workspaces", () => {
293
+ test("skips uninitialized workspaces", async () => {
294
+ const uninitDir = join(
295
+ tmpdir(),
296
+ `vellum-uninit-${Date.now()}-${Math.random().toString(36).slice(2)}`,
297
+ );
264
298
  mkdirSync(uninitDir, { recursive: true });
265
299
 
266
300
  const uninitService = new WorkspaceGitService(uninitDir);
@@ -268,7 +302,7 @@ describe('WorkspaceHeartbeatService', () => {
268
302
  mixedServices.set(uninitDir, uninitService);
269
303
  mixedServices.set(testDir, service);
270
304
 
271
- writeFileSync(join(testDir, 'file.txt'), 'content');
305
+ writeFileSync(join(testDir, "file.txt"), "content");
272
306
 
273
307
  const heartbeat = new WorkspaceHeartbeatService({
274
308
  ageThresholdMs: 0,
@@ -289,8 +323,8 @@ describe('WorkspaceHeartbeatService', () => {
289
323
  });
290
324
  });
291
325
 
292
- describe('threshold behavior', () => {
293
- test('resets dirty tracking after successful commit', async () => {
326
+ describe("threshold behavior", () => {
327
+ test("resets dirty tracking after successful commit", async () => {
294
328
  let currentTime = 1000000;
295
329
  const heartbeat = new WorkspaceHeartbeatService({
296
330
  ageThresholdMs: 5 * 60 * 1000,
@@ -300,7 +334,7 @@ describe('WorkspaceHeartbeatService', () => {
300
334
  });
301
335
 
302
336
  // Create changes and register dirty state
303
- writeFileSync(join(testDir, 'file1.txt'), 'content');
337
+ writeFileSync(join(testDir, "file1.txt"), "content");
304
338
  await heartbeat.check(); // Records first-seen time
305
339
 
306
340
  // Advance past threshold and commit
@@ -309,7 +343,7 @@ describe('WorkspaceHeartbeatService', () => {
309
343
  expect(firstResult.committed).toBe(1);
310
344
 
311
345
  // Create new changes after the commit
312
- writeFileSync(join(testDir, 'file2.txt'), 'more content');
346
+ writeFileSync(join(testDir, "file2.txt"), "more content");
313
347
 
314
348
  // Check again immediately -- should not commit (dirty timer was reset)
315
349
  const secondResult = await heartbeat.check();
@@ -321,8 +355,8 @@ describe('WorkspaceHeartbeatService', () => {
321
355
  expect(thirdResult.committed).toBe(1);
322
356
  });
323
357
 
324
- test('commit message includes trigger metadata', async () => {
325
- writeFileSync(join(testDir, 'file.txt'), 'content');
358
+ test("commit message includes trigger metadata", async () => {
359
+ writeFileSync(join(testDir, "file.txt"), "content");
326
360
 
327
361
  const heartbeat = new WorkspaceHeartbeatService({
328
362
  ageThresholdMs: 0,
@@ -334,16 +368,16 @@ describe('WorkspaceHeartbeatService', () => {
334
368
  await heartbeat.check();
335
369
  await heartbeat.check();
336
370
 
337
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
371
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
338
372
  cwd: testDir,
339
- encoding: 'utf-8',
373
+ encoding: "utf-8",
340
374
  });
341
375
  expect(commitMsg).toContain('trigger: "heartbeat"');
342
376
  });
343
377
  });
344
378
 
345
- describe('start and stop', () => {
346
- test('start and stop are idempotent', async () => {
379
+ describe("start and stop", () => {
380
+ test("start and stop are idempotent", async () => {
347
381
  const heartbeat = new WorkspaceHeartbeatService({
348
382
  intervalMs: 60000,
349
383
  getServices: () => services,
@@ -357,9 +391,9 @@ describe('WorkspaceHeartbeatService', () => {
357
391
  });
358
392
  });
359
393
 
360
- describe('custom commit message provider', () => {
361
- test('heartbeat commit uses custom provider message', async () => {
362
- writeFileSync(join(testDir, 'file.txt'), 'content');
394
+ describe("custom commit message provider", () => {
395
+ test("heartbeat commit uses custom provider message", async () => {
396
+ writeFileSync(join(testDir, "file.txt"), "content");
363
397
 
364
398
  const customProvider: CommitMessageProvider = {
365
399
  buildImmediateMessage(ctx: CommitContext): CommitMessageResult {
@@ -387,17 +421,17 @@ describe('WorkspaceHeartbeatService', () => {
387
421
  const result = await heartbeat.check();
388
422
  expect(result.committed).toBe(1);
389
423
 
390
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
424
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
391
425
  cwd: testDir,
392
- encoding: 'utf-8',
426
+ encoding: "utf-8",
393
427
  });
394
- expect(commitMsg).toContain('CUSTOM-HEARTBEAT:');
395
- expect(commitMsg).toContain('via heartbeat');
396
- expect(commitMsg).toContain('customProvider: true');
428
+ expect(commitMsg).toContain("CUSTOM-HEARTBEAT:");
429
+ expect(commitMsg).toContain("via heartbeat");
430
+ expect(commitMsg).toContain("customProvider: true");
397
431
  });
398
432
 
399
- test('shutdown commit uses custom provider message', async () => {
400
- writeFileSync(join(testDir, 'unsaved.txt'), 'uncommitted content');
433
+ test("shutdown commit uses custom provider message", async () => {
434
+ writeFileSync(join(testDir, "unsaved.txt"), "uncommitted content");
401
435
 
402
436
  const customProvider: CommitMessageProvider = {
403
437
  buildImmediateMessage(ctx: CommitContext): CommitMessageResult {
@@ -416,23 +450,23 @@ describe('WorkspaceHeartbeatService', () => {
416
450
  const result = await heartbeat.commitAllPending();
417
451
  expect(result.committed).toBe(1);
418
452
 
419
- const commitMsg = execFileSync('git', ['log', '-1', '--pretty=%B'], {
453
+ const commitMsg = execFileSync("git", ["log", "-1", "--pretty=%B"], {
420
454
  cwd: testDir,
421
- encoding: 'utf-8',
455
+ encoding: "utf-8",
422
456
  });
423
- expect(commitMsg).toContain('CUSTOM-SHUTDOWN: saving');
424
- expect(commitMsg).toContain('shutdownProvider: true');
457
+ expect(commitMsg).toContain("CUSTOM-SHUTDOWN: saving");
458
+ expect(commitMsg).toContain("shutdownProvider: true");
425
459
  });
426
460
 
427
- test('custom provider receives correct context fields for heartbeat trigger', async () => {
428
- writeFileSync(join(testDir, 'a.txt'), 'a');
429
- writeFileSync(join(testDir, 'b.txt'), 'b');
461
+ test("custom provider receives correct context fields for heartbeat trigger", async () => {
462
+ writeFileSync(join(testDir, "a.txt"), "a");
463
+ writeFileSync(join(testDir, "b.txt"), "b");
430
464
 
431
465
  let capturedCtx: CommitContext | null = null;
432
466
  const customProvider: CommitMessageProvider = {
433
467
  buildImmediateMessage(ctx: CommitContext): CommitMessageResult {
434
468
  capturedCtx = ctx;
435
- return { message: 'capture-context' };
469
+ return { message: "capture-context" };
436
470
  },
437
471
  };
438
472
 
@@ -452,22 +486,22 @@ describe('WorkspaceHeartbeatService', () => {
452
486
  await heartbeat.check();
453
487
 
454
488
  expect(capturedCtx).not.toBeNull();
455
- expect(capturedCtx!.trigger).toBe('heartbeat');
489
+ expect(capturedCtx!.trigger).toBe("heartbeat");
456
490
  expect(capturedCtx!.workspaceDir).toBe(testDir);
457
- expect(capturedCtx!.changedFiles).toContain('a.txt');
458
- expect(capturedCtx!.changedFiles).toContain('b.txt');
491
+ expect(capturedCtx!.changedFiles).toContain("a.txt");
492
+ expect(capturedCtx!.changedFiles).toContain("b.txt");
459
493
  expect(capturedCtx!.timestampMs).toBe(currentTime);
460
494
  expect(capturedCtx!.reason).toBeDefined();
461
495
  });
462
496
 
463
- test('custom provider receives correct context fields for shutdown trigger', async () => {
464
- writeFileSync(join(testDir, 'shutdown-file.txt'), 'data');
497
+ test("custom provider receives correct context fields for shutdown trigger", async () => {
498
+ writeFileSync(join(testDir, "shutdown-file.txt"), "data");
465
499
 
466
500
  let capturedCtx: CommitContext | null = null;
467
501
  const customProvider: CommitMessageProvider = {
468
502
  buildImmediateMessage(ctx: CommitContext): CommitMessageResult {
469
503
  capturedCtx = ctx;
470
- return { message: 'capture-shutdown-context' };
504
+ return { message: "capture-shutdown-context" };
471
505
  },
472
506
  };
473
507
 
@@ -479,9 +513,9 @@ describe('WorkspaceHeartbeatService', () => {
479
513
  await heartbeat.commitAllPending();
480
514
 
481
515
  expect(capturedCtx).not.toBeNull();
482
- expect(capturedCtx!.trigger).toBe('shutdown');
516
+ expect(capturedCtx!.trigger).toBe("shutdown");
483
517
  expect(capturedCtx!.workspaceDir).toBe(testDir);
484
- expect(capturedCtx!.changedFiles).toContain('shutdown-file.txt');
518
+ expect(capturedCtx!.changedFiles).toContain("shutdown-file.txt");
485
519
  });
486
520
  });
487
521
  });