@vellumai/assistant 0.4.17 → 0.4.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/docs/runbook-trusted-contacts.md +5 -3
  2. package/eslint.config.mjs +2 -2
  3. package/package.json +1 -1
  4. package/src/__tests__/access-request-decision.test.ts +128 -120
  5. package/src/__tests__/account-registry.test.ts +121 -110
  6. package/src/__tests__/active-skill-tools.test.ts +200 -172
  7. package/src/__tests__/actor-token-service.test.ts +341 -274
  8. package/src/__tests__/agent-loop-thinking.test.ts +28 -19
  9. package/src/__tests__/agent-loop.test.ts +798 -378
  10. package/src/__tests__/anthropic-provider.test.ts +405 -247
  11. package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
  12. package/src/__tests__/app-bundler.test.ts +112 -79
  13. package/src/__tests__/app-executors.test.ts +205 -178
  14. package/src/__tests__/app-git-history.test.ts +90 -73
  15. package/src/__tests__/app-git-service.test.ts +67 -53
  16. package/src/__tests__/app-open-proxy.test.ts +29 -25
  17. package/src/__tests__/approval-conversation-turn.test.ts +100 -81
  18. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
  19. package/src/__tests__/approval-message-composer.test.ts +119 -119
  20. package/src/__tests__/approval-primitive.test.ts +264 -233
  21. package/src/__tests__/approval-routes-http.test.ts +4 -3
  22. package/src/__tests__/asset-materialize-tool.test.ts +250 -178
  23. package/src/__tests__/asset-search-tool.test.ts +251 -191
  24. package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
  25. package/src/__tests__/assistant-attachments.test.ts +254 -186
  26. package/src/__tests__/assistant-event-hub.test.ts +105 -63
  27. package/src/__tests__/assistant-event.test.ts +66 -58
  28. package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
  29. package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
  30. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
  32. package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
  33. package/src/__tests__/attachments-store.test.ts +240 -183
  34. package/src/__tests__/attachments.test.ts +70 -62
  35. package/src/__tests__/audit-log-rotation.test.ts +50 -35
  36. package/src/__tests__/browser-fill-credential.test.ts +169 -101
  37. package/src/__tests__/browser-manager.test.ts +97 -75
  38. package/src/__tests__/browser-runtime-check.test.ts +16 -15
  39. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
  40. package/src/__tests__/browser-skill-endstate.test.ts +97 -72
  41. package/src/__tests__/bundle-scanner.test.ts +47 -22
  42. package/src/__tests__/bundled-asset.test.ts +74 -47
  43. package/src/__tests__/call-constants.test.ts +19 -19
  44. package/src/__tests__/call-controller.test.ts +0 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +90 -65
  46. package/src/__tests__/call-domain.test.ts +149 -121
  47. package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
  48. package/src/__tests__/call-pointer-messages.test.ts +213 -154
  49. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
  50. package/src/__tests__/call-recovery.test.ts +232 -212
  51. package/src/__tests__/call-routes-http.test.ts +0 -1
  52. package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
  53. package/src/__tests__/call-state-machine.test.ts +62 -51
  54. package/src/__tests__/call-state.test.ts +89 -75
  55. package/src/__tests__/call-store.test.ts +387 -316
  56. package/src/__tests__/callback-handoff-copy.test.ts +84 -82
  57. package/src/__tests__/canonical-guardian-store.test.ts +331 -280
  58. package/src/__tests__/channel-approval-routes.test.ts +1643 -1115
  59. package/src/__tests__/channel-approval.test.ts +139 -137
  60. package/src/__tests__/channel-approvals.test.ts +7 -2
  61. package/src/__tests__/channel-delivery-store.test.ts +232 -194
  62. package/src/__tests__/channel-guardian.test.ts +5 -3
  63. package/src/__tests__/channel-invite-transport.test.ts +107 -92
  64. package/src/__tests__/channel-policy.test.ts +42 -38
  65. package/src/__tests__/channel-readiness-service.test.ts +119 -102
  66. package/src/__tests__/channel-reply-delivery.test.ts +147 -118
  67. package/src/__tests__/channel-retry-sweep.test.ts +153 -110
  68. package/src/__tests__/checker.test.ts +3309 -1850
  69. package/src/__tests__/clarification-resolver.test.ts +91 -79
  70. package/src/__tests__/classifier.test.ts +64 -54
  71. package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
  72. package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
  73. package/src/__tests__/clawhub.test.ts +92 -82
  74. package/src/__tests__/cli.test.ts +30 -30
  75. package/src/__tests__/clipboard.test.ts +53 -46
  76. package/src/__tests__/commit-guarantee.test.ts +59 -52
  77. package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
  78. package/src/__tests__/compaction.benchmark.test.ts +33 -31
  79. package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
  80. package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
  81. package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
  82. package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
  83. package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
  84. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
  85. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
  86. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
  87. package/src/__tests__/computer-use-tools.test.ts +121 -98
  88. package/src/__tests__/config-schema.test.ts +443 -347
  89. package/src/__tests__/config-watcher.test.ts +96 -81
  90. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
  91. package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
  92. package/src/__tests__/conflict-policy.test.ts +151 -80
  93. package/src/__tests__/conflict-store.test.ts +203 -157
  94. package/src/__tests__/connection-policy.test.ts +89 -59
  95. package/src/__tests__/contacts-tools.test.ts +247 -178
  96. package/src/__tests__/context-memory-e2e.test.ts +306 -214
  97. package/src/__tests__/context-token-estimator.test.ts +114 -74
  98. package/src/__tests__/context-window-manager.test.ts +269 -167
  99. package/src/__tests__/contradiction-checker.test.ts +161 -135
  100. package/src/__tests__/conversation-attention-store.test.ts +350 -290
  101. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  102. package/src/__tests__/conversation-pairing.test.ts +220 -113
  103. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  104. package/src/__tests__/conversation-store.test.ts +390 -235
  105. package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
  106. package/src/__tests__/credential-broker-server-use.test.ts +283 -243
  107. package/src/__tests__/credential-broker.test.ts +128 -74
  108. package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
  109. package/src/__tests__/credential-metadata-store.test.ts +360 -311
  110. package/src/__tests__/credential-policy-validate.test.ts +81 -65
  111. package/src/__tests__/credential-resolve.test.ts +212 -145
  112. package/src/__tests__/credential-security-e2e.test.ts +144 -103
  113. package/src/__tests__/credential-security-invariants.test.ts +253 -208
  114. package/src/__tests__/credential-selection.test.ts +254 -146
  115. package/src/__tests__/credential-vault-unit.test.ts +531 -341
  116. package/src/__tests__/credential-vault.test.ts +761 -484
  117. package/src/__tests__/daemon-assistant-events.test.ts +91 -66
  118. package/src/__tests__/daemon-lifecycle.test.ts +258 -190
  119. package/src/__tests__/daemon-server-session-init.test.ts +2 -1
  120. package/src/__tests__/date-context.test.ts +314 -249
  121. package/src/__tests__/db-migration-rollback.test.ts +259 -130
  122. package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
  123. package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
  124. package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
  125. package/src/__tests__/dictation-mode-detection.test.ts +77 -55
  126. package/src/__tests__/dictation-profile-store.test.ts +70 -56
  127. package/src/__tests__/dictation-text-processing.test.ts +53 -35
  128. package/src/__tests__/diff.test.ts +102 -98
  129. package/src/__tests__/domain-normalize.test.ts +54 -54
  130. package/src/__tests__/domain-policy.test.ts +71 -55
  131. package/src/__tests__/dynamic-page-surface.test.ts +31 -33
  132. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
  133. package/src/__tests__/edit-engine.test.ts +56 -56
  134. package/src/__tests__/elevenlabs-client.test.ts +117 -91
  135. package/src/__tests__/elevenlabs-config.test.ts +32 -31
  136. package/src/__tests__/email-classifier.test.ts +15 -12
  137. package/src/__tests__/email-cli.test.ts +121 -108
  138. package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
  139. package/src/__tests__/encrypted-store.test.ts +180 -154
  140. package/src/__tests__/entity-extractor.test.ts +108 -87
  141. package/src/__tests__/entity-search.test.ts +664 -258
  142. package/src/__tests__/ephemeral-permissions.test.ts +224 -188
  143. package/src/__tests__/event-bus.test.ts +81 -77
  144. package/src/__tests__/extract-email.test.ts +29 -20
  145. package/src/__tests__/file-edit-tool.test.ts +62 -44
  146. package/src/__tests__/file-ops-service.test.ts +131 -114
  147. package/src/__tests__/file-read-tool.test.ts +48 -31
  148. package/src/__tests__/file-write-tool.test.ts +43 -37
  149. package/src/__tests__/filesystem-tools.test.ts +238 -209
  150. package/src/__tests__/followup-tools.test.ts +237 -162
  151. package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
  152. package/src/__tests__/frontmatter.test.ts +96 -81
  153. package/src/__tests__/fuzzy-match-property.test.ts +75 -81
  154. package/src/__tests__/fuzzy-match.test.ts +71 -65
  155. package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
  156. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  157. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  158. package/src/__tests__/gemini-image-service.test.ts +113 -100
  159. package/src/__tests__/gemini-provider.test.ts +297 -220
  160. package/src/__tests__/get-weather.test.ts +188 -114
  161. package/src/__tests__/gmail-integration.test.ts +13 -5
  162. package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
  163. package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
  164. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
  165. package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
  166. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
  167. package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
  168. package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
  169. package/src/__tests__/guardian-action-store.test.ts +158 -109
  170. package/src/__tests__/guardian-action-sweep.test.ts +114 -100
  171. package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
  172. package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
  173. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
  174. package/src/__tests__/guardian-dispatch.test.ts +316 -256
  175. package/src/__tests__/guardian-grant-minting.test.ts +247 -178
  176. package/src/__tests__/guardian-outbound-http.test.ts +5 -3
  177. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
  178. package/src/__tests__/guardian-question-copy.test.ts +17 -17
  179. package/src/__tests__/guardian-question-mode.test.ts +134 -100
  180. package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
  181. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  182. package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
  183. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
  184. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
  185. package/src/__tests__/handle-user-message-secret-resume.test.ts +7 -2
  186. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
  187. package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
  188. package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
  189. package/src/__tests__/handlers-slack-config.test.ts +63 -54
  190. package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
  191. package/src/__tests__/handlers-telegram-config.test.ts +662 -329
  192. package/src/__tests__/handlers-twitter-config.test.ts +525 -298
  193. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +5 -2
  194. package/src/__tests__/headless-browser-interactions.test.ts +444 -280
  195. package/src/__tests__/headless-browser-navigate.test.ts +116 -79
  196. package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
  197. package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
  198. package/src/__tests__/heartbeat-service.test.ts +76 -58
  199. package/src/__tests__/history-repair-observability.test.ts +14 -14
  200. package/src/__tests__/history-repair.test.ts +171 -167
  201. package/src/__tests__/home-base-bootstrap.test.ts +30 -27
  202. package/src/__tests__/hooks-blocking.test.ts +86 -37
  203. package/src/__tests__/hooks-cli.test.ts +104 -68
  204. package/src/__tests__/hooks-config.test.ts +81 -43
  205. package/src/__tests__/hooks-discovery.test.ts +106 -96
  206. package/src/__tests__/hooks-integration.test.ts +78 -72
  207. package/src/__tests__/hooks-manager.test.ts +99 -61
  208. package/src/__tests__/hooks-runner.test.ts +94 -71
  209. package/src/__tests__/hooks-settings.test.ts +69 -64
  210. package/src/__tests__/hooks-templates.test.ts +85 -54
  211. package/src/__tests__/hooks-ts-runner.test.ts +82 -45
  212. package/src/__tests__/hooks-watch.test.ts +32 -22
  213. package/src/__tests__/host-file-edit-tool.test.ts +190 -148
  214. package/src/__tests__/host-file-read-tool.test.ts +86 -63
  215. package/src/__tests__/host-file-write-tool.test.ts +98 -64
  216. package/src/__tests__/host-shell-tool.test.ts +342 -233
  217. package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
  218. package/src/__tests__/ingress-member-store.test.ts +163 -159
  219. package/src/__tests__/ingress-reconcile.test.ts +13 -6
  220. package/src/__tests__/ingress-routes-http.test.ts +441 -356
  221. package/src/__tests__/ingress-url-consistency.test.ts +125 -64
  222. package/src/__tests__/integration-status.test.ts +93 -73
  223. package/src/__tests__/intent-routing.test.ts +148 -118
  224. package/src/__tests__/invite-redemption-service.test.ts +163 -121
  225. package/src/__tests__/ipc-blob-store.test.ts +104 -91
  226. package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
  227. package/src/__tests__/ipc-contract.test.ts +24 -23
  228. package/src/__tests__/ipc-protocol.test.ts +52 -46
  229. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
  230. package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
  231. package/src/__tests__/ipc-validate.test.ts +240 -179
  232. package/src/__tests__/key-migration.test.ts +123 -90
  233. package/src/__tests__/keychain.test.ts +150 -123
  234. package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
  235. package/src/__tests__/llm-usage-store.test.ts +112 -87
  236. package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
  237. package/src/__tests__/managed-store.test.ts +411 -360
  238. package/src/__tests__/mcp-cli.test.ts +190 -124
  239. package/src/__tests__/mcp-health-check.test.ts +26 -21
  240. package/src/__tests__/media-generate-image.test.ts +122 -99
  241. package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
  242. package/src/__tests__/media-visibility-policy.test.ts +86 -38
  243. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
  244. package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
  245. package/src/__tests__/memory-query-builder.test.ts +32 -33
  246. package/src/__tests__/memory-recall-quality.test.ts +761 -407
  247. package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
  248. package/src/__tests__/memory-regressions.test.ts +3725 -2642
  249. package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
  250. package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
  251. package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
  252. package/src/__tests__/messaging-send-tool.test.ts +36 -29
  253. package/src/__tests__/migration-cli-flows.test.ts +69 -53
  254. package/src/__tests__/migration-ordering.test.ts +103 -86
  255. package/src/__tests__/mime-builder.test.ts +55 -32
  256. package/src/__tests__/mock-signup-server.test.ts +384 -246
  257. package/src/__tests__/model-intents.test.ts +61 -37
  258. package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
  259. package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
  260. package/src/__tests__/non-member-access-request.test.ts +3 -2
  261. package/src/__tests__/notification-broadcaster.test.ts +99 -81
  262. package/src/__tests__/notification-decision-fallback.test.ts +223 -178
  263. package/src/__tests__/notification-decision-strategy.test.ts +375 -337
  264. package/src/__tests__/notification-deep-link.test.ts +67 -61
  265. package/src/__tests__/notification-guardian-path.test.ts +248 -206
  266. package/src/__tests__/notification-routing-intent.test.ts +166 -93
  267. package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
  268. package/src/__tests__/notification-thread-candidates.test.ts +64 -61
  269. package/src/__tests__/oauth-callback-registry.test.ts +40 -30
  270. package/src/__tests__/oauth-connect-handler.test.ts +109 -89
  271. package/src/__tests__/oauth-scope-policy.test.ts +63 -55
  272. package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
  273. package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
  274. package/src/__tests__/onboarding-template-contract.test.ts +93 -94
  275. package/src/__tests__/openai-provider.test.ts +366 -274
  276. package/src/__tests__/pairing-concurrent.test.ts +18 -12
  277. package/src/__tests__/pairing-routes.test.ts +45 -41
  278. package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
  279. package/src/__tests__/parser.test.ts +316 -226
  280. package/src/__tests__/path-classifier.test.ts +24 -25
  281. package/src/__tests__/path-policy.test.ts +187 -147
  282. package/src/__tests__/phone.test.ts +36 -36
  283. package/src/__tests__/platform-move-helper.test.ts +48 -40
  284. package/src/__tests__/platform-socket-path.test.ts +23 -24
  285. package/src/__tests__/platform-workspace-migration.test.ts +464 -414
  286. package/src/__tests__/platform.test.ts +61 -53
  287. package/src/__tests__/playbook-execution.test.ts +397 -265
  288. package/src/__tests__/playbook-tools.test.ts +267 -196
  289. package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
  290. package/src/__tests__/pricing.test.ts +316 -136
  291. package/src/__tests__/profile-compiler.test.ts +206 -188
  292. package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
  293. package/src/__tests__/provider-error-scenarios.test.ts +212 -158
  294. package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
  295. package/src/__tests__/provider-registry-ollama.test.ts +13 -9
  296. package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
  297. package/src/__tests__/proxy-approval-callback.test.ts +180 -119
  298. package/src/__tests__/public-ingress-urls.test.ts +112 -94
  299. package/src/__tests__/qdrant-manager.test.ts +147 -98
  300. package/src/__tests__/ratelimit.test.ts +152 -82
  301. package/src/__tests__/recording-handler.test.ts +273 -151
  302. package/src/__tests__/recording-intent-fallback.test.ts +94 -75
  303. package/src/__tests__/recording-intent-handler.test.ts +9 -2
  304. package/src/__tests__/recording-intent.test.ts +578 -379
  305. package/src/__tests__/recording-state-machine.test.ts +530 -316
  306. package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
  307. package/src/__tests__/recurrence-engine.test.ts +81 -41
  308. package/src/__tests__/recurrence-types.test.ts +63 -44
  309. package/src/__tests__/relay-server.test.ts +2131 -1602
  310. package/src/__tests__/reminder-store.test.ts +158 -80
  311. package/src/__tests__/reminder.test.ts +113 -109
  312. package/src/__tests__/remote-skill-policy.test.ts +96 -72
  313. package/src/__tests__/request-file-tool.test.ts +74 -67
  314. package/src/__tests__/response-tier.test.ts +131 -74
  315. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  316. package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
  317. package/src/__tests__/runtime-events-sse.test.ts +0 -1
  318. package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
  319. package/src/__tests__/sandbox-host-parity.test.ts +377 -301
  320. package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
  321. package/src/__tests__/schedule-store.test.ts +268 -205
  322. package/src/__tests__/schedule-tools.test.ts +702 -524
  323. package/src/__tests__/scheduler-recurrence.test.ts +240 -130
  324. package/src/__tests__/scoped-approval-grants.test.ts +258 -168
  325. package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
  326. package/src/__tests__/script-proxy-certs.test.ts +38 -35
  327. package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
  328. package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
  329. package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
  330. package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
  331. package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
  332. package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
  333. package/src/__tests__/script-proxy-policy.test.ts +308 -153
  334. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
  335. package/src/__tests__/script-proxy-router.test.ts +111 -77
  336. package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
  337. package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
  338. package/src/__tests__/secret-allowlist.test.ts +105 -90
  339. package/src/__tests__/secret-ingress-handler.test.ts +41 -30
  340. package/src/__tests__/secret-onetime-send.test.ts +67 -50
  341. package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
  342. package/src/__tests__/secret-response-routing.test.ts +50 -41
  343. package/src/__tests__/secret-scanner-executor.test.ts +152 -111
  344. package/src/__tests__/secret-scanner.test.ts +495 -413
  345. package/src/__tests__/secure-keys.test.ts +132 -121
  346. package/src/__tests__/send-endpoint-busy.test.ts +8 -3
  347. package/src/__tests__/send-notification-tool.test.ts +43 -42
  348. package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
  349. package/src/__tests__/sequence-store.test.ts +335 -167
  350. package/src/__tests__/server-history-render.test.ts +341 -202
  351. package/src/__tests__/session-abort-tool-results.test.ts +133 -70
  352. package/src/__tests__/session-confirmation-signals.test.ts +252 -160
  353. package/src/__tests__/session-conflict-gate.test.ts +775 -585
  354. package/src/__tests__/session-error.test.ts +222 -191
  355. package/src/__tests__/session-evictor.test.ts +79 -62
  356. package/src/__tests__/session-init.benchmark.test.ts +170 -108
  357. package/src/__tests__/session-load-history-repair.test.ts +273 -139
  358. package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
  359. package/src/__tests__/session-pre-run-repair.test.ts +106 -59
  360. package/src/__tests__/session-profile-injection.test.ts +198 -130
  361. package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
  362. package/src/__tests__/session-queue.test.ts +624 -321
  363. package/src/__tests__/session-runtime-assembly.test.ts +425 -329
  364. package/src/__tests__/session-runtime-workspace.test.ts +69 -61
  365. package/src/__tests__/session-skill-tools.test.ts +973 -678
  366. package/src/__tests__/session-slash-known.test.ts +185 -133
  367. package/src/__tests__/session-slash-queue.test.ts +147 -81
  368. package/src/__tests__/session-slash-unknown.test.ts +135 -90
  369. package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
  370. package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
  371. package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
  372. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
  373. package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
  374. package/src/__tests__/session-undo.test.ts +43 -30
  375. package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
  376. package/src/__tests__/session-workspace-injection.test.ts +245 -117
  377. package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
  378. package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
  379. package/src/__tests__/shell-credential-ref.test.ts +126 -90
  380. package/src/__tests__/shell-identity.test.ts +134 -111
  381. package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
  382. package/src/__tests__/shell-parser-property.test.ts +435 -288
  383. package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
  384. package/src/__tests__/size-guard.test.ts +42 -44
  385. package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
  386. package/src/__tests__/skill-feature-flags.test.ts +75 -47
  387. package/src/__tests__/skill-include-graph.test.ts +143 -148
  388. package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
  389. package/src/__tests__/skill-load-tool.test.ts +371 -199
  390. package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
  391. package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
  392. package/src/__tests__/skill-script-runner-host.test.ts +460 -250
  393. package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
  394. package/src/__tests__/skill-script-runner.test.ts +115 -74
  395. package/src/__tests__/skill-tool-factory.test.ts +140 -96
  396. package/src/__tests__/skill-tool-manifest.test.ts +306 -210
  397. package/src/__tests__/skill-version-hash.test.ts +70 -56
  398. package/src/__tests__/skills.test.ts +0 -1
  399. package/src/__tests__/slack-channel-config.test.ts +127 -84
  400. package/src/__tests__/slack-skill.test.ts +60 -47
  401. package/src/__tests__/slash-commands-catalog.test.ts +37 -31
  402. package/src/__tests__/slash-commands-parser.test.ts +71 -64
  403. package/src/__tests__/slash-commands-resolver.test.ts +143 -107
  404. package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
  405. package/src/__tests__/sms-messaging-provider.test.ts +4 -0
  406. package/src/__tests__/speaker-identification.test.ts +28 -25
  407. package/src/__tests__/starter-bundle.test.ts +27 -23
  408. package/src/__tests__/starter-task-flow.test.ts +67 -52
  409. package/src/__tests__/subagent-manager-notify.test.ts +154 -108
  410. package/src/__tests__/subagent-tools.test.ts +311 -270
  411. package/src/__tests__/subagent-types.test.ts +40 -40
  412. package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
  413. package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
  414. package/src/__tests__/swarm-orchestrator.test.ts +135 -101
  415. package/src/__tests__/swarm-plan-validator.test.ts +125 -73
  416. package/src/__tests__/swarm-recursion.test.ts +58 -46
  417. package/src/__tests__/swarm-router-planner.test.ts +99 -74
  418. package/src/__tests__/swarm-session-integration.test.ts +148 -91
  419. package/src/__tests__/swarm-tool.test.ts +65 -45
  420. package/src/__tests__/swarm-worker-backend.test.ts +59 -45
  421. package/src/__tests__/swarm-worker-runner.test.ts +133 -118
  422. package/src/__tests__/system-prompt.test.ts +311 -256
  423. package/src/__tests__/task-compiler.test.ts +176 -120
  424. package/src/__tests__/task-management-tools.test.ts +561 -456
  425. package/src/__tests__/task-memory-cleanup.test.ts +627 -362
  426. package/src/__tests__/task-runner.test.ts +117 -94
  427. package/src/__tests__/task-scheduler.test.ts +113 -84
  428. package/src/__tests__/task-tools.test.ts +349 -264
  429. package/src/__tests__/terminal-sandbox.test.ts +138 -108
  430. package/src/__tests__/terminal-tools.test.ts +350 -305
  431. package/src/__tests__/thread-seed-composer.test.ts +307 -180
  432. package/src/__tests__/tool-approval-handler.test.ts +238 -137
  433. package/src/__tests__/tool-audit-listener.test.ts +69 -69
  434. package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
  435. package/src/__tests__/tool-execution-abort-cleanup.test.ts +155 -146
  436. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
  437. package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
  438. package/src/__tests__/tool-executor-redaction.test.ts +112 -109
  439. package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
  440. package/src/__tests__/tool-executor.test.ts +1274 -674
  441. package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
  442. package/src/__tests__/tool-metrics-listener.test.ts +97 -85
  443. package/src/__tests__/tool-notification-listener.test.ts +42 -25
  444. package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
  445. package/src/__tests__/tool-policy.test.ts +44 -25
  446. package/src/__tests__/tool-profiling-listener.test.ts +99 -93
  447. package/src/__tests__/tool-result-truncation.test.ts +5 -4
  448. package/src/__tests__/tool-trace-listener.test.ts +131 -111
  449. package/src/__tests__/top-level-renderer.test.ts +62 -58
  450. package/src/__tests__/top-level-scanner.test.ts +68 -64
  451. package/src/__tests__/trace-emitter.test.ts +56 -56
  452. package/src/__tests__/trust-context-guards.test.ts +65 -65
  453. package/src/__tests__/trust-store.test.ts +1239 -806
  454. package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
  455. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
  456. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
  457. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
  458. package/src/__tests__/trusted-contact-verification.test.ts +251 -231
  459. package/src/__tests__/turn-commit.test.ts +259 -200
  460. package/src/__tests__/twilio-provider.test.ts +140 -126
  461. package/src/__tests__/twilio-rest.test.ts +22 -18
  462. package/src/__tests__/twilio-routes-elevenlabs.test.ts +0 -1
  463. package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
  464. package/src/__tests__/twilio-routes.test.ts +0 -1
  465. package/src/__tests__/twitter-auth-handler.test.ts +184 -139
  466. package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
  467. package/src/__tests__/twitter-cli-routing.test.ts +146 -99
  468. package/src/__tests__/twitter-oauth-client.test.ts +82 -65
  469. package/src/__tests__/update-bulletin-format.test.ts +69 -66
  470. package/src/__tests__/update-bulletin-state.test.ts +66 -60
  471. package/src/__tests__/update-bulletin.test.ts +150 -114
  472. package/src/__tests__/update-template-contract.test.ts +15 -10
  473. package/src/__tests__/url-safety.test.ts +288 -265
  474. package/src/__tests__/user-reference.test.ts +32 -32
  475. package/src/__tests__/view-image-tool.test.ts +118 -96
  476. package/src/__tests__/voice-invite-redemption.test.ts +111 -106
  477. package/src/__tests__/voice-quality.test.ts +117 -102
  478. package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
  479. package/src/__tests__/voice-session-bridge.test.ts +351 -216
  480. package/src/__tests__/weather-skill-regression.test.ts +170 -120
  481. package/src/__tests__/web-fetch.test.ts +664 -526
  482. package/src/__tests__/web-search.test.ts +379 -213
  483. package/src/__tests__/work-item-output.test.ts +90 -53
  484. package/src/__tests__/workspace-git-service.test.ts +437 -356
  485. package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
  486. package/src/__tests__/workspace-lifecycle.test.ts +98 -64
  487. package/src/__tests__/workspace-policy.test.ts +139 -71
  488. package/src/cli/mcp.ts +81 -28
  489. package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
  490. package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
  491. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +25 -10
  492. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
  493. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +6 -11
  494. package/src/config/bundled-skills/messaging/SKILL.md +4 -3
  495. package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
  496. package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
  497. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -2
  498. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
  499. package/src/config/bundled-skills/sms-setup/SKILL.md +8 -16
  500. package/src/config/bundled-skills/telegram-setup/SKILL.md +3 -3
  501. package/src/config/bundled-skills/trusted-contacts/SKILL.md +13 -25
  502. package/src/config/bundled-skills/twilio-setup/SKILL.md +13 -23
  503. package/src/config/bundled-tool-registry.ts +2 -0
  504. package/src/config/env.ts +3 -4
  505. package/src/config/system-prompt.ts +32 -0
  506. package/src/mcp/client.ts +2 -7
  507. package/src/memory/db-connection.ts +16 -10
  508. package/src/messaging/providers/gmail/adapter.ts +10 -3
  509. package/src/messaging/providers/gmail/client.ts +280 -72
  510. package/src/runtime/auth/__tests__/context.test.ts +75 -65
  511. package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
  512. package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
  513. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
  514. package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
  515. package/src/runtime/auth/__tests__/policy.test.ts +9 -9
  516. package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
  517. package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
  518. package/src/runtime/auth/__tests__/subject.test.ts +54 -54
  519. package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
  520. package/src/runtime/auth/scopes.ts +3 -0
  521. package/src/runtime/auth/token-service.ts +4 -1
  522. package/src/runtime/auth/types.ts +2 -1
  523. package/src/runtime/http-server.ts +2 -1
  524. package/src/security/secure-keys.ts +120 -54
  525. package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
  526. package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
  527. package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
  528. package/src/tools/terminal/safe-env.ts +7 -0
