@vellumai/assistant 0.3.0

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 (1068) hide show
  1. package/.dockerignore +27 -0
  2. package/.env.example +22 -0
  3. package/Dockerfile +99 -0
  4. package/Dockerfile.sandbox +5 -0
  5. package/README.md +248 -0
  6. package/bun.lock +1723 -0
  7. package/bunfig.toml +2 -0
  8. package/docs/skills.md +158 -0
  9. package/drizzle/0000_dizzy_maggott.sql +301 -0
  10. package/drizzle/meta/0000_snapshot.json +1999 -0
  11. package/drizzle/meta/_journal.json +13 -0
  12. package/drizzle.config.ts +7 -0
  13. package/eslint.config.mjs +17 -0
  14. package/hook-templates/debug-prompt-logger/hook.json +7 -0
  15. package/hook-templates/debug-prompt-logger/run.sh +68 -0
  16. package/knip.json +9 -0
  17. package/package.json +70 -0
  18. package/scripts/capture-x-graphql.ts +545 -0
  19. package/scripts/ipc/check-contract-inventory.ts +104 -0
  20. package/scripts/ipc/check-swift-decoder-drift.ts +166 -0
  21. package/scripts/ipc/generate-swift.ts +492 -0
  22. package/scripts/test-filesystem-tools.sh +48 -0
  23. package/scripts/test.sh +127 -0
  24. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2485 -0
  25. package/src/__tests__/account-registry.test.ts +245 -0
  26. package/src/__tests__/active-skill-tools.test.ts +378 -0
  27. package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
  28. package/src/__tests__/agent-loop-thinking.test.ts +81 -0
  29. package/src/__tests__/agent-loop.test.ts +1135 -0
  30. package/src/__tests__/anthropic-provider.test.ts +778 -0
  31. package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
  32. package/src/__tests__/app-bundler.test.ts +292 -0
  33. package/src/__tests__/app-executors.test.ts +613 -0
  34. package/src/__tests__/app-git-history.test.ts +176 -0
  35. package/src/__tests__/app-git-service.test.ts +169 -0
  36. package/src/__tests__/app-open-proxy.test.ts +62 -0
  37. package/src/__tests__/asset-materialize-tool.test.ts +452 -0
  38. package/src/__tests__/asset-search-tool.test.ts +477 -0
  39. package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
  40. package/src/__tests__/assistant-attachments.test.ts +437 -0
  41. package/src/__tests__/assistant-event-hub.test.ts +226 -0
  42. package/src/__tests__/assistant-event.test.ts +123 -0
  43. package/src/__tests__/assistant-events-sse-hardening.test.ts +315 -0
  44. package/src/__tests__/attachments-store.test.ts +476 -0
  45. package/src/__tests__/attachments.test.ts +134 -0
  46. package/src/__tests__/audit-log-rotation.test.ts +154 -0
  47. package/src/__tests__/browser-fill-credential.test.ts +309 -0
  48. package/src/__tests__/browser-manager.test.ts +203 -0
  49. package/src/__tests__/browser-runtime-check.test.ts +55 -0
  50. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +68 -0
  51. package/src/__tests__/browser-skill-endstate.test.ts +195 -0
  52. package/src/__tests__/bundle-scanner.test.ts +313 -0
  53. package/src/__tests__/call-bridge.test.ts +517 -0
  54. package/src/__tests__/call-constants.test.ts +40 -0
  55. package/src/__tests__/call-domain.test.ts +163 -0
  56. package/src/__tests__/call-orchestrator.test.ts +625 -0
  57. package/src/__tests__/call-recovery.test.ts +518 -0
  58. package/src/__tests__/call-routes-http.test.ts +699 -0
  59. package/src/__tests__/call-state-machine.test.ts +143 -0
  60. package/src/__tests__/call-state.test.ts +174 -0
  61. package/src/__tests__/call-store.test.ts +691 -0
  62. package/src/__tests__/channel-approval-routes.test.ts +2356 -0
  63. package/src/__tests__/channel-approval.test.ts +299 -0
  64. package/src/__tests__/channel-approvals.test.ts +521 -0
  65. package/src/__tests__/channel-delivery-store.test.ts +447 -0
  66. package/src/__tests__/channel-guardian.test.ts +1005 -0
  67. package/src/__tests__/checker.test.ts +3519 -0
  68. package/src/__tests__/clarification-resolver.test.ts +159 -0
  69. package/src/__tests__/classifier.test.ts +67 -0
  70. package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
  71. package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
  72. package/src/__tests__/cli-discover.test.ts +85 -0
  73. package/src/__tests__/cli.test.ts +26 -0
  74. package/src/__tests__/clipboard.test.ts +80 -0
  75. package/src/__tests__/commit-guarantee.test.ts +335 -0
  76. package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
  77. package/src/__tests__/compaction.benchmark.test.ts +176 -0
  78. package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
  79. package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
  80. package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
  81. package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
  82. package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
  83. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
  84. package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
  85. package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
  86. package/src/__tests__/computer-use-tools.test.ts +250 -0
  87. package/src/__tests__/config-schema.test.ts +1462 -0
  88. package/src/__tests__/conflict-intent-tokenization.test.ts +141 -0
  89. package/src/__tests__/conflict-policy.test.ts +121 -0
  90. package/src/__tests__/conflict-store.test.ts +332 -0
  91. package/src/__tests__/connection-policy.test.ts +102 -0
  92. package/src/__tests__/contacts-tools.test.ts +331 -0
  93. package/src/__tests__/context-memory-e2e.test.ts +434 -0
  94. package/src/__tests__/context-token-estimator.test.ts +135 -0
  95. package/src/__tests__/context-window-manager.test.ts +376 -0
  96. package/src/__tests__/contradiction-checker.test.ts +314 -0
  97. package/src/__tests__/conversation-store.test.ts +612 -0
  98. package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
  99. package/src/__tests__/credential-broker-server-use.test.ts +554 -0
  100. package/src/__tests__/credential-broker.test.ts +167 -0
  101. package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
  102. package/src/__tests__/credential-metadata-store.test.ts +779 -0
  103. package/src/__tests__/credential-policy-validate.test.ts +121 -0
  104. package/src/__tests__/credential-resolve.test.ts +328 -0
  105. package/src/__tests__/credential-security-e2e.test.ts +352 -0
  106. package/src/__tests__/credential-security-invariants.test.ts +583 -0
  107. package/src/__tests__/credential-selection.test.ts +354 -0
  108. package/src/__tests__/credential-vault-unit.test.ts +780 -0
  109. package/src/__tests__/credential-vault.test.ts +852 -0
  110. package/src/__tests__/daemon-assistant-events.test.ts +164 -0
  111. package/src/__tests__/daemon-server-session-init.test.ts +522 -0
  112. package/src/__tests__/date-context.test.ts +373 -0
  113. package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
  114. package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
  115. package/src/__tests__/diff.test.ts +121 -0
  116. package/src/__tests__/domain-normalize.test.ts +112 -0
  117. package/src/__tests__/domain-policy.test.ts +124 -0
  118. package/src/__tests__/doordash-client.test.ts +186 -0
  119. package/src/__tests__/doordash-session.test.ts +152 -0
  120. package/src/__tests__/dynamic-page-surface.test.ts +91 -0
  121. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
  122. package/src/__tests__/edit-engine.test.ts +180 -0
  123. package/src/__tests__/elevenlabs-client.test.ts +271 -0
  124. package/src/__tests__/email-cli.test.ts +283 -0
  125. package/src/__tests__/encrypted-store.test.ts +332 -0
  126. package/src/__tests__/entity-extractor.test.ts +190 -0
  127. package/src/__tests__/ephemeral-permissions.test.ts +362 -0
  128. package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
  129. package/src/__tests__/event-bus.test.ts +222 -0
  130. package/src/__tests__/file-edit-tool.test.ts +122 -0
  131. package/src/__tests__/file-ops-service.test.ts +330 -0
  132. package/src/__tests__/file-read-tool.test.ts +75 -0
  133. package/src/__tests__/file-write-tool.test.ts +113 -0
  134. package/src/__tests__/filesystem-tools.test.ts +579 -0
  135. package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
  136. package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
  137. package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
  138. package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
  139. package/src/__tests__/followup-tools.test.ts +303 -0
  140. package/src/__tests__/forbidden-legacy-symbols.test.ts +71 -0
  141. package/src/__tests__/fuzzy-match-property.test.ts +216 -0
  142. package/src/__tests__/fuzzy-match.test.ts +138 -0
  143. package/src/__tests__/gateway-only-enforcement.test.ts +631 -0
  144. package/src/__tests__/gemini-image-service.test.ts +261 -0
  145. package/src/__tests__/gemini-provider.test.ts +651 -0
  146. package/src/__tests__/get-weather.test.ts +318 -0
  147. package/src/__tests__/gmail-integration.test.ts +73 -0
  148. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +202 -0
  149. package/src/__tests__/handlers-cu-observation-blob.test.ts +352 -0
  150. package/src/__tests__/handlers-ipc-blob-probe.test.ts +191 -0
  151. package/src/__tests__/handlers-slack-config.test.ts +200 -0
  152. package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
  153. package/src/__tests__/handlers-telegram-config.test.ts +968 -0
  154. package/src/__tests__/handlers-twilio-config.test.ts +659 -0
  155. package/src/__tests__/handlers-twitter-config.test.ts +858 -0
  156. package/src/__tests__/headless-browser-interactions.test.ts +536 -0
  157. package/src/__tests__/headless-browser-navigate.test.ts +211 -0
  158. package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
  159. package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
  160. package/src/__tests__/history-repair-observability.test.ts +56 -0
  161. package/src/__tests__/history-repair.test.ts +510 -0
  162. package/src/__tests__/home-base-bootstrap.test.ts +82 -0
  163. package/src/__tests__/hooks-blocking.test.ts +128 -0
  164. package/src/__tests__/hooks-cli.test.ts +144 -0
  165. package/src/__tests__/hooks-config.test.ts +93 -0
  166. package/src/__tests__/hooks-discovery.test.ts +199 -0
  167. package/src/__tests__/hooks-integration.test.ts +189 -0
  168. package/src/__tests__/hooks-manager.test.ts +187 -0
  169. package/src/__tests__/hooks-runner.test.ts +182 -0
  170. package/src/__tests__/hooks-settings.test.ts +154 -0
  171. package/src/__tests__/hooks-templates.test.ts +137 -0
  172. package/src/__tests__/hooks-ts-runner.test.ts +125 -0
  173. package/src/__tests__/hooks-watch.test.ts +100 -0
  174. package/src/__tests__/host-file-edit-tool.test.ts +228 -0
  175. package/src/__tests__/host-file-read-tool.test.ts +123 -0
  176. package/src/__tests__/host-file-write-tool.test.ts +136 -0
  177. package/src/__tests__/host-shell-tool.test.ts +562 -0
  178. package/src/__tests__/ingress-reconcile.test.ts +581 -0
  179. package/src/__tests__/ingress-url-consistency.test.ts +214 -0
  180. package/src/__tests__/intent-routing.test.ts +259 -0
  181. package/src/__tests__/ipc-blob-store.test.ts +315 -0
  182. package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
  183. package/src/__tests__/ipc-contract.test.ts +74 -0
  184. package/src/__tests__/ipc-protocol.test.ts +113 -0
  185. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
  186. package/src/__tests__/ipc-snapshot.test.ts +1769 -0
  187. package/src/__tests__/ipc-validate.test.ts +407 -0
  188. package/src/__tests__/key-migration.test.ts +206 -0
  189. package/src/__tests__/keychain.test.ts +258 -0
  190. package/src/__tests__/llm-usage-store.test.ts +221 -0
  191. package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
  192. package/src/__tests__/managed-store.test.ts +608 -0
  193. package/src/__tests__/media-generate-image.test.ts +238 -0
  194. package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
  195. package/src/__tests__/media-visibility-policy.test.ts +141 -0
  196. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +235 -0
  197. package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
  198. package/src/__tests__/memory-query-builder.test.ts +59 -0
  199. package/src/__tests__/memory-recall-quality.test.ts +846 -0
  200. package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
  201. package/src/__tests__/memory-regressions.test.ts +4435 -0
  202. package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
  203. package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
  204. package/src/__tests__/migration-cli-flows.test.ts +169 -0
  205. package/src/__tests__/migration-ordering.test.ts +249 -0
  206. package/src/__tests__/mock-signup-server.test.ts +528 -0
  207. package/src/__tests__/oauth-callback-registry.test.ts +92 -0
  208. package/src/__tests__/oauth2-gateway-transport.test.ts +285 -0
  209. package/src/__tests__/onboarding-starter-tasks.test.ts +176 -0
  210. package/src/__tests__/onboarding-template-contract.test.ts +58 -0
  211. package/src/__tests__/openai-provider.test.ts +753 -0
  212. package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
  213. package/src/__tests__/parser.test.ts +472 -0
  214. package/src/__tests__/path-classifier.test.ts +73 -0
  215. package/src/__tests__/path-policy.test.ts +435 -0
  216. package/src/__tests__/platform-move-helper.test.ts +99 -0
  217. package/src/__tests__/platform-socket-path.test.ts +52 -0
  218. package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
  219. package/src/__tests__/platform.test.ts +131 -0
  220. package/src/__tests__/playbook-execution.test.ts +502 -0
  221. package/src/__tests__/playbook-tools.test.ts +340 -0
  222. package/src/__tests__/prebuilt-home-base-seed.test.ts +75 -0
  223. package/src/__tests__/pricing.test.ts +256 -0
  224. package/src/__tests__/profile-compiler.test.ts +374 -0
  225. package/src/__tests__/provider-commit-message-generator.test.ts +342 -0
  226. package/src/__tests__/provider-registry-ollama.test.ts +16 -0
  227. package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
  228. package/src/__tests__/proxy-approval-callback.test.ts +601 -0
  229. package/src/__tests__/public-ingress-urls.test.ts +256 -0
  230. package/src/__tests__/qdrant-manager.test.ts +267 -0
  231. package/src/__tests__/ratelimit.test.ts +297 -0
  232. package/src/__tests__/recurrence-engine-rruleset.test.ts +175 -0
  233. package/src/__tests__/recurrence-engine.test.ts +78 -0
  234. package/src/__tests__/recurrence-types.test.ts +79 -0
  235. package/src/__tests__/registry.test.ts +494 -0
  236. package/src/__tests__/relay-server.test.ts +688 -0
  237. package/src/__tests__/reminder-store.test.ts +223 -0
  238. package/src/__tests__/reminder.test.ts +229 -0
  239. package/src/__tests__/request-file-tool.test.ts +158 -0
  240. package/src/__tests__/run-orchestrator-assistant-events.test.ts +227 -0
  241. package/src/__tests__/run-orchestrator.test.ts +425 -0
  242. package/src/__tests__/runtime-attachment-metadata.test.ts +189 -0
  243. package/src/__tests__/runtime-events-sse-parity.test.ts +343 -0
  244. package/src/__tests__/runtime-events-sse.test.ts +162 -0
  245. package/src/__tests__/runtime-runs-http.test.ts +438 -0
  246. package/src/__tests__/runtime-runs.test.ts +260 -0
  247. package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
  248. package/src/__tests__/sandbox-host-parity.test.ts +950 -0
  249. package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
  250. package/src/__tests__/schedule-store.test.ts +484 -0
  251. package/src/__tests__/schedule-tools.test.ts +783 -0
  252. package/src/__tests__/scheduler-recurrence.test.ts +430 -0
  253. package/src/__tests__/script-proxy-certs.test.ts +90 -0
  254. package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
  255. package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
  256. package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
  257. package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
  258. package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
  259. package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
  260. package/src/__tests__/script-proxy-policy.test.ts +310 -0
  261. package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
  262. package/src/__tests__/script-proxy-router.test.ts +180 -0
  263. package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
  264. package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
  265. package/src/__tests__/secret-allowlist.test.ts +230 -0
  266. package/src/__tests__/secret-ingress-handler.test.ts +110 -0
  267. package/src/__tests__/secret-onetime-send.test.ts +130 -0
  268. package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
  269. package/src/__tests__/secret-response-routing.test.ts +93 -0
  270. package/src/__tests__/secret-scanner-executor.test.ts +348 -0
  271. package/src/__tests__/secret-scanner.test.ts +900 -0
  272. package/src/__tests__/secure-keys.test.ts +323 -0
  273. package/src/__tests__/server-history-render.test.ts +431 -0
  274. package/src/__tests__/session-abort-tool-results.test.ts +240 -0
  275. package/src/__tests__/session-conflict-gate.test.ts +1136 -0
  276. package/src/__tests__/session-error.test.ts +369 -0
  277. package/src/__tests__/session-evictor.test.ts +188 -0
  278. package/src/__tests__/session-init.benchmark.test.ts +465 -0
  279. package/src/__tests__/session-load-history-repair.test.ts +222 -0
  280. package/src/__tests__/session-pre-run-repair.test.ts +213 -0
  281. package/src/__tests__/session-process-bridge.test.ts +242 -0
  282. package/src/__tests__/session-profile-injection.test.ts +444 -0
  283. package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
  284. package/src/__tests__/session-queue.test.ts +1535 -0
  285. package/src/__tests__/session-runtime-assembly.test.ts +476 -0
  286. package/src/__tests__/session-runtime-workspace.test.ts +183 -0
  287. package/src/__tests__/session-skill-tools.test.ts +2431 -0
  288. package/src/__tests__/session-slash-known.test.ts +368 -0
  289. package/src/__tests__/session-slash-queue.test.ts +288 -0
  290. package/src/__tests__/session-slash-unknown.test.ts +271 -0
  291. package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
  292. package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
  293. package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
  294. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
  295. package/src/__tests__/session-undo.test.ts +75 -0
  296. package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
  297. package/src/__tests__/session-workspace-injection.test.ts +327 -0
  298. package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
  299. package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
  300. package/src/__tests__/shell-credential-ref.test.ts +187 -0
  301. package/src/__tests__/shell-identity.test.ts +256 -0
  302. package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
  303. package/src/__tests__/shell-parser-property.test.ts +433 -0
  304. package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
  305. package/src/__tests__/signup-e2e.test.ts +353 -0
  306. package/src/__tests__/size-guard.test.ts +117 -0
  307. package/src/__tests__/skill-include-graph.test.ts +303 -0
  308. package/src/__tests__/skill-load-tool.test.ts +409 -0
  309. package/src/__tests__/skill-projection.benchmark.test.ts +338 -0
  310. package/src/__tests__/skill-script-runner-host.test.ts +489 -0
  311. package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
  312. package/src/__tests__/skill-script-runner.test.ts +159 -0
  313. package/src/__tests__/skill-tool-factory.test.ts +252 -0
  314. package/src/__tests__/skill-tool-manifest.test.ts +658 -0
  315. package/src/__tests__/skill-version-hash.test.ts +182 -0
  316. package/src/__tests__/skills.test.ts +680 -0
  317. package/src/__tests__/slash-commands-catalog.test.ts +86 -0
  318. package/src/__tests__/slash-commands-parser.test.ts +119 -0
  319. package/src/__tests__/slash-commands-resolver.test.ts +193 -0
  320. package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
  321. package/src/__tests__/speaker-identification.test.ts +52 -0
  322. package/src/__tests__/starter-bundle.test.ts +136 -0
  323. package/src/__tests__/starter-task-flow.test.ts +143 -0
  324. package/src/__tests__/subagent-manager-notify.test.ts +404 -0
  325. package/src/__tests__/subagent-tools.test.ts +801 -0
  326. package/src/__tests__/subagent-types.test.ts +78 -0
  327. package/src/__tests__/swarm-orchestrator.test.ts +428 -0
  328. package/src/__tests__/swarm-plan-validator.test.ts +330 -0
  329. package/src/__tests__/swarm-recursion.test.ts +165 -0
  330. package/src/__tests__/swarm-router-planner.test.ts +208 -0
  331. package/src/__tests__/swarm-session-integration.test.ts +274 -0
  332. package/src/__tests__/swarm-tool.test.ts +145 -0
  333. package/src/__tests__/swarm-worker-backend.test.ts +129 -0
  334. package/src/__tests__/swarm-worker-runner.test.ts +272 -0
  335. package/src/__tests__/system-prompt.test.ts +439 -0
  336. package/src/__tests__/task-compiler.test.ts +284 -0
  337. package/src/__tests__/task-management-tools.test.ts +936 -0
  338. package/src/__tests__/task-runner.test.ts +216 -0
  339. package/src/__tests__/task-scheduler.test.ts +217 -0
  340. package/src/__tests__/task-tools.test.ts +595 -0
  341. package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
  342. package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
  343. package/src/__tests__/terminal-sandbox.test.ts +202 -0
  344. package/src/__tests__/terminal-tools.test.ts +840 -0
  345. package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
  346. package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
  347. package/src/__tests__/tool-audit-listener.test.ts +113 -0
  348. package/src/__tests__/tool-domain-event-publisher.test.ts +253 -0
  349. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
  350. package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
  351. package/src/__tests__/tool-executor-redaction.test.ts +289 -0
  352. package/src/__tests__/tool-executor-shell-integration.test.ts +301 -0
  353. package/src/__tests__/tool-executor.test.ts +1989 -0
  354. package/src/__tests__/tool-metrics-listener.test.ts +225 -0
  355. package/src/__tests__/tool-notification-listener.test.ts +49 -0
  356. package/src/__tests__/tool-permission-simulate-handler.test.ts +336 -0
  357. package/src/__tests__/tool-policy.test.ts +54 -0
  358. package/src/__tests__/tool-profiling-listener.test.ts +268 -0
  359. package/src/__tests__/tool-result-truncation.test.ts +217 -0
  360. package/src/__tests__/tool-trace-listener.test.ts +226 -0
  361. package/src/__tests__/top-level-renderer.test.ts +121 -0
  362. package/src/__tests__/top-level-scanner.test.ts +141 -0
  363. package/src/__tests__/trace-emitter.test.ts +173 -0
  364. package/src/__tests__/trust-store.test.ts +1605 -0
  365. package/src/__tests__/turn-commit.test.ts +554 -0
  366. package/src/__tests__/twilio-provider.test.ts +329 -0
  367. package/src/__tests__/twilio-routes-elevenlabs.test.ts +375 -0
  368. package/src/__tests__/twilio-routes-twiml.test.ts +127 -0
  369. package/src/__tests__/twilio-routes.test.ts +577 -0
  370. package/src/__tests__/twitter-auth-handler.test.ts +667 -0
  371. package/src/__tests__/twitter-cli-error-shaping.test.ts +208 -0
  372. package/src/__tests__/twitter-cli-routing.test.ts +252 -0
  373. package/src/__tests__/twitter-oauth-client.test.ts +209 -0
  374. package/src/__tests__/url-safety.test.ts +418 -0
  375. package/src/__tests__/view-image-tool.test.ts +217 -0
  376. package/src/__tests__/weather-skill-regression.test.ts +225 -0
  377. package/src/__tests__/web-fetch.test.ts +869 -0
  378. package/src/__tests__/web-search.test.ts +584 -0
  379. package/src/__tests__/workspace-git-service.test.ts +1153 -0
  380. package/src/__tests__/workspace-heartbeat-service.test.ts +486 -0
  381. package/src/__tests__/workspace-lifecycle.test.ts +292 -0
  382. package/src/__tests__/workspace-policy.test.ts +213 -0
  383. package/src/agent/attachments.ts +35 -0
  384. package/src/agent/loop.ts +500 -0
  385. package/src/agent/message-types.ts +17 -0
  386. package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
  387. package/src/autonomy/autonomy-resolver.ts +60 -0
  388. package/src/autonomy/autonomy-store.ts +122 -0
  389. package/src/autonomy/disposition-mapper.ts +31 -0
  390. package/src/autonomy/index.ts +11 -0
  391. package/src/autonomy/types.ts +39 -0
  392. package/src/bundler/app-bundler.ts +295 -0
  393. package/src/bundler/bundle-scanner.ts +535 -0
  394. package/src/bundler/bundle-signer.ts +124 -0
  395. package/src/bundler/manifest.ts +21 -0
  396. package/src/bundler/signature-verifier.ts +184 -0
  397. package/src/calls/call-bridge.ts +168 -0
  398. package/src/calls/call-constants.ts +48 -0
  399. package/src/calls/call-domain.ts +430 -0
  400. package/src/calls/call-orchestrator.ts +498 -0
  401. package/src/calls/call-recovery.ts +207 -0
  402. package/src/calls/call-state-machine.ts +68 -0
  403. package/src/calls/call-state.ts +87 -0
  404. package/src/calls/call-store.ts +422 -0
  405. package/src/calls/elevenlabs-client.ts +97 -0
  406. package/src/calls/elevenlabs-config.ts +31 -0
  407. package/src/calls/relay-server.ts +390 -0
  408. package/src/calls/speaker-identification.ts +213 -0
  409. package/src/calls/twilio-config.ts +45 -0
  410. package/src/calls/twilio-provider.ts +263 -0
  411. package/src/calls/twilio-rest.ts +156 -0
  412. package/src/calls/twilio-routes.ts +311 -0
  413. package/src/calls/types.ts +39 -0
  414. package/src/calls/voice-provider.ts +14 -0
  415. package/src/calls/voice-quality.ts +114 -0
  416. package/src/cli/autonomy.ts +188 -0
  417. package/src/cli/config-commands.ts +334 -0
  418. package/src/cli/contacts.ts +149 -0
  419. package/src/cli/core-commands.ts +784 -0
  420. package/src/cli/doordash.ts +1055 -0
  421. package/src/cli/email-guardrails.ts +200 -0
  422. package/src/cli/email.ts +405 -0
  423. package/src/cli/ipc-client.ts +82 -0
  424. package/src/cli/main-screen.tsx +53 -0
  425. package/src/cli/map.ts +270 -0
  426. package/src/cli/twitter.ts +754 -0
  427. package/src/cli.ts +918 -0
  428. package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
  429. package/src/commands/cc-command-registry.ts +209 -0
  430. package/src/config/bundled-skills/.gitkeep +0 -0
  431. package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
  432. package/src/config/bundled-skills/agentmail/icon.svg +21 -0
  433. package/src/config/bundled-skills/app-builder/SKILL.md +1404 -0
  434. package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
  435. package/src/config/bundled-skills/app-builder/icon.svg +9 -0
  436. package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
  437. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
  438. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
  439. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
  440. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
  441. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
  442. package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
  443. package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
  444. package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
  445. package/src/config/bundled-skills/browser/SKILL.md +28 -0
  446. package/src/config/bundled-skills/browser/TOOLS.json +234 -0
  447. package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
  448. package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
  449. package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
  450. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
  451. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
  452. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
  453. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
  454. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
  455. package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
  456. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
  457. package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
  458. package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
  459. package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
  460. package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
  461. package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
  462. package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
  463. package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
  464. package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
  465. package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
  466. package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
  467. package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
  468. package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
  469. package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
  470. package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
  471. package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
  472. package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
  473. package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
  474. package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
  475. package/src/config/bundled-skills/contacts/SKILL.md +39 -0
  476. package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
  477. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +57 -0
  478. package/src/config/bundled-skills/contacts/tools/contact-search.ts +60 -0
  479. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +66 -0
  480. package/src/config/bundled-skills/document/SKILL.md +26 -0
  481. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  482. package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
  483. package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
  484. package/src/config/bundled-skills/doordash/SKILL.md +163 -0
  485. package/src/config/bundled-skills/followups/SKILL.md +32 -0
  486. package/src/config/bundled-skills/followups/TOOLS.json +100 -0
  487. package/src/config/bundled-skills/followups/icon.svg +24 -0
  488. package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
  489. package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
  490. package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
  491. package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
  492. package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
  493. package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
  494. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
  495. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
  496. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
  497. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
  498. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
  499. package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
  500. package/src/config/bundled-skills/google-calendar/types.ts +97 -0
  501. package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
  502. package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
  503. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +115 -0
  504. package/src/config/bundled-skills/macos-automation/SKILL.md +66 -0
  505. package/src/config/bundled-skills/messaging/SKILL.md +153 -0
  506. package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
  507. package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
  508. package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
  509. package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
  510. package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
  511. package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
  512. package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
  513. package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
  514. package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
  515. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +125 -0
  516. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
  517. package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
  518. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
  519. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
  520. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
  521. package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +32 -0
  522. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
  523. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +31 -0
  524. package/src/config/bundled-skills/messaging/tools/shared.ts +76 -0
  525. package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
  526. package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
  527. package/src/config/bundled-skills/phone-calls/SKILL.md +533 -0
  528. package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
  529. package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
  530. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +98 -0
  531. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +54 -0
  532. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +76 -0
  533. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +113 -0
  534. package/src/config/bundled-skills/public-ingress/SKILL.md +200 -0
  535. package/src/config/bundled-skills/reminder/SKILL.md +20 -0
  536. package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
  537. package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
  538. package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
  539. package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
  540. package/src/config/bundled-skills/schedule/SKILL.md +74 -0
  541. package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
  542. package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
  543. package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
  544. package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
  545. package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
  546. package/src/config/bundled-skills/self-upgrade/SKILL.md +68 -0
  547. package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
  548. package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
  549. package/src/config/bundled-skills/subagent/SKILL.md +25 -0
  550. package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
  551. package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
  552. package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
  553. package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
  554. package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
  555. package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
  556. package/src/config/bundled-skills/tasks/SKILL.md +28 -0
  557. package/src/config/bundled-skills/tasks/TOOLS.json +281 -0
  558. package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
  559. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
  560. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
  561. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
  562. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
  563. package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
  564. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +9 -0
  565. package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
  566. package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
  567. package/src/config/bundled-skills/transcribe/SKILL.md +25 -0
  568. package/src/config/bundled-skills/transcribe/TOOLS.json +32 -0
  569. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +370 -0
  570. package/src/config/bundled-skills/twitter/SKILL.md +220 -0
  571. package/src/config/bundled-skills/watcher/SKILL.md +27 -0
  572. package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
  573. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
  574. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
  575. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
  576. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
  577. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
  578. package/src/config/bundled-skills/weather/SKILL.md +37 -0
  579. package/src/config/bundled-skills/weather/TOOLS.json +32 -0
  580. package/src/config/bundled-skills/weather/icon.svg +24 -0
  581. package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
  582. package/src/config/computer-use-prompt.ts +97 -0
  583. package/src/config/defaults.ts +263 -0
  584. package/src/config/loader.ts +339 -0
  585. package/src/config/schema.ts +1436 -0
  586. package/src/config/skill-state.ts +95 -0
  587. package/src/config/skills.ts +972 -0
  588. package/src/config/system-prompt.ts +675 -0
  589. package/src/config/templates/BOOTSTRAP.md +70 -0
  590. package/src/config/templates/IDENTITY.md +25 -0
  591. package/src/config/templates/LOOKS.md +25 -0
  592. package/src/config/templates/SOUL.md +37 -0
  593. package/src/config/templates/USER.md +19 -0
  594. package/src/config/types.ts +42 -0
  595. package/src/config/vellum-skills/chatgpt-import/SKILL.md +24 -0
  596. package/src/config/vellum-skills/chatgpt-import/TOOLS.json +23 -0
  597. package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +284 -0
  598. package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
  599. package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
  600. package/src/config/vellum-skills/google-oauth-setup/SKILL.md +199 -0
  601. package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +153 -0
  602. package/src/config/vellum-skills/telegram-setup/SKILL.md +143 -0
  603. package/src/config/vellum-skills/twilio-setup/SKILL.md +213 -0
  604. package/src/contacts/contact-store.ts +410 -0
  605. package/src/contacts/index.ts +11 -0
  606. package/src/contacts/types.ts +28 -0
  607. package/src/context/token-estimator.ts +108 -0
  608. package/src/context/tool-result-truncation.ts +128 -0
  609. package/src/context/window-manager.ts +531 -0
  610. package/src/daemon/assistant-attachments.ts +691 -0
  611. package/src/daemon/classifier.ts +110 -0
  612. package/src/daemon/computer-use-session.ts +903 -0
  613. package/src/daemon/connection-policy.ts +41 -0
  614. package/src/daemon/date-context.ts +136 -0
  615. package/src/daemon/handlers/apps.ts +530 -0
  616. package/src/daemon/handlers/browser.ts +54 -0
  617. package/src/daemon/handlers/computer-use.ts +187 -0
  618. package/src/daemon/handlers/config.ts +1517 -0
  619. package/src/daemon/handlers/diagnostics.ts +338 -0
  620. package/src/daemon/handlers/documents.ts +173 -0
  621. package/src/daemon/handlers/home-base.ts +78 -0
  622. package/src/daemon/handlers/identity.ts +127 -0
  623. package/src/daemon/handlers/index.ts +129 -0
  624. package/src/daemon/handlers/misc.ts +331 -0
  625. package/src/daemon/handlers/open-bundle-handler.ts +80 -0
  626. package/src/daemon/handlers/publish.ts +187 -0
  627. package/src/daemon/handlers/sessions.ts +555 -0
  628. package/src/daemon/handlers/shared.ts +570 -0
  629. package/src/daemon/handlers/signing.ts +37 -0
  630. package/src/daemon/handlers/skills.ts +486 -0
  631. package/src/daemon/handlers/subagents.ts +210 -0
  632. package/src/daemon/handlers/twitter-auth.ts +198 -0
  633. package/src/daemon/handlers/work-items.ts +632 -0
  634. package/src/daemon/handlers/workspace-files.ts +75 -0
  635. package/src/daemon/handlers.ts +17 -0
  636. package/src/daemon/history-repair.ts +214 -0
  637. package/src/daemon/ipc-blob-store.ts +231 -0
  638. package/src/daemon/ipc-contract-inventory.json +495 -0
  639. package/src/daemon/ipc-contract-inventory.ts +126 -0
  640. package/src/daemon/ipc-contract.ts +2551 -0
  641. package/src/daemon/ipc-protocol.ts +75 -0
  642. package/src/daemon/ipc-validate.ts +188 -0
  643. package/src/daemon/lifecycle.ts +582 -0
  644. package/src/daemon/main.ts +21 -0
  645. package/src/daemon/media-visibility-policy.ts +57 -0
  646. package/src/daemon/ride-shotgun-handler.ts +309 -0
  647. package/src/daemon/server.ts +1215 -0
  648. package/src/daemon/session-agent-loop.ts +922 -0
  649. package/src/daemon/session-attachments.ts +196 -0
  650. package/src/daemon/session-conflict-gate.ts +184 -0
  651. package/src/daemon/session-dynamic-profile.ts +63 -0
  652. package/src/daemon/session-error.ts +290 -0
  653. package/src/daemon/session-evictor.ts +196 -0
  654. package/src/daemon/session-history.ts +437 -0
  655. package/src/daemon/session-lifecycle.ts +147 -0
  656. package/src/daemon/session-media-retry.ts +147 -0
  657. package/src/daemon/session-memory.ts +212 -0
  658. package/src/daemon/session-messaging.ts +145 -0
  659. package/src/daemon/session-notifiers.ts +193 -0
  660. package/src/daemon/session-process.ts +323 -0
  661. package/src/daemon/session-queue-manager.ts +82 -0
  662. package/src/daemon/session-runtime-assembly.ts +447 -0
  663. package/src/daemon/session-skill-tools.ts +356 -0
  664. package/src/daemon/session-slash.ts +305 -0
  665. package/src/daemon/session-surfaces.ts +702 -0
  666. package/src/daemon/session-tool-setup.ts +523 -0
  667. package/src/daemon/session-usage.ts +72 -0
  668. package/src/daemon/session-workspace.ts +19 -0
  669. package/src/daemon/session.ts +400 -0
  670. package/src/daemon/tls-certs.ts +189 -0
  671. package/src/daemon/trace-emitter.ts +82 -0
  672. package/src/daemon/video-thumbnail.ts +62 -0
  673. package/src/daemon/watch-handler.ts +274 -0
  674. package/src/doordash/client.ts +999 -0
  675. package/src/doordash/queries.ts +1311 -0
  676. package/src/doordash/query-extractor.ts +93 -0
  677. package/src/doordash/session.ts +82 -0
  678. package/src/email/provider.ts +117 -0
  679. package/src/email/providers/agentmail.ts +317 -0
  680. package/src/email/providers/index.ts +58 -0
  681. package/src/email/service.ts +303 -0
  682. package/src/email/types.ts +126 -0
  683. package/src/events/bus.ts +157 -0
  684. package/src/events/domain-events.ts +83 -0
  685. package/src/events/index.ts +18 -0
  686. package/src/events/tool-audit-listener.ts +80 -0
  687. package/src/events/tool-domain-event-publisher.ts +111 -0
  688. package/src/events/tool-metrics-listener.ts +159 -0
  689. package/src/events/tool-notification-listener.ts +17 -0
  690. package/src/events/tool-profiling-listener.ts +158 -0
  691. package/src/events/tool-trace-listener.ts +75 -0
  692. package/src/export/formatter.ts +98 -0
  693. package/src/followups/followup-store.ts +168 -0
  694. package/src/followups/index.ts +10 -0
  695. package/src/followups/types.ts +29 -0
  696. package/src/gallery/default-gallery.ts +795 -0
  697. package/src/gallery/gallery-manifest.ts +24 -0
  698. package/src/home-base/app-link-store.ts +82 -0
  699. package/src/home-base/bootstrap.ts +68 -0
  700. package/src/home-base/prebuilt/index.html +662 -0
  701. package/src/home-base/prebuilt/seed-metadata.json +21 -0
  702. package/src/home-base/prebuilt/seed.ts +112 -0
  703. package/src/home-base/prebuilt-home-base-updater.ts +30 -0
  704. package/src/hooks/cli.ts +163 -0
  705. package/src/hooks/config.ts +88 -0
  706. package/src/hooks/discovery.ts +110 -0
  707. package/src/hooks/manager.ts +124 -0
  708. package/src/hooks/runner.ts +123 -0
  709. package/src/hooks/templates.ts +52 -0
  710. package/src/hooks/types.ts +72 -0
  711. package/src/inbound/public-ingress-urls.ts +123 -0
  712. package/src/index.ts +81 -0
  713. package/src/instrument.ts +60 -0
  714. package/src/logfire.ts +99 -0
  715. package/src/media/gemini-image-service.ts +136 -0
  716. package/src/memory/account-store.ts +108 -0
  717. package/src/memory/admin.ts +211 -0
  718. package/src/memory/app-git-service.ts +295 -0
  719. package/src/memory/app-store.ts +577 -0
  720. package/src/memory/attachments-store.ts +397 -0
  721. package/src/memory/channel-delivery-store.ts +353 -0
  722. package/src/memory/channel-guardian-store.ts +669 -0
  723. package/src/memory/checkpoints.ts +52 -0
  724. package/src/memory/clarification-resolver.ts +298 -0
  725. package/src/memory/conflict-intent.ts +157 -0
  726. package/src/memory/conflict-policy.ts +73 -0
  727. package/src/memory/conflict-store.ts +350 -0
  728. package/src/memory/contradiction-checker.ts +358 -0
  729. package/src/memory/conversation-key-store.ts +122 -0
  730. package/src/memory/conversation-store.ts +470 -0
  731. package/src/memory/db.ts +1991 -0
  732. package/src/memory/embedding-backend.ts +229 -0
  733. package/src/memory/embedding-gemini.ts +52 -0
  734. package/src/memory/embedding-local.ts +65 -0
  735. package/src/memory/embedding-ollama.ts +55 -0
  736. package/src/memory/embedding-openai.ts +25 -0
  737. package/src/memory/entity-extractor.ts +474 -0
  738. package/src/memory/external-conversation-store.ts +234 -0
  739. package/src/memory/fingerprint.ts +20 -0
  740. package/src/memory/indexer.ts +156 -0
  741. package/src/memory/items-extractor.ts +461 -0
  742. package/src/memory/job-handlers/backfill.ts +139 -0
  743. package/src/memory/job-handlers/cleanup.ts +58 -0
  744. package/src/memory/job-handlers/conflict.ts +141 -0
  745. package/src/memory/job-handlers/embedding.ts +61 -0
  746. package/src/memory/job-handlers/extraction.ts +123 -0
  747. package/src/memory/job-handlers/index-maintenance.ts +54 -0
  748. package/src/memory/job-handlers/summarization.ts +286 -0
  749. package/src/memory/job-utils.ts +170 -0
  750. package/src/memory/jobs-store.ts +401 -0
  751. package/src/memory/jobs-worker.ts +313 -0
  752. package/src/memory/llm-request-log-store.ts +45 -0
  753. package/src/memory/llm-usage-store.ts +60 -0
  754. package/src/memory/message-content.ts +54 -0
  755. package/src/memory/profile-compiler.ts +160 -0
  756. package/src/memory/published-pages-store.ts +137 -0
  757. package/src/memory/qdrant-client.ts +366 -0
  758. package/src/memory/qdrant-manager.ts +242 -0
  759. package/src/memory/query-builder.ts +45 -0
  760. package/src/memory/retrieval-budget.ts +30 -0
  761. package/src/memory/retriever.ts +653 -0
  762. package/src/memory/runs-store.ts +305 -0
  763. package/src/memory/schema.ts +677 -0
  764. package/src/memory/search/entity.ts +298 -0
  765. package/src/memory/search/formatting.ts +207 -0
  766. package/src/memory/search/lexical.ts +227 -0
  767. package/src/memory/search/ranking.ts +401 -0
  768. package/src/memory/search/semantic.ts +121 -0
  769. package/src/memory/search/types.ts +137 -0
  770. package/src/memory/segmenter.ts +68 -0
  771. package/src/memory/shared-app-links-store.ts +138 -0
  772. package/src/memory/tool-usage-store.ts +62 -0
  773. package/src/messaging/activity-analyzer.ts +76 -0
  774. package/src/messaging/draft-store.ts +88 -0
  775. package/src/messaging/index.ts +3 -0
  776. package/src/messaging/provider-types.ts +80 -0
  777. package/src/messaging/provider.ts +52 -0
  778. package/src/messaging/providers/gmail/adapter.ts +193 -0
  779. package/src/messaging/providers/gmail/client.ts +204 -0
  780. package/src/messaging/providers/gmail/types.ts +90 -0
  781. package/src/messaging/providers/slack/adapter.ts +202 -0
  782. package/src/messaging/providers/slack/client.ts +198 -0
  783. package/src/messaging/providers/slack/types.ts +119 -0
  784. package/src/messaging/providers/telegram-bot/adapter.ts +162 -0
  785. package/src/messaging/providers/telegram-bot/client.ts +104 -0
  786. package/src/messaging/providers/telegram-bot/types.ts +15 -0
  787. package/src/messaging/registry.ts +35 -0
  788. package/src/messaging/style-analyzer.ts +159 -0
  789. package/src/messaging/thread-summarizer.ts +306 -0
  790. package/src/messaging/triage-engine.ts +323 -0
  791. package/src/messaging/types.ts +55 -0
  792. package/src/permissions/checker.ts +640 -0
  793. package/src/permissions/defaults.ts +254 -0
  794. package/src/permissions/prompter.ts +98 -0
  795. package/src/permissions/secret-prompter.ts +114 -0
  796. package/src/permissions/shell-identity.ts +227 -0
  797. package/src/permissions/trust-store.ts +607 -0
  798. package/src/permissions/types.ts +43 -0
  799. package/src/permissions/workspace-policy.ts +114 -0
  800. package/src/playbooks/index.ts +2 -0
  801. package/src/playbooks/playbook-compiler.ts +90 -0
  802. package/src/playbooks/types.ts +55 -0
  803. package/src/providers/anthropic/client.ts +751 -0
  804. package/src/providers/failover.ts +129 -0
  805. package/src/providers/fireworks/client.ts +20 -0
  806. package/src/providers/gemini/client.ts +285 -0
  807. package/src/providers/ollama/client.ts +30 -0
  808. package/src/providers/openai/client.ts +337 -0
  809. package/src/providers/openrouter/client.ts +20 -0
  810. package/src/providers/ratelimit.ts +93 -0
  811. package/src/providers/registry.ts +146 -0
  812. package/src/providers/retry.ts +81 -0
  813. package/src/providers/stream-timeout.ts +38 -0
  814. package/src/providers/types.ts +109 -0
  815. package/src/runtime/assistant-event-hub.ts +157 -0
  816. package/src/runtime/assistant-event.ts +82 -0
  817. package/src/runtime/channel-approval-parser.ts +60 -0
  818. package/src/runtime/channel-approval-types.ts +73 -0
  819. package/src/runtime/channel-approvals.ts +206 -0
  820. package/src/runtime/channel-guardian-service.ts +212 -0
  821. package/src/runtime/gateway-client.ts +58 -0
  822. package/src/runtime/http-server.ts +1076 -0
  823. package/src/runtime/http-types.ts +66 -0
  824. package/src/runtime/routes/app-routes.ts +174 -0
  825. package/src/runtime/routes/attachment-routes.ts +133 -0
  826. package/src/runtime/routes/call-routes.ts +190 -0
  827. package/src/runtime/routes/channel-routes.ts +1404 -0
  828. package/src/runtime/routes/conversation-routes.ts +352 -0
  829. package/src/runtime/routes/events-routes.ts +148 -0
  830. package/src/runtime/routes/run-routes.ts +257 -0
  831. package/src/runtime/routes/secret-routes.ts +76 -0
  832. package/src/runtime/run-orchestrator.ts +330 -0
  833. package/src/schedule/recurrence-engine.ts +162 -0
  834. package/src/schedule/recurrence-types.ts +67 -0
  835. package/src/schedule/schedule-store.ts +506 -0
  836. package/src/schedule/scheduler.ts +171 -0
  837. package/src/security/encrypted-store.ts +238 -0
  838. package/src/security/keychain.ts +252 -0
  839. package/src/security/oauth-callback-registry.ts +66 -0
  840. package/src/security/oauth2.ts +274 -0
  841. package/src/security/redaction.ts +89 -0
  842. package/src/security/secret-allowlist.ts +164 -0
  843. package/src/security/secret-ingress.ts +57 -0
  844. package/src/security/secret-scanner.ts +550 -0
  845. package/src/security/secure-keys.ts +180 -0
  846. package/src/security/token-manager.ts +141 -0
  847. package/src/services/published-app-updater.ts +69 -0
  848. package/src/services/vercel-deploy.ts +73 -0
  849. package/src/skills/active-skill-tools.ts +81 -0
  850. package/src/skills/clawhub.ts +414 -0
  851. package/src/skills/include-graph.ts +146 -0
  852. package/src/skills/managed-store.ts +233 -0
  853. package/src/skills/path-classifier.ts +128 -0
  854. package/src/skills/slash-commands.ts +174 -0
  855. package/src/skills/tool-manifest.ts +165 -0
  856. package/src/skills/version-hash.ts +110 -0
  857. package/src/slack/slack-webhook.ts +61 -0
  858. package/src/subagent/index.ts +19 -0
  859. package/src/subagent/manager.ts +511 -0
  860. package/src/subagent/types.ts +69 -0
  861. package/src/swarm/backend-claude-code.ts +145 -0
  862. package/src/swarm/index.ts +44 -0
  863. package/src/swarm/limits.ts +37 -0
  864. package/src/swarm/orchestrator.ts +279 -0
  865. package/src/swarm/plan-validator.ts +151 -0
  866. package/src/swarm/router-planner.ts +100 -0
  867. package/src/swarm/router-prompts.ts +36 -0
  868. package/src/swarm/synthesizer.ts +62 -0
  869. package/src/swarm/types.ts +62 -0
  870. package/src/swarm/worker-backend.ts +121 -0
  871. package/src/swarm/worker-prompts.ts +79 -0
  872. package/src/swarm/worker-runner.ts +164 -0
  873. package/src/tasks/SPEC.md +139 -0
  874. package/src/tasks/candidate-store.ts +86 -0
  875. package/src/tasks/ephemeral-permissions.ts +48 -0
  876. package/src/tasks/task-compiler.ts +199 -0
  877. package/src/tasks/task-runner.ts +90 -0
  878. package/src/tasks/task-scheduler.ts +21 -0
  879. package/src/tasks/task-store.ts +127 -0
  880. package/src/tasks/tool-sanitizer.ts +36 -0
  881. package/src/tools/apps/definitions.ts +59 -0
  882. package/src/tools/apps/executors.ts +313 -0
  883. package/src/tools/apps/open-proxy.ts +43 -0
  884. package/src/tools/apps/registry.ts +16 -0
  885. package/src/tools/assets/materialize.ts +218 -0
  886. package/src/tools/assets/search.ts +361 -0
  887. package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
  888. package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
  889. package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
  890. package/src/tools/browser/api-map.ts +293 -0
  891. package/src/tools/browser/auth-cache.ts +149 -0
  892. package/src/tools/browser/auth-detector.ts +347 -0
  893. package/src/tools/browser/auto-navigate.ts +270 -0
  894. package/src/tools/browser/browser-execution.ts +980 -0
  895. package/src/tools/browser/browser-handoff.ts +79 -0
  896. package/src/tools/browser/browser-manager.ts +715 -0
  897. package/src/tools/browser/browser-screencast.ts +217 -0
  898. package/src/tools/browser/headless-browser.ts +450 -0
  899. package/src/tools/browser/jit-auth.ts +51 -0
  900. package/src/tools/browser/network-recorder.ts +349 -0
  901. package/src/tools/browser/network-recording-types.ts +49 -0
  902. package/src/tools/browser/recording-store.ts +49 -0
  903. package/src/tools/browser/runtime-check.ts +43 -0
  904. package/src/tools/browser/x-auto-navigate.ts +207 -0
  905. package/src/tools/calls/call-end.ts +67 -0
  906. package/src/tools/calls/call-start.ts +81 -0
  907. package/src/tools/calls/call-status.ts +81 -0
  908. package/src/tools/claude-code/claude-code.ts +428 -0
  909. package/src/tools/computer-use/definitions.ts +443 -0
  910. package/src/tools/computer-use/registry.ts +22 -0
  911. package/src/tools/computer-use/request-computer-control.ts +53 -0
  912. package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
  913. package/src/tools/credentials/account-registry.ts +127 -0
  914. package/src/tools/credentials/broker-types.ts +107 -0
  915. package/src/tools/credentials/broker.ts +372 -0
  916. package/src/tools/credentials/domain-policy.ts +51 -0
  917. package/src/tools/credentials/host-pattern-match.ts +60 -0
  918. package/src/tools/credentials/metadata-store.ts +335 -0
  919. package/src/tools/credentials/policy-types.ts +52 -0
  920. package/src/tools/credentials/policy-validate.ts +80 -0
  921. package/src/tools/credentials/resolve.ts +122 -0
  922. package/src/tools/credentials/selection.ts +159 -0
  923. package/src/tools/credentials/tool-policy.ts +25 -0
  924. package/src/tools/credentials/vault.ts +657 -0
  925. package/src/tools/document/document-tool.ts +92 -0
  926. package/src/tools/document/editor-template.ts +237 -0
  927. package/src/tools/execution-target.ts +21 -0
  928. package/src/tools/execution-timeout.ts +49 -0
  929. package/src/tools/executor.ts +815 -0
  930. package/src/tools/filesystem/edit.ts +127 -0
  931. package/src/tools/filesystem/fuzzy-match.ts +202 -0
  932. package/src/tools/filesystem/read.ts +71 -0
  933. package/src/tools/filesystem/view-image.ts +199 -0
  934. package/src/tools/filesystem/write.ts +79 -0
  935. package/src/tools/followups/followup_create.ts +76 -0
  936. package/src/tools/followups/followup_list.ts +60 -0
  937. package/src/tools/followups/followup_resolve.ts +56 -0
  938. package/src/tools/host-filesystem/edit.ts +125 -0
  939. package/src/tools/host-filesystem/read.ts +80 -0
  940. package/src/tools/host-filesystem/write.ts +76 -0
  941. package/src/tools/host-terminal/cli-discover.ts +180 -0
  942. package/src/tools/host-terminal/host-shell.ts +191 -0
  943. package/src/tools/memory/definitions.ts +69 -0
  944. package/src/tools/memory/handlers.ts +246 -0
  945. package/src/tools/memory/register.ts +66 -0
  946. package/src/tools/network/__tests__/web-search.test.ts +427 -0
  947. package/src/tools/network/domain-normalize.ts +85 -0
  948. package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
  949. package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
  950. package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
  951. package/src/tools/network/script-proxy/certs.ts +237 -0
  952. package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
  953. package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
  954. package/src/tools/network/script-proxy/index.ts +28 -0
  955. package/src/tools/network/script-proxy/logging.ts +196 -0
  956. package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
  957. package/src/tools/network/script-proxy/policy.ts +152 -0
  958. package/src/tools/network/script-proxy/router.ts +60 -0
  959. package/src/tools/network/script-proxy/server.ts +136 -0
  960. package/src/tools/network/script-proxy/session-manager.ts +534 -0
  961. package/src/tools/network/script-proxy/types.ts +125 -0
  962. package/src/tools/network/url-safety.ts +227 -0
  963. package/src/tools/network/web-fetch.ts +713 -0
  964. package/src/tools/network/web-search.ts +296 -0
  965. package/src/tools/policy-context.ts +29 -0
  966. package/src/tools/registry.ts +295 -0
  967. package/src/tools/reminder/reminder-store.ts +148 -0
  968. package/src/tools/reminder/reminder.ts +80 -0
  969. package/src/tools/schedule/create.ts +81 -0
  970. package/src/tools/schedule/delete.ts +28 -0
  971. package/src/tools/schedule/list.ts +69 -0
  972. package/src/tools/schedule/update.ts +97 -0
  973. package/src/tools/shared/filesystem/edit-engine.ts +56 -0
  974. package/src/tools/shared/filesystem/errors.ts +85 -0
  975. package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
  976. package/src/tools/shared/filesystem/format-diff.ts +35 -0
  977. package/src/tools/shared/filesystem/path-policy.ts +125 -0
  978. package/src/tools/shared/filesystem/size-guard.ts +41 -0
  979. package/src/tools/shared/filesystem/types.ts +80 -0
  980. package/src/tools/shared/shell-output.ts +52 -0
  981. package/src/tools/skills/delete-managed.ts +60 -0
  982. package/src/tools/skills/load.ts +139 -0
  983. package/src/tools/skills/sandbox-runner.ts +279 -0
  984. package/src/tools/skills/scaffold-managed.ts +150 -0
  985. package/src/tools/skills/script-contract.ts +6 -0
  986. package/src/tools/skills/skill-script-runner.ts +86 -0
  987. package/src/tools/skills/skill-tool-factory.ts +64 -0
  988. package/src/tools/skills/vellum-catalog.ts +217 -0
  989. package/src/tools/subagent/abort.ts +33 -0
  990. package/src/tools/subagent/message.ts +39 -0
  991. package/src/tools/subagent/read.ts +67 -0
  992. package/src/tools/subagent/spawn.ts +46 -0
  993. package/src/tools/subagent/status.ts +45 -0
  994. package/src/tools/swarm/delegate.ts +183 -0
  995. package/src/tools/system/request-permission.ts +98 -0
  996. package/src/tools/system/version.ts +43 -0
  997. package/src/tools/tasks/index.ts +27 -0
  998. package/src/tools/tasks/task-delete.ts +82 -0
  999. package/src/tools/tasks/task-list.ts +44 -0
  1000. package/src/tools/tasks/task-run.ts +97 -0
  1001. package/src/tools/tasks/task-save.ts +47 -0
  1002. package/src/tools/tasks/work-item-enqueue.ts +234 -0
  1003. package/src/tools/tasks/work-item-list.ts +55 -0
  1004. package/src/tools/tasks/work-item-remove.ts +60 -0
  1005. package/src/tools/tasks/work-item-run.ts +78 -0
  1006. package/src/tools/tasks/work-item-update.ts +114 -0
  1007. package/src/tools/terminal/backends/docker.ts +372 -0
  1008. package/src/tools/terminal/backends/native.ts +190 -0
  1009. package/src/tools/terminal/backends/types.ts +26 -0
  1010. package/src/tools/terminal/evaluate-typescript.ts +275 -0
  1011. package/src/tools/terminal/parser.ts +413 -0
  1012. package/src/tools/terminal/safe-env.ts +37 -0
  1013. package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
  1014. package/src/tools/terminal/sandbox.ts +44 -0
  1015. package/src/tools/terminal/shell.ts +257 -0
  1016. package/src/tools/tool-manifest.ts +198 -0
  1017. package/src/tools/types.ts +176 -0
  1018. package/src/tools/ui-surface/definitions.ts +244 -0
  1019. package/src/tools/ui-surface/registry.ts +14 -0
  1020. package/src/tools/watch/screen-watch.ts +130 -0
  1021. package/src/tools/watch/watch-state.ts +119 -0
  1022. package/src/tools/watcher/create.ts +64 -0
  1023. package/src/tools/watcher/delete.ts +27 -0
  1024. package/src/tools/watcher/digest.ts +50 -0
  1025. package/src/tools/watcher/list.ts +60 -0
  1026. package/src/tools/watcher/update.ts +56 -0
  1027. package/src/tools/weather/service.ts +551 -0
  1028. package/src/twitter/client.ts +690 -0
  1029. package/src/twitter/oauth-client.ts +102 -0
  1030. package/src/twitter/router.ts +101 -0
  1031. package/src/twitter/session.ts +91 -0
  1032. package/src/usage/actors.ts +24 -0
  1033. package/src/usage/types.ts +37 -0
  1034. package/src/util/clipboard.ts +33 -0
  1035. package/src/util/content-id.ts +16 -0
  1036. package/src/util/debounce.ts +88 -0
  1037. package/src/util/diff.ts +181 -0
  1038. package/src/util/errors.ts +129 -0
  1039. package/src/util/logger.ts +243 -0
  1040. package/src/util/network-info.ts +47 -0
  1041. package/src/util/platform.ts +632 -0
  1042. package/src/util/pricing.ts +150 -0
  1043. package/src/util/promise-guard.ts +37 -0
  1044. package/src/util/retry.ts +98 -0
  1045. package/src/util/spinner.ts +51 -0
  1046. package/src/util/time.ts +16 -0
  1047. package/src/util/truncate.ts +6 -0
  1048. package/src/util/xml.ts +4 -0
  1049. package/src/version.ts +3 -0
  1050. package/src/watcher/constants.ts +11 -0
  1051. package/src/watcher/engine.ts +199 -0
  1052. package/src/watcher/provider-registry.ts +15 -0
  1053. package/src/watcher/provider-types.ts +48 -0
  1054. package/src/watcher/providers/gmail.ts +198 -0
  1055. package/src/watcher/providers/google-calendar.ts +228 -0
  1056. package/src/watcher/providers/slack.ts +129 -0
  1057. package/src/watcher/watcher-store.ts +419 -0
  1058. package/src/work-items/work-item-runner.ts +171 -0
  1059. package/src/work-items/work-item-store.ts +325 -0
  1060. package/src/workspace/commit-message-enrichment-service.ts +284 -0
  1061. package/src/workspace/commit-message-provider.ts +95 -0
  1062. package/src/workspace/git-service.ts +857 -0
  1063. package/src/workspace/heartbeat-service.ts +345 -0
  1064. package/src/workspace/provider-commit-message-generator.ts +285 -0
  1065. package/src/workspace/top-level-renderer.ts +19 -0
  1066. package/src/workspace/top-level-scanner.ts +41 -0
  1067. package/src/workspace/turn-commit.ts +175 -0
  1068. package/tsconfig.json +21 -0
@@ -0,0 +1,900 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import {
3
+ scanText,
4
+ redactSecrets,
5
+ shannonEntropy,
6
+ _isPlaceholder,
7
+ _redact,
8
+ _hasSecretContext,
9
+ type SecretMatch,
10
+ } from '../security/secret-scanner.js';
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Helper: assert a single match of the expected type
14
+ // ---------------------------------------------------------------------------
15
+ function expectMatch(text: string, expectedType: string): SecretMatch {
16
+ const matches = scanText(text);
17
+ const found = matches.find((m) => m.type === expectedType);
18
+ expect(found).toBeDefined();
19
+ return found!;
20
+ }
21
+
22
+ function expectNoMatch(text: string): void {
23
+ const matches = scanText(text);
24
+ expect(matches).toHaveLength(0);
25
+ }
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // AWS
29
+ // ---------------------------------------------------------------------------
30
+ describe('AWS keys', () => {
31
+ test('detects AWS access key ID', () => {
32
+ expectMatch('aws_access_key_id = AKIAIOSFODNN7REALKEY', 'AWS Access Key');
33
+ });
34
+
35
+ test('does not flag the AWS example key', () => {
36
+ const matches = scanText('AKIAIOSFODNN7EXAMPLE');
37
+ const aws = matches.filter((m) => m.type === 'AWS Access Key');
38
+ expect(aws).toHaveLength(0);
39
+ });
40
+
41
+ test('detects AWS secret key after separator', () => {
42
+ // Exactly 40 base-64 chars with mixed case and / (distinguishes from hex)
43
+ const secret = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYRE+LK3Yzab';
44
+ expect(secret.length).toBe(40);
45
+ expectMatch(
46
+ `aws_secret_access_key = "${secret}"`,
47
+ 'AWS Secret Key',
48
+ );
49
+ });
50
+
51
+ test('does not flag AWS example secret key', () => {
52
+ const matches = scanText(
53
+ 'secret = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"',
54
+ );
55
+ const aws = matches.filter((m) => m.type === 'AWS Secret Key');
56
+ expect(aws).toHaveLength(0);
57
+ });
58
+ });
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // GitHub
62
+ // ---------------------------------------------------------------------------
63
+ describe('GitHub tokens', () => {
64
+ test('detects ghp_ personal access token', () => {
65
+ expectMatch(
66
+ `token=ghp_${'A'.repeat(36)}`,
67
+ 'GitHub Token',
68
+ );
69
+ });
70
+
71
+ test('detects gho_ OAuth token', () => {
72
+ expectMatch(
73
+ `gho_${'B'.repeat(36)}`,
74
+ 'GitHub Token',
75
+ );
76
+ });
77
+
78
+ test('detects fine-grained PAT', () => {
79
+ expectMatch(
80
+ `github_pat_${'C'.repeat(30)}`,
81
+ 'GitHub Fine-Grained PAT',
82
+ );
83
+ });
84
+ });
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // GitLab
88
+ // ---------------------------------------------------------------------------
89
+ describe('GitLab tokens', () => {
90
+ test('detects glpat- token', () => {
91
+ expectMatch('glpat-abcDEF1234567890abcde', 'GitLab Token');
92
+ });
93
+ });
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Stripe
97
+ // ---------------------------------------------------------------------------
98
+ describe('Stripe keys', () => {
99
+ test('detects live secret key', () => {
100
+ expectMatch(`sk_live_${'a'.repeat(24)}`, 'Stripe Secret Key');
101
+ });
102
+
103
+ test('detects live restricted key', () => {
104
+ expectMatch(`rk_live_${'b'.repeat(24)}`, 'Stripe Restricted Key');
105
+ });
106
+
107
+ test('does not flag test keys', () => {
108
+ const matches = scanText(`sk_test_${'c'.repeat(24)}`);
109
+ const stripe = matches.filter((m) => m.type === 'Stripe Secret Key');
110
+ expect(stripe).toHaveLength(0);
111
+ });
112
+ });
113
+
114
+ // ---------------------------------------------------------------------------
115
+ // Slack
116
+ // ---------------------------------------------------------------------------
117
+ describe('Slack tokens', () => {
118
+ test('detects bot token', () => {
119
+ expectMatch(
120
+ 'xoxb-1234567890-1234567890-aBcDeFgHiJkLmNoPqRsTuVwX',
121
+ 'Slack Bot Token',
122
+ );
123
+ });
124
+
125
+ test('detects webhook URL', () => {
126
+ expectMatch(
127
+ 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX',
128
+ 'Slack Webhook',
129
+ );
130
+ });
131
+ });
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Telegram
135
+ // ---------------------------------------------------------------------------
136
+ describe('Telegram bot tokens', () => {
137
+ // Build test token at runtime to avoid tripping pre-commit secret hook
138
+ const BOT_TOKEN = ['123456789', ':', 'ABCDefGHIJklmnopQRSTuvwxyz012345678'].join('');
139
+
140
+ test('detects Telegram bot token', () => {
141
+ expectMatch(`token=${BOT_TOKEN}`, 'Telegram Bot Token');
142
+ });
143
+
144
+ test('detects bot token in surrounding text', () => {
145
+ expectMatch(`My bot token is ${BOT_TOKEN} please save it`, 'Telegram Bot Token');
146
+ });
147
+
148
+ test('detects bot token ending with hyphen', () => {
149
+ // ~1.5% of valid tokens end with '-'; trailing \b would miss these
150
+ const tokenEndingHyphen = ['123456789', ':', 'ABCDefGHIJklmnopQRSTuvwxyz01234567-'].join('');
151
+ expectMatch(`token=${tokenEndingHyphen}`, 'Telegram Bot Token');
152
+ });
153
+
154
+ test('does not flag short numeric:alpha strings', () => {
155
+ // Too few digits in bot ID (only 5)
156
+ const matches = scanText('12345:ABCDefGHIJklmnopQRSTuvwxyz012345678');
157
+ const telegram = matches.filter((m) => m.type === 'Telegram Bot Token');
158
+ expect(telegram).toHaveLength(0);
159
+ });
160
+
161
+ test('does not flag token with wrong secret length', () => {
162
+ // Secret part is only 10 chars (needs 35)
163
+ const matches = scanText('123456789:ABCDefGHIJ');
164
+ const telegram = matches.filter((m) => m.type === 'Telegram Bot Token');
165
+ expect(telegram).toHaveLength(0);
166
+ });
167
+
168
+ test('does not flag token with too-long secret part', () => {
169
+ // Secret part is 40 chars (needs exactly 35)
170
+ const matches = scanText('123456789:ABCDefGHIJklmnopQRSTuvwxyz0123456789AB');
171
+ const telegram = matches.filter((m) => m.type === 'Telegram Bot Token');
172
+ expect(telegram).toHaveLength(0);
173
+ });
174
+ });
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Anthropic
178
+ // ---------------------------------------------------------------------------
179
+ describe('Anthropic keys', () => {
180
+ test('detects sk-ant- key', () => {
181
+ expectMatch(`sk-ant-${'a'.repeat(80)}`, 'Anthropic API Key');
182
+ });
183
+ });
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // OpenAI
187
+ // ---------------------------------------------------------------------------
188
+ describe('OpenAI keys', () => {
189
+ test('detects sk-proj- key', () => {
190
+ expectMatch(`sk-proj-${'a'.repeat(40)}`, 'OpenAI Project Key');
191
+ });
192
+
193
+ test('detects classic OpenAI key format', () => {
194
+ expectMatch(
195
+ `sk-${'a'.repeat(20)}T3BlbkFJ${'b'.repeat(20)}`,
196
+ 'OpenAI API Key',
197
+ );
198
+ });
199
+ });
200
+
201
+ // ---------------------------------------------------------------------------
202
+ // Google
203
+ // ---------------------------------------------------------------------------
204
+ describe('Google keys', () => {
205
+ test('detects AIza key', () => {
206
+ // AIza + exactly 35 alphanumeric/dash/underscore chars
207
+ const key = 'AIza' + 'SyA1bcDefGHijklMnoPQRStuvWXyz012345';
208
+ expect(key.slice(4).length).toBe(35);
209
+ expectMatch(key, 'Google API Key');
210
+ });
211
+
212
+ test('detects GOCSPX- client secret', () => {
213
+ // GOCSPX- + exactly 28 chars
214
+ const key = 'GOCSPX-' + 'aBcDeFgHiJkLmNoPqRsTuVwXy123';
215
+ expect(key.slice(7).length).toBe(28);
216
+ expectMatch(key, 'Google OAuth Client Secret');
217
+ });
218
+ });
219
+
220
+ // ---------------------------------------------------------------------------
221
+ // Twilio
222
+ // ---------------------------------------------------------------------------
223
+ describe('Twilio keys', () => {
224
+ test('detects SK key', () => {
225
+ expectMatch(`SK${'a'.repeat(32)}`, 'Twilio API Key');
226
+ });
227
+ });
228
+
229
+ // ---------------------------------------------------------------------------
230
+ // SendGrid
231
+ // ---------------------------------------------------------------------------
232
+ describe('SendGrid keys', () => {
233
+ test('detects SG. key', () => {
234
+ expectMatch(
235
+ `SG.${'a'.repeat(22)}.${'b'.repeat(43)}`,
236
+ 'SendGrid API Key',
237
+ );
238
+ });
239
+ });
240
+
241
+ // ---------------------------------------------------------------------------
242
+ // Mailgun
243
+ // ---------------------------------------------------------------------------
244
+ describe('Mailgun keys', () => {
245
+ test('detects key- format', () => {
246
+ expectMatch(`key-${'c'.repeat(32)}`, 'Mailgun API Key');
247
+ });
248
+ });
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // npm
252
+ // ---------------------------------------------------------------------------
253
+ describe('npm tokens', () => {
254
+ test('detects npm_ token', () => {
255
+ expectMatch(`npm_${'d'.repeat(36)}`, 'npm Token');
256
+ });
257
+ });
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // PyPI
261
+ // ---------------------------------------------------------------------------
262
+ describe('PyPI tokens', () => {
263
+ test('detects pypi- token', () => {
264
+ expectMatch(`pypi-${'e'.repeat(50)}`, 'PyPI API Token');
265
+ });
266
+ });
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // Private keys
270
+ // ---------------------------------------------------------------------------
271
+ describe('private keys', () => {
272
+ test('detects RSA private key header', () => {
273
+ expectMatch(
274
+ '-----BEGIN RSA PRIVATE KEY-----\nMIIE...',
275
+ 'Private Key',
276
+ );
277
+ });
278
+
279
+ test('detects generic private key header', () => {
280
+ expectMatch(
281
+ '-----BEGIN PRIVATE KEY-----\nMIIE...',
282
+ 'Private Key',
283
+ );
284
+ });
285
+
286
+ test('detects EC private key header', () => {
287
+ expectMatch(
288
+ '-----BEGIN EC PRIVATE KEY-----\nMIIE...',
289
+ 'Private Key',
290
+ );
291
+ });
292
+
293
+ test('detects OPENSSH private key header', () => {
294
+ expectMatch(
295
+ '-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNz...',
296
+ 'Private Key',
297
+ );
298
+ });
299
+ });
300
+
301
+ // ---------------------------------------------------------------------------
302
+ // JWT
303
+ // ---------------------------------------------------------------------------
304
+ describe('JSON Web Tokens', () => {
305
+ test('detects JWT', () => {
306
+ // A structurally valid JWT (base64url-encoded header.payload.signature)
307
+ const header = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9';
308
+ const payload = 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ';
309
+ const signature = 'SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
310
+ expectMatch(`${header}.${payload}.${signature}`, 'JSON Web Token');
311
+ });
312
+ });
313
+
314
+ // ---------------------------------------------------------------------------
315
+ // Connection strings
316
+ // ---------------------------------------------------------------------------
317
+ describe('connection strings', () => {
318
+ test('detects postgres connection string', () => {
319
+ expectMatch(
320
+ 'postgres://user:secret@db.example.com:5432/mydb',
321
+ 'Database Connection String',
322
+ );
323
+ });
324
+
325
+ test('detects mongodb+srv connection string', () => {
326
+ expectMatch(
327
+ 'mongodb+srv://user:password@cluster.mongodb.net/db',
328
+ 'Database Connection String',
329
+ );
330
+ });
331
+
332
+ test('detects redis connection string', () => {
333
+ expectMatch(
334
+ 'redis://default:password@redis.example.com:6379',
335
+ 'Database Connection String',
336
+ );
337
+ });
338
+
339
+ test('detects mysql connection string', () => {
340
+ expectMatch(
341
+ 'mysql://root:secret@localhost:3306/app',
342
+ 'Database Connection String',
343
+ );
344
+ });
345
+ });
346
+
347
+ // ---------------------------------------------------------------------------
348
+ // Generic secret assignment
349
+ // ---------------------------------------------------------------------------
350
+ describe('generic secret assignments', () => {
351
+ test('detects password = "value"', () => {
352
+ expectMatch(
353
+ 'password = "SuperSecret123!"',
354
+ 'Generic Secret Assignment',
355
+ );
356
+ });
357
+
358
+ test('detects api_key: "value"', () => {
359
+ expectMatch(
360
+ "api_key: 'my-real-api-key-value'",
361
+ 'Generic Secret Assignment',
362
+ );
363
+ });
364
+
365
+ test('detects SECRET=value in quotes', () => {
366
+ expectMatch(
367
+ 'SECRET="a-very-long-secret-value"',
368
+ 'Generic Secret Assignment',
369
+ );
370
+ });
371
+
372
+ test('ignores short values (< 8 chars)', () => {
373
+ // "short" is only 5 chars, should not match generic pattern
374
+ const matches = scanText('password = "short"');
375
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
376
+ expect(generic).toHaveLength(0);
377
+ });
378
+ });
379
+
380
+ // ---------------------------------------------------------------------------
381
+ // Placeholder / false-positive suppression
382
+ // ---------------------------------------------------------------------------
383
+ describe('placeholder detection', () => {
384
+ test('suppresses known placeholder values', () => {
385
+ expectNoMatch('password = "changeme"');
386
+ expectNoMatch('password = "password"');
387
+ expectNoMatch('password = "xxxxxxxx"');
388
+ });
389
+
390
+ test('suppresses test-prefixed keys', () => {
391
+ expectNoMatch(`sk_test_${'a'.repeat(24)}`);
392
+ expectNoMatch(`pk_test_${'b'.repeat(24)}`);
393
+ });
394
+
395
+ test('suppresses values containing example/placeholder/dummy', () => {
396
+ expectNoMatch('token = "my-example-api-key-value"');
397
+ expectNoMatch('key = "this-is-a-placeholder-string"');
398
+ expectNoMatch('secret = "dummy-value-for-testing"');
399
+ });
400
+
401
+ test('suppresses all-same-character strings', () => {
402
+ expectNoMatch('password = "aaaaaaaa"');
403
+ });
404
+
405
+ test('isPlaceholder returns true for known values', () => {
406
+ expect(_isPlaceholder('AKIAIOSFODNN7EXAMPLE')).toBe(true);
407
+ expect(_isPlaceholder('your-api-key-here')).toBe(true);
408
+ expect(_isPlaceholder('changeme')).toBe(true);
409
+ });
410
+
411
+ test('isPlaceholder returns false for real-looking values', () => {
412
+ expect(_isPlaceholder('wJalrXUtnFEMI/K7MDENG/bPxRfiCYREALKEY')).toBe(false);
413
+ expect(_isPlaceholder('sk_live_abcdefghij1234567890abcd')).toBe(false);
414
+ });
415
+ });
416
+
417
+ // ---------------------------------------------------------------------------
418
+ // Redaction
419
+ // ---------------------------------------------------------------------------
420
+ describe('redaction', () => {
421
+ test('redact masks the middle of a string', () => {
422
+ const result = _redact('AKIAIOSFODNN7REALKEY');
423
+ // Should show first few + last few with stars in between
424
+ expect(result).toContain('*');
425
+ expect(result.length).toBeLessThanOrEqual(30);
426
+ // First chars visible
427
+ expect(result.startsWith('AKIA')).toBe(false); // only ~15% visible
428
+ expect(result.startsWith('AK')).toBe(true);
429
+ });
430
+
431
+ test('redact handles short strings', () => {
432
+ expect(_redact('short')).toBe('***');
433
+ });
434
+
435
+ test('redactSecrets replaces secrets in text', () => {
436
+ const input = `export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7REALKEY`;
437
+ const result = redactSecrets(input);
438
+ expect(result).toContain('<redacted type="AWS Access Key" />');
439
+ expect(result).not.toContain('AKIAIOSFODNN7REALKEY');
440
+ });
441
+
442
+ test('redactSecrets preserves text without secrets', () => {
443
+ const input = 'Hello world, this is safe text.';
444
+ expect(redactSecrets(input)).toBe(input);
445
+ });
446
+
447
+ test('redactSecrets handles multiple secrets', () => {
448
+ const input = `
449
+ AWS_KEY=AKIAIOSFODNN7REALKEY
450
+ TOKEN=ghp_${'A'.repeat(36)}
451
+ `;
452
+ const result = redactSecrets(input);
453
+ expect(result).toContain('<redacted type="AWS Access Key" />');
454
+ expect(result).toContain('<redacted type="GitHub Token" />');
455
+ });
456
+ });
457
+
458
+ // ---------------------------------------------------------------------------
459
+ // scanText behavior
460
+ // ---------------------------------------------------------------------------
461
+ describe('scanText', () => {
462
+ test('returns empty array for safe text', () => {
463
+ expect(scanText('just normal text with no secrets')).toHaveLength(0);
464
+ });
465
+
466
+ test('returns matches sorted by position', () => {
467
+ const input = `second=ghp_${'A'.repeat(36)} first=AKIAIOSFODNN7REALKEY`;
468
+ const matches = scanText(input);
469
+ expect(matches.length).toBeGreaterThanOrEqual(2);
470
+ for (let i = 1; i < matches.length; i++) {
471
+ expect(matches[i].startIndex).toBeGreaterThanOrEqual(matches[i - 1].startIndex);
472
+ }
473
+ });
474
+
475
+ test('does not flag common code patterns', () => {
476
+ // git SHA (40 hex chars) should not be flagged as AWS secret
477
+ // since it lacks a preceding separator
478
+ const sha = '4b825dc642cb6eb9a060e54bf899d15f13fe1d7a';
479
+ const matches = scanText(`commit ${sha}`);
480
+ const awsMatches = matches.filter((m) => m.type === 'AWS Secret Key');
481
+ expect(awsMatches).toHaveLength(0);
482
+ });
483
+
484
+ test('handles multi-line input', () => {
485
+ const input = `
486
+ -----BEGIN RSA PRIVATE KEY-----
487
+ MIIEpAIBAAKCAQEA0Z3VS5JJcds3xfn/ygWep4PAtGoSNQ==
488
+ -----END RSA PRIVATE KEY-----
489
+ `;
490
+ expectMatch(input, 'Private Key');
491
+ });
492
+
493
+ test('handles empty string', () => {
494
+ expect(scanText('')).toHaveLength(0);
495
+ });
496
+
497
+ test('handles very long text without crashing', () => {
498
+ const longText = 'a'.repeat(100_000);
499
+ const start = performance.now();
500
+ scanText(longText);
501
+ const elapsed = performance.now() - start;
502
+ // Should complete in under 500ms even for 100KB
503
+ expect(elapsed).toBeLessThan(500);
504
+ });
505
+
506
+ test('match includes correct startIndex and endIndex', () => {
507
+ const prefix = 'key is: ';
508
+ const key = 'AKIAIOSFODNN7REALKEY';
509
+ const input = prefix + key;
510
+ const match = expectMatch(input, 'AWS Access Key');
511
+ expect(match.startIndex).toBe(prefix.length);
512
+ expect(match.endIndex).toBe(prefix.length + key.length);
513
+ expect(input.slice(match.startIndex, match.endIndex)).toBe(key);
514
+ });
515
+ });
516
+
517
+ // ---------------------------------------------------------------------------
518
+ // Edge cases / false positives
519
+ // ---------------------------------------------------------------------------
520
+ describe('false positive resistance', () => {
521
+ test('does not flag base64-encoded images', () => {
522
+ // A typical short base64 image data chunk — should not trigger
523
+ const img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA';
524
+ const matches = scanText(img);
525
+ // May match JWT-like patterns; verify no AWS/generic matches
526
+ const sensitive = matches.filter(
527
+ (m) => m.type === 'AWS Secret Key' || m.type === 'Generic Secret Assignment',
528
+ );
529
+ expect(sensitive).toHaveLength(0);
530
+ });
531
+
532
+ test('does not flag UUIDs as Heroku keys when they are zero-filled', () => {
533
+ const matches = scanText('00000000-0000-0000-0000-000000000000');
534
+ const heroku = matches.filter((m) => m.type === 'Heroku API Key');
535
+ expect(heroku).toHaveLength(0);
536
+ });
537
+
538
+ test('does not flag common hex strings without context', () => {
539
+ // MD5/SHA hashes are hex but should not be flagged
540
+ expectNoMatch('d41d8cd98f00b204e9800998ecf8427e');
541
+ });
542
+
543
+ test('does not flag public key headers', () => {
544
+ const pubKey = '-----BEGIN PUBLIC KEY-----';
545
+ const matches = scanText(pubKey);
546
+ const privKeys = matches.filter((m) => m.type === 'Private Key');
547
+ expect(privKeys).toHaveLength(0);
548
+ });
549
+ });
550
+
551
+ // ---------------------------------------------------------------------------
552
+ // Shannon entropy
553
+ // ---------------------------------------------------------------------------
554
+ describe('shannonEntropy', () => {
555
+ test('returns 0 for empty string', () => {
556
+ expect(shannonEntropy('')).toBe(0);
557
+ });
558
+
559
+ test('returns 0 for single repeated character', () => {
560
+ expect(shannonEntropy('aaaaaa')).toBe(0);
561
+ });
562
+
563
+ test('returns 1.0 for two equally distributed characters', () => {
564
+ expect(shannonEntropy('ababab')).toBeCloseTo(1.0, 5);
565
+ });
566
+
567
+ test('returns high entropy for random-looking strings', () => {
568
+ // A high-entropy hex string
569
+ const entropy = shannonEntropy('a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4');
570
+ expect(entropy).toBeGreaterThan(3.0);
571
+ });
572
+
573
+ test('returns lower entropy for structured/repetitive content', () => {
574
+ const entropy = shannonEntropy('abcabcabcabcabcabc');
575
+ expect(entropy).toBeLessThan(2.0);
576
+ });
577
+ });
578
+
579
+ // ---------------------------------------------------------------------------
580
+ // Entropy-based secret detection
581
+ // ---------------------------------------------------------------------------
582
+ describe('entropy-based detection', () => {
583
+ test('detects high-entropy hex token near secret keyword', () => {
584
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
585
+ // Use context that triggers entropy detection but not generic assignment pattern
586
+ const input = `The signing_key is ${hexSecret}`;
587
+ const matches = scanText(input);
588
+ const entropyMatch = matches.find((m) => m.type === 'High-Entropy Hex Token');
589
+ expect(entropyMatch).toBeDefined();
590
+ expect(entropyMatch!.startIndex).toBe(input.indexOf(hexSecret));
591
+ });
592
+
593
+ test('detects high-entropy base64 token near secret keyword', () => {
594
+ const b64Secret = 'aB3cD4eF5gH6iJ7kL8mN+pQ/rS0tU1vW2xY3zA=';
595
+ // Use "is" instead of ": " to avoid triggering the generic assignment pattern
596
+ const input = `The token is ${b64Secret}`;
597
+ const matches = scanText(input);
598
+ const entropyMatch = matches.find((m) => m.type === 'High-Entropy Base64 Token');
599
+ expect(entropyMatch).toBeDefined();
600
+ });
601
+
602
+ test('does not flag high-entropy hex without secret context', () => {
603
+ const hexString = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
604
+ // No secret keyword nearby — just "checksum"
605
+ const input = `checksum: ${hexString}`;
606
+ const matches = scanText(input);
607
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
608
+ expect(entropyMatches).toHaveLength(0);
609
+ });
610
+
611
+ test('does not flag low-entropy tokens even with context', () => {
612
+ // Repeated pattern = low entropy
613
+ const lowEntropy = 'abcabcabcabcabcabcabcabc';
614
+ const input = `secret = ${lowEntropy}`;
615
+ const matches = scanText(input);
616
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
617
+ expect(entropyMatches).toHaveLength(0);
618
+ });
619
+
620
+ test('does not flag tokens shorter than minLength', () => {
621
+ const shortToken = 'a3f8c1b2d9e4f5a6';
622
+ const input = `api_key = ${shortToken}`;
623
+ const matches = scanText(input);
624
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
625
+ expect(entropyMatches).toHaveLength(0);
626
+ });
627
+
628
+ test('can be disabled via config', () => {
629
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
630
+ const input = `api_key = ${hexSecret}`;
631
+ const matches = scanText(input, { enabled: false });
632
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
633
+ expect(entropyMatches).toHaveLength(0);
634
+ });
635
+
636
+ test('respects custom threshold', () => {
637
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
638
+ const input = `The signing_key is ${hexSecret}`;
639
+
640
+ // With extremely high threshold, nothing matches
641
+ const matchesHigh = scanText(input, { hexThreshold: 10.0 });
642
+ const entropyHigh = matchesHigh.filter((m) => m.type.startsWith('High-Entropy'));
643
+ expect(entropyHigh).toHaveLength(0);
644
+
645
+ // With low threshold, it matches
646
+ const matchesLow = scanText(input, { hexThreshold: 1.0 });
647
+ const entropyLow = matchesLow.filter((m) => m.type.startsWith('High-Entropy'));
648
+ expect(entropyLow.length).toBeGreaterThan(0);
649
+ });
650
+
651
+ test('does not double-count tokens already matched by patterns', () => {
652
+ // An AWS access key should only appear once (pattern match), not again as entropy
653
+ const input = `api_key = AKIAIOSFODNN7REALKEY`;
654
+ const matches = scanText(input);
655
+ const awsMatches = matches.filter((m) => m.type === 'AWS Access Key');
656
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
657
+ expect(awsMatches).toHaveLength(1);
658
+ // Should not have an entropy match for the same range
659
+ expect(entropyMatches).toHaveLength(0);
660
+ });
661
+
662
+ test('recognizes various secret context keywords', () => {
663
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
664
+ // Use "is" instead of "=" to avoid matching the generic assignment pattern
665
+ const keywords = ['bearer', 'credential', 'private_key', 'signing_key', 'encryption_key'];
666
+ for (const kw of keywords) {
667
+ const input = `The ${kw} is ${hexSecret}`;
668
+ const matches = scanText(input);
669
+ const entropyMatches = matches.filter((m) => m.type.startsWith('High-Entropy'));
670
+ expect(entropyMatches.length).toBeGreaterThanOrEqual(1);
671
+ }
672
+ });
673
+ });
674
+
675
+ // ---------------------------------------------------------------------------
676
+ // hasSecretContext helper
677
+ // ---------------------------------------------------------------------------
678
+ describe('hasSecretContext', () => {
679
+ test('detects keyword in prefix', () => {
680
+ const text = 'api_key = abc123';
681
+ expect(_hasSecretContext(text, 10)).toBe(true);
682
+ });
683
+
684
+ test('returns false without keyword', () => {
685
+ const text = 'username = abc123';
686
+ expect(_hasSecretContext(text, 11)).toBe(false);
687
+ });
688
+
689
+ test('detects keyword case-insensitively', () => {
690
+ const text = 'API_KEY = abc123';
691
+ expect(_hasSecretContext(text, 10)).toBe(true);
692
+ });
693
+ });
694
+
695
+ // ---------------------------------------------------------------------------
696
+ // Overlapping match handling in redactSecrets (#166 feedback)
697
+ // ---------------------------------------------------------------------------
698
+ describe('overlapping match redaction', () => {
699
+ test('does not corrupt output when matches overlap', () => {
700
+ // An AWS key inside a generic secret assignment produces overlapping matches
701
+ const input = `api_key = "AKIAIOSFODNN7REALKEY"`;
702
+ const result = redactSecrets(input);
703
+ // Should redact correctly without duplicating markers or losing text
704
+ expect(result).not.toContain('AKIAIOSFODNN7REALKEY');
705
+ // The outer quotes should be preserved somewhere in the output
706
+ expect(result).toContain('<redacted type="');
707
+ });
708
+
709
+ test('skips nested match and preserves surrounding text', () => {
710
+ // Construct a case where a specific match is entirely inside a broader one
711
+ const input = `password = "AKIAIOSFODNN7REALKEY inside text"`;
712
+ const result = redactSecrets(input);
713
+ // Should have at least one redaction
714
+ expect(result).toContain('<redacted type="');
715
+ // Should not contain the raw key
716
+ expect(result).not.toContain('AKIAIOSFODNN7REALKEY');
717
+ });
718
+
719
+ test('wider overlapping match extends redaction span (#172 feedback)', () => {
720
+ // A shorter match (e.g. AWS-like 40 chars) inside a longer generic assignment
721
+ // should not leak the suffix of the longer match
722
+ const input = `password = "AKIAIOSFODNN7REALKEY extra-tail-secret"`;
723
+ const result = redactSecrets(input);
724
+ // Nothing from the original secret value should leak
725
+ expect(result).not.toContain('extra-tail-secret');
726
+ expect(result).not.toContain('AKIAIOSFODNN7REALKEY');
727
+ expect(result).toContain('<redacted type="');
728
+ });
729
+
730
+ test('wider match at same start position wins', () => {
731
+ // When two matches start at same offset, wider one should be used
732
+ const input = `token = "AKIAIOSFODNN7REALKEY-plus-extra-data"`;
733
+ const result = redactSecrets(input);
734
+ expect(result).not.toContain('AKIAIOSFODNN7REALKEY');
735
+ expect(result).not.toContain('plus-extra-data');
736
+ expect(result).toContain('<redacted type="');
737
+ });
738
+ });
739
+
740
+ // ---------------------------------------------------------------------------
741
+ // Heroku UUID context requirement (#166 feedback)
742
+ // ---------------------------------------------------------------------------
743
+ describe('Heroku API Key', () => {
744
+ test('detects UUID with heroku context keyword', () => {
745
+ const uuid = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
746
+ const input = `HEROKU_API_KEY=${uuid}`;
747
+ const matches = scanText(input);
748
+ const heroku = matches.filter((m) => m.type === 'Heroku API Key');
749
+ expect(heroku).toHaveLength(1);
750
+ });
751
+
752
+ test('detects UUID with heroku_auth_token prefix', () => {
753
+ const uuid = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
754
+ const input = `heroku_auth_token = "${uuid}"`;
755
+ const matches = scanText(input);
756
+ const heroku = matches.filter((m) => m.type === 'Heroku API Key');
757
+ expect(heroku).toHaveLength(1);
758
+ });
759
+
760
+ test('does not flag random UUIDs without heroku context', () => {
761
+ const uuid = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
762
+ const input = `request_id: ${uuid}`;
763
+ const matches = scanText(input);
764
+ const heroku = matches.filter((m) => m.type === 'Heroku API Key');
765
+ expect(heroku).toHaveLength(0);
766
+ });
767
+
768
+ test('does not flag UUIDs in logs', () => {
769
+ const input = 'Processed request id=a1b2c3d4-e5f6-7890-abcd-ef1234567890 in 42ms';
770
+ const matches = scanText(input);
771
+ const heroku = matches.filter((m) => m.type === 'Heroku API Key');
772
+ expect(heroku).toHaveLength(0);
773
+ });
774
+ });
775
+
776
+ // ---------------------------------------------------------------------------
777
+ // Unquoted generic secret assignments (#166 feedback)
778
+ // ---------------------------------------------------------------------------
779
+ describe('unquoted generic secret assignments', () => {
780
+ test('detects .env-style unquoted password', () => {
781
+ const input = 'DATABASE_PASSWORD=supersecret123';
782
+ const matches = scanText(input);
783
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
784
+ expect(generic.length).toBeGreaterThan(0);
785
+ });
786
+
787
+ test('detects .env-style unquoted api key', () => {
788
+ const input = 'API_KEY=abcdef1234567890';
789
+ const matches = scanText(input);
790
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
791
+ expect(generic.length).toBeGreaterThan(0);
792
+ });
793
+
794
+ test('detects unquoted token assignment', () => {
795
+ const input = 'AUTH_TOKEN=mysecuretokenvalue123';
796
+ const matches = scanText(input);
797
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
798
+ expect(generic.length).toBeGreaterThan(0);
799
+ });
800
+
801
+ test('still detects quoted assignments', () => {
802
+ const input = `secret = "mysupersecretsecret"`;
803
+ const matches = scanText(input);
804
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
805
+ expect(generic.length).toBeGreaterThan(0);
806
+ });
807
+
808
+ test('does not match short unquoted values', () => {
809
+ const input = 'password=short';
810
+ const matches = scanText(input);
811
+ const generic = matches.filter((m) => m.type === 'Generic Secret Assignment');
812
+ expect(generic).toHaveLength(0);
813
+ });
814
+ });
815
+
816
+ // ---------------------------------------------------------------------------
817
+ // Base64 padding in entropy detection (#169 feedback)
818
+ // ---------------------------------------------------------------------------
819
+ describe('base64 padding handling', () => {
820
+ test('includes trailing = padding in the match', () => {
821
+ const b64 = 'aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2xY3zA=';
822
+ const input = `token: ${b64}`;
823
+ const matches = scanText(input);
824
+ const entropyMatch = matches.find((m) => m.type === 'High-Entropy Base64 Token');
825
+ expect(entropyMatch).toBeDefined();
826
+ // endIndex should include the '='
827
+ expect(input.slice(entropyMatch!.startIndex, entropyMatch!.endIndex)).toContain('=');
828
+ });
829
+
830
+ test('includes trailing == padding in the match', () => {
831
+ const b64 = 'aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2x==';
832
+ const input = `token: ${b64}`;
833
+ const matches = scanText(input);
834
+ const entropyMatch = matches.find((m) => m.type === 'High-Entropy Base64 Token');
835
+ expect(entropyMatch).toBeDefined();
836
+ expect(input.slice(entropyMatch!.startIndex, entropyMatch!.endIndex)).toContain('==');
837
+ });
838
+
839
+ test('redactSecrets fully redacts padded base64 tokens', () => {
840
+ const b64 = 'aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2xY3zA=';
841
+ const input = `token: "${b64}"`;
842
+ const result = redactSecrets(input);
843
+ // No trailing '=' should leak after redaction
844
+ expect(result).not.toMatch(/<redacted type="[^"]+" \/>=/)
845
+ expect(result).toContain('<redacted type="');
846
+ });
847
+ });
848
+
849
+ // ---------------------------------------------------------------------------
850
+ // Word-boundary context keyword matching (#169 feedback)
851
+ // ---------------------------------------------------------------------------
852
+ describe('word-boundary context keywords', () => {
853
+ test('does not match "key" inside "monkey"', () => {
854
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
855
+ const input = `monkey: ${hexSecret}`;
856
+ const matches = scanText(input);
857
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
858
+ expect(entropy).toHaveLength(0);
859
+ });
860
+
861
+ test('does not match "key" inside "keyboard"', () => {
862
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
863
+ const input = `keyboard = ${hexSecret}`;
864
+ const matches = scanText(input);
865
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
866
+ expect(entropy).toHaveLength(0);
867
+ });
868
+
869
+ test('does not match "token" inside "tokenizer"', () => {
870
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
871
+ const input = `tokenizer: ${hexSecret}`;
872
+ const matches = scanText(input);
873
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
874
+ expect(entropy).toHaveLength(0);
875
+ });
876
+
877
+ test('still matches "key" as a standalone word', () => {
878
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
879
+ const input = `The key is ${hexSecret}`;
880
+ const matches = scanText(input);
881
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
882
+ expect(entropy.length).toBeGreaterThan(0);
883
+ });
884
+
885
+ test('still matches "api_key" with underscores', () => {
886
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
887
+ const input = `The api_key is ${hexSecret}`;
888
+ const matches = scanText(input);
889
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
890
+ expect(entropy.length).toBeGreaterThan(0);
891
+ });
892
+
893
+ test('still matches "api-key" with hyphens', () => {
894
+ const hexSecret = 'a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8';
895
+ const input = `The api-key is ${hexSecret}`;
896
+ const matches = scanText(input);
897
+ const entropy = matches.filter((m) => m.type.startsWith('High-Entropy'));
898
+ expect(entropy.length).toBeGreaterThan(0);
899
+ });
900
+ });