@@ -1,4 +1,4 @@
1
- import { beforeEach,describe, expect, mock, test } from 'bun:test';
1
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  // ---------------------------------------------------------------------------
4
4
  // Mock the Agent SDK — prevents real subprocess spawning
@@ -8,82 +8,84 @@ const queryMock = mock(() => {
8
8
  return {
9
9
  async *[Symbol.asyncIterator]() {
10
10
  yield {
11
- type: 'result' as const,
12
- session_id: 'test-session',
13
- subtype: 'success' as const,
14
- result: 'Done.',
11
+ type: "result" as const,
12
+ session_id: "test-session",
13
+ subtype: "success" as const,
14
+ result: "Done.",
15
15
  };
16
16
  },
17
17
  };
18
18
  });
19
19
 
20
- mock.module('@anthropic-ai/claude-agent-sdk', () => ({
20
+ mock.module("@anthropic-ai/claude-agent-sdk", () => ({
21
21
  query: queryMock,
22
22
  }));
23
23
 
24
24
  // Mock logger
25
- mock.module('../util/logger.js', () => ({
26
- getLogger: () => new Proxy({} as Record<string, unknown>, {
27
- get: () => () => {},
28
- }),
25
+ mock.module("../util/logger.js", () => ({
26
+ getLogger: () =>
27
+ new Proxy({} as Record<string, unknown>, {
28
+ get: () => () => {},
29
+ }),
29
30
  }));
30
31
 
31
32
  // Mock config
32
- mock.module('../config/loader.js', () => ({
33
+ mock.module("../config/loader.js", () => ({
33
34
  getConfig: () => ({
34
35
  ui: {},
35
-
36
- apiKeys: { anthropic: 'test-key' },
36
+
37
+ apiKeys: { anthropic: "test-key" },
37
38
  }),
38
39
  }));
39
40
 
40
- import { claudeCodeTool } from '../tools/claude-code/claude-code.js';
41
- import type { ToolContext } from '../tools/types.js';
41
+ import { claudeCodeTool } from "../tools/claude-code/claude-code.js";
42
+ import type { ToolContext } from "../tools/types.js";
42
43
 
43
44
  function makeContext(overrides?: Partial<ToolContext>): ToolContext {
44
45
  return {
45
- sessionId: 'test-session',
46
- workingDir: '/tmp/test',
47
- guardianTrustClass: 'guardian',
46
+ sessionId: "test-session",
47
+ workingDir: "/tmp/test",
48
+ guardianTrustClass: "guardian",
48
49
  onOutput: () => {},
49
50
  ...overrides,
50
51
  } as ToolContext;
51
52
  }
52
53
 
53
- describe('claude_code tool profile support', () => {
54
+ describe("claude_code tool profile support", () => {
54
55
  beforeEach(() => {
55
56
  queryMock.mockClear();
56
57
  });
57
58
 
58
- test('getDefinition includes profile parameter', () => {
59
+ test("getDefinition includes profile parameter", () => {
59
60
  const def = claudeCodeTool.getDefinition();
60
- const props = (def.input_schema as Record<string, unknown>).properties as Record<string, unknown>;
61
+ const props = (def.input_schema as Record<string, unknown>)
62
+ .properties as Record<string, unknown>;
61
63
  expect(props.profile).toBeDefined();
62
64
  });
63
65
 
64
- test('rejects invalid profile', async () => {
66
+ test("rejects invalid profile", async () => {
65
67
  const result = await claudeCodeTool.execute(
66
- { prompt: 'test', profile: 'hacker' },
68
+ { prompt: "test", profile: "hacker" },
67
69
  makeContext(),
68
70
  );
69
71
  expect(result.isError).toBe(true);
70
- expect(result.content).toContain('Invalid profile');
72
+ expect(result.content).toContain("Invalid profile");
71
73
  });
72
74
 
73
- test('accepts valid profiles without error', async () => {
74
- for (const profile of ['general', 'researcher', 'coder', 'reviewer']) {
75
+ test("accepts valid profiles without error", async () => {
76
+ for (const profile of ["general", "researcher", "coder", "reviewer"]) {
75
77
  queryMock.mockClear();
76
78
  const result = await claudeCodeTool.execute(
77
- { prompt: 'test', profile },
79
+ { prompt: "test", profile },
78
80
  makeContext(),
79
81
  );
80
82
  expect(result.isError).toBeFalsy();
81
83
  }
82
84
  });
83
85
 
84
- test('omitted profile defaults to general (backward compat)', async () => {
86
+ test("omitted profile defaults to general (backward compat)", async () => {
85
87
  const result = await claudeCodeTool.execute(
86
- { prompt: 'test' },
88
+ { prompt: "test" },
87
89
  makeContext(),
88
90
  );
89
91
  expect(result.isError).toBeFalsy();
@@ -1,21 +1,27 @@
1
- import { existsSync,mkdirSync, mkdtempSync, 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';
6
- import { mock } from 'bun:test';
7
-
8
- let TEST_DIR = '';
9
-
10
- mock.module('../util/platform.js', () => ({
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ mkdtempSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+ import { mock } from "bun:test";
12
+
13
+ let TEST_DIR = "";
14
+
15
+ mock.module("../util/platform.js", () => ({
11
16
  getRootDir: () => TEST_DIR,
12
- getWorkspaceSkillsDir: () => join(TEST_DIR, 'skills'),
17
+ getWorkspaceSkillsDir: () => join(TEST_DIR, "skills"),
13
18
  }));
14
19
 
15
- mock.module('../util/logger.js', () => ({
16
- getLogger: () => new Proxy({} as Record<string, unknown>, {
17
- get: () => () => {},
18
- }),
20
+ mock.module("../util/logger.js", () => ({
21
+ getLogger: () =>
22
+ new Proxy({} as Record<string, unknown>, {
23
+ get: () => () => {},
24
+ }),
19
25
  }));
20
26
 
21
27
  import {
@@ -23,11 +29,11 @@ import {
23
29
  clawhubInstall,
24
30
  loadIntegrityManifest,
25
31
  verifyAndRecordSkillHash,
26
- } from '../skills/clawhub.js';
32
+ } from "../skills/clawhub.js";
27
33
 
28
34
  beforeEach(() => {
29
- TEST_DIR = mkdtempSync(join(tmpdir(), 'clawhub-test-'));
30
- mkdirSync(join(TEST_DIR, 'skills'), { recursive: true });
35
+ TEST_DIR = mkdtempSync(join(tmpdir(), "clawhub-test-"));
36
+ mkdirSync(join(TEST_DIR, "skills"), { recursive: true });
31
37
  });
32
38
 
33
39
  afterEach(() => {
@@ -38,71 +44,71 @@ afterEach(() => {
38
44
  // Slug validation (exercised through public API)
39
45
  // ---------------------------------------------------------------------------
40
46
 
41
- describe('clawhubInstall slug validation', () => {
42
- test('rejects empty slug', async () => {
43
- const result = await clawhubInstall('');
47
+ describe("clawhubInstall slug validation", () => {
48
+ test("rejects empty slug", async () => {
49
+ const result = await clawhubInstall("");
44
50
  expect(result.success).toBe(false);
45
- expect(result.error).toContain('Invalid skill slug');
51
+ expect(result.error).toContain("Invalid skill slug");
46
52
  });
47
53
 
48
- test('rejects slug starting with a dot', async () => {
49
- const result = await clawhubInstall('.hidden');
54
+ test("rejects slug starting with a dot", async () => {
55
+ const result = await clawhubInstall(".hidden");
50
56
  expect(result.success).toBe(false);
51
- expect(result.error).toContain('Invalid skill slug');
57
+ expect(result.error).toContain("Invalid skill slug");
52
58
  });
53
59
 
54
- test('rejects slug starting with a hyphen', async () => {
55
- const result = await clawhubInstall('-dashed');
60
+ test("rejects slug starting with a hyphen", async () => {
61
+ const result = await clawhubInstall("-dashed");
56
62
  expect(result.success).toBe(false);
57
- expect(result.error).toContain('Invalid skill slug');
63
+ expect(result.error).toContain("Invalid skill slug");
58
64
  });
59
65
 
60
- test('rejects slug with path traversal', async () => {
61
- const result = await clawhubInstall('../escape');
66
+ test("rejects slug with path traversal", async () => {
67
+ const result = await clawhubInstall("../escape");
62
68
  expect(result.success).toBe(false);
63
- expect(result.error).toContain('Invalid skill slug');
69
+ expect(result.error).toContain("Invalid skill slug");
64
70
  });
65
71
 
66
- test('rejects slug with spaces', async () => {
67
- const result = await clawhubInstall('my skill');
72
+ test("rejects slug with spaces", async () => {
73
+ const result = await clawhubInstall("my skill");
68
74
  expect(result.success).toBe(false);
69
- expect(result.error).toContain('Invalid skill slug');
75
+ expect(result.error).toContain("Invalid skill slug");
70
76
  });
71
77
 
72
- test('rejects slug with double slash', async () => {
73
- const result = await clawhubInstall('ns//skill');
78
+ test("rejects slug with double slash", async () => {
79
+ const result = await clawhubInstall("ns//skill");
74
80
  expect(result.success).toBe(false);
75
- expect(result.error).toContain('Invalid skill slug');
81
+ expect(result.error).toContain("Invalid skill slug");
76
82
  });
77
83
 
78
- test('rejects slug ending with slash', async () => {
79
- const result = await clawhubInstall('skill/');
84
+ test("rejects slug ending with slash", async () => {
85
+ const result = await clawhubInstall("skill/");
80
86
  expect(result.success).toBe(false);
81
- expect(result.error).toContain('Invalid skill slug');
87
+ expect(result.error).toContain("Invalid skill slug");
82
88
  });
83
89
 
84
- test('rejects slug with special characters', async () => {
85
- const result = await clawhubInstall('skill@latest');
90
+ test("rejects slug with special characters", async () => {
91
+ const result = await clawhubInstall("skill@latest");
86
92
  expect(result.success).toBe(false);
87
- expect(result.error).toContain('Invalid skill slug');
93
+ expect(result.error).toContain("Invalid skill slug");
88
94
  });
89
95
  });
90
96
 
91
- describe('clawhubInspect slug validation', () => {
92
- test('rejects empty slug', async () => {
93
- const result = await clawhubInspect('');
94
- expect(result.error).toContain('Invalid skill slug');
97
+ describe("clawhubInspect slug validation", () => {
98
+ test("rejects empty slug", async () => {
99
+ const result = await clawhubInspect("");
100
+ expect(result.error).toContain("Invalid skill slug");
95
101
  expect(result.data).toBeUndefined();
96
102
  });
97
103
 
98
- test('rejects slug with path traversal', async () => {
99
- const result = await clawhubInspect('../../etc/passwd');
100
- expect(result.error).toContain('Invalid skill slug');
104
+ test("rejects slug with path traversal", async () => {
105
+ const result = await clawhubInspect("../../etc/passwd");
106
+ expect(result.error).toContain("Invalid skill slug");
101
107
  });
102
108
 
103
- test('rejects slug with spaces', async () => {
104
- const result = await clawhubInspect('bad slug');
105
- expect(result.error).toContain('Invalid skill slug');
109
+ test("rejects slug with spaces", async () => {
110
+ const result = await clawhubInspect("bad slug");
111
+ expect(result.error).toContain("Invalid skill slug");
106
112
  });
107
113
  });
108
114
 
@@ -111,62 +117,66 @@ describe('clawhubInspect slug validation', () => {
111
117
  // which is the code path that reads/writes the manifest.
112
118
  // ---------------------------------------------------------------------------
113
119
 
114
- describe('integrity manifest', () => {
120
+ describe("integrity manifest", () => {
115
121
  function createSkillFiles(slug: string): void {
116
- const skillDir = join(TEST_DIR, 'skills', slug);
122
+ const skillDir = join(TEST_DIR, "skills", slug);
117
123
  mkdirSync(skillDir, { recursive: true });
118
- writeFileSync(join(skillDir, 'SKILL.md'), '# Test Skill\n', 'utf-8');
124
+ writeFileSync(join(skillDir, "SKILL.md"), "# Test Skill\n", "utf-8");
119
125
  }
120
126
 
121
- test('malformed integrity JSON is handled gracefully', () => {
122
- const integrityPath = join(TEST_DIR, 'skills', '.integrity.json');
123
- writeFileSync(integrityPath, '{not valid json!!!', 'utf-8');
124
- createSkillFiles('valid-slug');
127
+ test("malformed integrity JSON is handled gracefully", () => {
128
+ const integrityPath = join(TEST_DIR, "skills", ".integrity.json");
129
+ writeFileSync(integrityPath, "{not valid json!!!", "utf-8");
130
+ createSkillFiles("valid-slug");
125
131
 
126
132
  // Should not throw — malformed manifest is replaced with a fresh one
127
- verifyAndRecordSkillHash('valid-slug');
133
+ verifyAndRecordSkillHash("valid-slug");
128
134
 
129
135
  // Manifest should now contain a valid entry
130
136
  const manifest = loadIntegrityManifest();
131
- expect(manifest['valid-slug']).toBeDefined();
132
- expect(manifest['valid-slug'].sha256).toMatch(/^v2:[0-9a-f]{64}$/);
137
+ expect(manifest["valid-slug"]).toBeDefined();
138
+ expect(manifest["valid-slug"].sha256).toMatch(/^v2:[0-9a-f]{64}$/);
133
139
  });
134
140
 
135
- test('missing integrity manifest is created on first install', () => {
136
- const integrityPath = join(TEST_DIR, 'skills', '.integrity.json');
141
+ test("missing integrity manifest is created on first install", () => {
142
+ const integrityPath = join(TEST_DIR, "skills", ".integrity.json");
137
143
  expect(existsSync(integrityPath)).toBe(false);
138
- createSkillFiles('new-skill');
144
+ createSkillFiles("new-skill");
139
145
 
140
- verifyAndRecordSkillHash('new-skill');
146
+ verifyAndRecordSkillHash("new-skill");
141
147
 
142
148
  // Manifest should now exist with the skill's hash
143
149
  expect(existsSync(integrityPath)).toBe(true);
144
150
  const manifest = loadIntegrityManifest();
145
- expect(manifest['new-skill']).toBeDefined();
146
- expect(manifest['new-skill'].sha256).toMatch(/^v2:[0-9a-f]{64}$/);
151
+ expect(manifest["new-skill"]).toBeDefined();
152
+ expect(manifest["new-skill"].sha256).toMatch(/^v2:[0-9a-f]{64}$/);
147
153
  });
148
154
 
149
- test('re-install with same content preserves hash', () => {
150
- createSkillFiles('stable-skill');
155
+ test("re-install with same content preserves hash", () => {
156
+ createSkillFiles("stable-skill");
151
157
 
152
- verifyAndRecordSkillHash('stable-skill');
153
- const first = loadIntegrityManifest()['stable-skill'].sha256;
158
+ verifyAndRecordSkillHash("stable-skill");
159
+ const first = loadIntegrityManifest()["stable-skill"].sha256;
154
160
 
155
- verifyAndRecordSkillHash('stable-skill');
156
- const second = loadIntegrityManifest()['stable-skill'].sha256;
161
+ verifyAndRecordSkillHash("stable-skill");
162
+ const second = loadIntegrityManifest()["stable-skill"].sha256;
157
163
 
158
164
  expect(first).toBe(second);
159
165
  });
160
166
 
161
- test('re-install with changed content updates hash', () => {
162
- createSkillFiles('changing-skill');
163
- verifyAndRecordSkillHash('changing-skill');
164
- const first = loadIntegrityManifest()['changing-skill'].sha256;
167
+ test("re-install with changed content updates hash", () => {
168
+ createSkillFiles("changing-skill");
169
+ verifyAndRecordSkillHash("changing-skill");
170
+ const first = loadIntegrityManifest()["changing-skill"].sha256;
165
171
 
166
172
  // Modify skill content
167
- writeFileSync(join(TEST_DIR, 'skills', 'changing-skill', 'SKILL.md'), '# Updated\n', 'utf-8');
168
- verifyAndRecordSkillHash('changing-skill');
169
- const second = loadIntegrityManifest()['changing-skill'].sha256;
173
+ writeFileSync(
174
+ join(TEST_DIR, "skills", "changing-skill", "SKILL.md"),
175
+ "# Updated\n",
176
+ "utf-8",
177
+ );
178
+ verifyAndRecordSkillHash("changing-skill");
179
+ const second = loadIntegrityManifest()["changing-skill"].sha256;
170
180
 
171
181
  expect(first).not.toBe(second);
172
182
  });
@@ -1,39 +1,43 @@
1
- import { describe, expect,test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
4
  formatConfirmationCommandPreview,
5
5
  formatConfirmationInputLines,
6
6
  sanitizeUrlForDisplay,
7
- } from '../cli.js';
7
+ } from "../cli.js";
8
8
 
9
- describe('sanitizeUrlForDisplay', () => {
10
- test('removes userinfo from absolute URLs', () => {
11
- const username = 'user';
12
- const credential = ['s', 'e', 'c', 'r', 'e', 't'].join('');
13
- const rawUrlObj = new URL('https://example.com/private');
9
+ describe("sanitizeUrlForDisplay", () => {
10
+ test("removes userinfo from absolute URLs", () => {
11
+ const username = "user";
12
+ const credential = ["s", "e", "c", "r", "e", "t"].join("");
13
+ const rawUrlObj = new URL("https://example.com/private");
14
14
  rawUrlObj.username = username;
15
15
  rawUrlObj.password = credential;
16
16
  const rawUrl = rawUrlObj.href;
17
17
 
18
- expect(sanitizeUrlForDisplay(rawUrl)).toBe('https://example.com/private');
18
+ expect(sanitizeUrlForDisplay(rawUrl)).toBe("https://example.com/private");
19
19
  });
20
20
 
21
- test('leaves URLs without userinfo unchanged', () => {
22
- expect(sanitizeUrlForDisplay('https://example.com/docs')).toBe('https://example.com/docs');
21
+ test("leaves URLs without userinfo unchanged", () => {
22
+ expect(sanitizeUrlForDisplay("https://example.com/docs")).toBe(
23
+ "https://example.com/docs",
24
+ );
23
25
  });
24
26
 
25
- test('redacts fallback //userinfo@ patterns when URL parsing fails', () => {
26
- const userinfo = ['u', 's', 'e', 'r', ':', 'p', 'w'].join('');
27
+ test("redacts fallback //userinfo@ patterns when URL parsing fails", () => {
28
+ const userinfo = ["u", "s", "e", "r", ":", "p", "w"].join("");
27
29
  const rawValue = `not-a-url //${userinfo}@example.com`;
28
30
 
29
- expect(sanitizeUrlForDisplay(rawValue)).toBe('not-a-url //[REDACTED]@example.com');
31
+ expect(sanitizeUrlForDisplay(rawValue)).toBe(
32
+ "not-a-url //[REDACTED]@example.com",
33
+ );
30
34
  });
31
35
  });
32
36
 
33
- describe('formatConfirmationInputLines', () => {
34
- test('preserves full old_string and new_string values without truncation', () => {
35
- const oldString = 'old '.repeat(120);
36
- const newString = 'new '.repeat(120);
37
+ describe("formatConfirmationInputLines", () => {
38
+ test("preserves full old_string and new_string values without truncation", () => {
39
+ const oldString = "old ".repeat(120);
40
+ const newString = "new ".repeat(120);
37
41
  const lines = formatConfirmationInputLines({
38
42
  old_string: oldString,
39
43
  new_string: newString,
@@ -41,28 +45,24 @@ describe('formatConfirmationInputLines', () => {
41
45
 
42
46
  expect(lines).toContain(`old_string: ${oldString}`);
43
47
  expect(lines).toContain(`new_string: ${newString}`);
44
- expect(lines.some((line) => line.includes('...'))).toBe(false);
48
+ expect(lines.some((line) => line.includes("..."))).toBe(false);
45
49
  });
46
50
 
47
- test('preserves multiline values', () => {
51
+ test("preserves multiline values", () => {
48
52
  const lines = formatConfirmationInputLines({
49
- old_string: 'line1\nline2\nline3',
53
+ old_string: "line1\nline2\nline3",
50
54
  });
51
55
 
52
- expect(lines).toEqual([
53
- 'old_string: line1',
54
- ' line2',
55
- ' line3',
56
- ]);
56
+ expect(lines).toEqual(["old_string: line1", " line2", " line3"]);
57
57
  });
58
58
  });
59
59
 
60
- describe('formatConfirmationCommandPreview', () => {
61
- test('shows concise file_edit preview', () => {
60
+ describe("formatConfirmationCommandPreview", () => {
61
+ test("shows concise file_edit preview", () => {
62
62
  const preview = formatConfirmationCommandPreview({
63
- toolName: 'file_edit',
64
- input: { path: '/tmp/sample.txt' },
63
+ toolName: "file_edit",
64
+ input: { path: "/tmp/sample.txt" },
65
65
  });
66
- expect(preview).toBe('edit /tmp/sample.txt');
66
+ expect(preview).toBe("edit /tmp/sample.txt");
67
67
  });
68
68
  });
@@ -1,81 +1,88 @@
1
- import { describe, expect,test } from 'bun:test';
1
+ import { describe, expect, test } from "bun:test";
2
2
 
3
- import { extractLastCodeBlock, formatSessionForExport } from '../util/clipboard.js';
3
+ import {
4
+ extractLastCodeBlock,
5
+ formatSessionForExport,
6
+ } from "../util/clipboard.js";
4
7
 
5
- describe('formatSessionForExport', () => {
6
- test('formats user and assistant messages', () => {
8
+ describe("formatSessionForExport", () => {
9
+ test("formats user and assistant messages", () => {
7
10
  const messages = [
8
- { role: 'user', text: 'Hello' },
9
- { role: 'assistant', text: 'Hi there!' },
11
+ { role: "user", text: "Hello" },
12
+ { role: "assistant", text: "Hi there!" },
10
13
  ];
11
- expect(formatSessionForExport(messages)).toBe('you> Hello\n\nassistant> Hi there!');
14
+ expect(formatSessionForExport(messages)).toBe(
15
+ "you> Hello\n\nassistant> Hi there!",
16
+ );
12
17
  });
13
18
 
14
- test('handles a single message', () => {
15
- const messages = [{ role: 'user', text: 'Just me' }];
16
- expect(formatSessionForExport(messages)).toBe('you> Just me');
19
+ test("handles a single message", () => {
20
+ const messages = [{ role: "user", text: "Just me" }];
21
+ expect(formatSessionForExport(messages)).toBe("you> Just me");
17
22
  });
18
23
 
19
- test('handles empty messages array', () => {
20
- expect(formatSessionForExport([])).toBe('');
24
+ test("handles empty messages array", () => {
25
+ expect(formatSessionForExport([])).toBe("");
21
26
  });
22
27
 
23
- test('preserves multiline message text', () => {
24
- const messages = [
25
- { role: 'assistant', text: 'Line 1\nLine 2\nLine 3' },
26
- ];
27
- expect(formatSessionForExport(messages)).toBe('assistant> Line 1\nLine 2\nLine 3');
28
+ test("preserves multiline message text", () => {
29
+ const messages = [{ role: "assistant", text: "Line 1\nLine 2\nLine 3" }];
30
+ expect(formatSessionForExport(messages)).toBe(
31
+ "assistant> Line 1\nLine 2\nLine 3",
32
+ );
28
33
  });
29
34
  });
30
35
 
31
- describe('extractLastCodeBlock', () => {
32
- test('extracts a simple code block', () => {
33
- const text = '```\nhello world\n```';
34
- expect(extractLastCodeBlock(text)).toBe('hello world');
36
+ describe("extractLastCodeBlock", () => {
37
+ test("extracts a simple code block", () => {
38
+ const text = "```\nhello world\n```";
39
+ expect(extractLastCodeBlock(text)).toBe("hello world");
35
40
  });
36
41
 
37
- test('extracts code block with language tag', () => {
38
- const text = '```typescript\nconst x = 1;\n```';
39
- expect(extractLastCodeBlock(text)).toBe('const x = 1;');
42
+ test("extracts code block with language tag", () => {
43
+ const text = "```typescript\nconst x = 1;\n```";
44
+ expect(extractLastCodeBlock(text)).toBe("const x = 1;");
40
45
  });
41
46
 
42
- test('returns the last code block when multiple exist', () => {
43
- const text = '```\nfirst\n```\nsome text\n```\nsecond\n```';
44
- expect(extractLastCodeBlock(text)).toBe('second');
47
+ test("returns the last code block when multiple exist", () => {
48
+ const text = "```\nfirst\n```\nsome text\n```\nsecond\n```";
49
+ expect(extractLastCodeBlock(text)).toBe("second");
45
50
  });
46
51
 
47
- test('handles empty code blocks', () => {
48
- const text = '```\n```';
49
- expect(extractLastCodeBlock(text)).toBe('');
52
+ test("handles empty code blocks", () => {
53
+ const text = "```\n```";
54
+ expect(extractLastCodeBlock(text)).toBe("");
50
55
  });
51
56
 
52
- test('handles empty code blocks with language tag', () => {
53
- const text = '```python\n```';
54
- expect(extractLastCodeBlock(text)).toBe('');
57
+ test("handles empty code blocks with language tag", () => {
58
+ const text = "```python\n```";
59
+ expect(extractLastCodeBlock(text)).toBe("");
55
60
  });
56
61
 
57
- test('does not match inline backticks as closing fence', () => {
62
+ test("does not match inline backticks as closing fence", () => {
58
63
  const text = '```\nconst s = "```"\n```';
59
64
  expect(extractLastCodeBlock(text)).toBe('const s = "```"');
60
65
  });
61
66
 
62
- test('handles multi-line code blocks', () => {
63
- const text = '```js\nfunction foo() {\n return 42;\n}\n```';
64
- expect(extractLastCodeBlock(text)).toBe('function foo() {\n return 42;\n}');
67
+ test("handles multi-line code blocks", () => {
68
+ const text = "```js\nfunction foo() {\n return 42;\n}\n```";
69
+ expect(extractLastCodeBlock(text)).toBe(
70
+ "function foo() {\n return 42;\n}",
71
+ );
65
72
  });
66
73
 
67
- test('returns null when no code blocks exist', () => {
68
- expect(extractLastCodeBlock('no code here')).toBeNull();
69
- expect(extractLastCodeBlock('`inline code`')).toBeNull();
74
+ test("returns null when no code blocks exist", () => {
75
+ expect(extractLastCodeBlock("no code here")).toBeNull();
76
+ expect(extractLastCodeBlock("`inline code`")).toBeNull();
70
77
  });
71
78
 
72
- test('extracts last block when separated by text', () => {
73
- const text = '```\nfirst\n```\nSome explanation\n```\nsecond\n```';
74
- expect(extractLastCodeBlock(text)).toBe('second');
79
+ test("extracts last block when separated by text", () => {
80
+ const text = "```\nfirst\n```\nSome explanation\n```\nsecond\n```";
81
+ expect(extractLastCodeBlock(text)).toBe("second");
75
82
  });
76
83
 
77
- test('handles non-empty block followed by empty block with text between', () => {
78
- const text = '```\nreal code\n```\nSome text\n```\n```';
79
- expect(extractLastCodeBlock(text)).toBe('');
84
+ test("handles non-empty block followed by empty block with text between", () => {
85
+ const text = "```\nreal code\n```\nSome text\n```\n```";
86
+ expect(extractLastCodeBlock(text)).toBe("");
80
87
  });
81
88
  });