@vellumai/assistant 0.6.5 → 0.6.6

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 (443) hide show
  1. package/AGENTS.md +9 -1
  2. package/ARCHITECTURE.md +15 -17
  3. package/Dockerfile +6 -4
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
  5. package/docs/architecture/integrations.md +32 -39
  6. package/docs/architecture/memory.md +25 -30
  7. package/docs/architecture/security.md +7 -6
  8. package/docs/browser-use-architecture-phase2.md +63 -20
  9. package/docs/plugins.md +761 -0
  10. package/examples/plugins/echo/README.md +132 -0
  11. package/examples/plugins/echo/package.json +17 -0
  12. package/examples/plugins/echo/register.ts +187 -0
  13. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  14. package/openapi.yaml +212 -68
  15. package/package.json +1 -1
  16. package/src/__tests__/app-compiler.test.ts +57 -0
  17. package/src/__tests__/approval-cascade.test.ts +7 -2
  18. package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
  19. package/src/__tests__/avatar-generator.test.ts +4 -2
  20. package/src/__tests__/bundled-asset.test.ts +6 -6
  21. package/src/__tests__/catalog-cache.test.ts +69 -0
  22. package/src/__tests__/checker.test.ts +459 -171
  23. package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
  24. package/src/__tests__/compaction-events.test.ts +501 -0
  25. package/src/__tests__/compaction-pipeline.test.ts +210 -0
  26. package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
  27. package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
  28. package/src/__tests__/config-model-image-provider.test.ts +110 -0
  29. package/src/__tests__/config-schema.test.ts +22 -9
  30. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
  31. package/src/__tests__/contacts-tools.test.ts +26 -0
  32. package/src/__tests__/context-overflow-policy.test.ts +7 -7
  33. package/src/__tests__/context-window-manager.test.ts +355 -4
  34. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  35. package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
  36. package/src/__tests__/conversation-agent-loop.test.ts +30 -141
  37. package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
  38. package/src/__tests__/conversation-history-web-search.test.ts +1 -0
  39. package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
  40. package/src/__tests__/conversation-pairing.test.ts +174 -10
  41. package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
  42. package/src/__tests__/conversation-process-callsite.test.ts +3 -0
  43. package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
  44. package/src/__tests__/conversation-queue.test.ts +29 -14
  45. package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
  46. package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
  47. package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
  48. package/src/__tests__/conversation-seed-composer.test.ts +2 -2
  49. package/src/__tests__/conversation-slash-queue.test.ts +7 -2
  50. package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
  51. package/src/__tests__/conversation-speed-override.test.ts +6 -1
  52. package/src/__tests__/conversation-title-service.test.ts +116 -0
  53. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
  54. package/src/__tests__/conversation-usage.test.ts +1 -1
  55. package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
  56. package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
  57. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
  58. package/src/__tests__/credential-health-service.test.ts +78 -9
  59. package/src/__tests__/credential-security-invariants.test.ts +2 -2
  60. package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
  61. package/src/__tests__/empty-response-pipeline.test.ts +305 -0
  62. package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
  63. package/src/__tests__/first-greeting.test.ts +247 -5
  64. package/src/__tests__/headless-browser-mode.test.ts +57 -0
  65. package/src/__tests__/history-repair-pipeline.test.ts +399 -0
  66. package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
  67. package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
  68. package/src/__tests__/host-proxy-interface.test.ts +36 -2
  69. package/src/__tests__/image-credentials.test.ts +137 -0
  70. package/src/__tests__/image-service-dispatcher.test.ts +186 -0
  71. package/src/__tests__/injector-chain.test.ts +526 -0
  72. package/src/__tests__/intent-routing.test.ts +0 -26
  73. package/src/__tests__/llm-call-pipeline.test.ts +285 -0
  74. package/src/__tests__/llm-schema.test.ts +1 -1
  75. package/src/__tests__/media-generate-image.test.ts +119 -13
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
  77. package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
  78. package/src/__tests__/migration-import-from-url.test.ts +5 -68
  79. package/src/__tests__/model-intents.test.ts +4 -2
  80. package/src/__tests__/notification-broadcaster.test.ts +3 -3
  81. package/src/__tests__/notification-decision-strategy.test.ts +0 -11
  82. package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
  83. package/src/__tests__/oauth-apps-routes.test.ts +1 -1
  84. package/src/__tests__/oauth-cli.test.ts +14 -12
  85. package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
  86. package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
  87. package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
  88. package/src/__tests__/oauth-providers-routes.test.ts +3 -2
  89. package/src/__tests__/oauth-store.test.ts +41 -76
  90. package/src/__tests__/onboarding-template-contract.test.ts +16 -64
  91. package/src/__tests__/openai-image-service.test.ts +368 -0
  92. package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
  93. package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
  94. package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
  95. package/src/__tests__/persistence-pipeline.test.ts +377 -0
  96. package/src/__tests__/pipeline-runner.test.ts +565 -0
  97. package/src/__tests__/platform.test.ts +5 -2
  98. package/src/__tests__/plugin-bootstrap.test.ts +483 -0
  99. package/src/__tests__/plugin-registry.test.ts +273 -0
  100. package/src/__tests__/plugin-route-contribution.test.ts +288 -0
  101. package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
  102. package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
  103. package/src/__tests__/plugin-types.test.ts +320 -0
  104. package/src/__tests__/pricing.test.ts +44 -12
  105. package/src/__tests__/proxy-approval-callback.test.ts +69 -8
  106. package/src/__tests__/reaction-persistence.test.ts +1 -0
  107. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
  108. package/src/__tests__/registry.test.ts +0 -2
  109. package/src/__tests__/schedule-routes.test.ts +131 -1
  110. package/src/__tests__/scheduler-recurrence.test.ts +14 -70
  111. package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
  112. package/src/__tests__/secret-detection-handler.test.ts +0 -10
  113. package/src/__tests__/shell-identity.test.ts +0 -134
  114. package/src/__tests__/suggestion-routes.test.ts +103 -4
  115. package/src/__tests__/task-memory-cleanup.test.ts +1 -0
  116. package/src/__tests__/task-scheduler.test.ts +3 -15
  117. package/src/__tests__/test-preload.ts +11 -0
  118. package/src/__tests__/title-generate-pipeline.test.ts +224 -0
  119. package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
  120. package/src/__tests__/tool-error-pipeline.test.ts +244 -0
  121. package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
  122. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
  123. package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
  124. package/src/__tests__/tool-executor.test.ts +141 -0
  125. package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
  126. package/src/__tests__/tool-result-truncation.test.ts +0 -110
  127. package/src/__tests__/user-plugin-loader.test.ts +191 -0
  128. package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
  129. package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
  130. package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
  131. package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
  132. package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
  133. package/src/__tests__/workspace-policy.test.ts +21 -3
  134. package/src/agent/loop.ts +340 -102
  135. package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
  136. package/src/approvals/guardian-request-resolvers.ts +80 -0
  137. package/src/backup/__tests__/backup-worker.test.ts +2 -13
  138. package/src/backup/backup-worker.ts +3 -15
  139. package/src/bundler/app-compiler.ts +84 -1
  140. package/src/calls/call-state.ts +2 -2
  141. package/src/channels/__tests__/types.test.ts +3 -3
  142. package/src/channels/types.ts +6 -4
  143. package/src/cli/__tests__/notifications.test.ts +87 -211
  144. package/src/cli/commands/__tests__/backup.test.ts +1 -1
  145. package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
  146. package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
  147. package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
  148. package/src/cli/commands/backup.ts +2 -2
  149. package/src/cli/commands/clients.ts +138 -0
  150. package/src/cli/commands/completions.ts +2 -9
  151. package/src/cli/commands/conversations.ts +55 -7
  152. package/src/cli/commands/image-generation.ts +33 -34
  153. package/src/cli/commands/notifications.ts +68 -103
  154. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
  155. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
  156. package/src/cli/commands/oauth/connect.ts +2 -2
  157. package/src/cli/commands/oauth/providers.ts +176 -8
  158. package/src/cli/commands/oauth/status.ts +46 -36
  159. package/src/cli/commands/skills.ts +3 -4
  160. package/src/cli/program.ts +25 -29
  161. package/src/config/__tests__/backup-schema.test.ts +7 -2
  162. package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
  163. package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
  164. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
  165. package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
  166. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
  170. package/src/config/bundled-skills/messaging/SKILL.md +3 -3
  171. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
  172. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
  173. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
  174. package/src/config/bundled-skills/schedule/SKILL.md +8 -3
  175. package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
  176. package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
  177. package/src/config/bundled-tool-registry.ts +0 -15
  178. package/src/config/feature-flag-registry.json +17 -1
  179. package/src/config/schema.ts +19 -0
  180. package/src/config/schemas/backup.ts +1 -1
  181. package/src/config/schemas/conversations.ts +16 -0
  182. package/src/config/schemas/llm.ts +2 -3
  183. package/src/config/schemas/security.ts +6 -6
  184. package/src/config/schemas/tts.ts +11 -0
  185. package/src/config/skill-state.ts +6 -2
  186. package/src/config/skills.ts +94 -5
  187. package/src/context/__tests__/compact-prompt.test.ts +27 -9
  188. package/src/context/prompts/compact.md +26 -12
  189. package/src/context/tool-result-truncation.ts +3 -63
  190. package/src/context/window-manager.ts +190 -16
  191. package/src/credential-health/credential-health-service.ts +19 -6
  192. package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
  193. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
  194. package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
  195. package/src/daemon/config-watcher.ts +0 -2
  196. package/src/daemon/context-overflow-policy.ts +4 -13
  197. package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
  198. package/src/daemon/conversation-agent-loop.ts +984 -683
  199. package/src/daemon/conversation-history.ts +10 -19
  200. package/src/daemon/conversation-lifecycle.ts +37 -19
  201. package/src/daemon/conversation-notifiers.ts +2 -110
  202. package/src/daemon/conversation-process.ts +14 -7
  203. package/src/daemon/conversation-runtime-assembly.ts +532 -411
  204. package/src/daemon/conversation-tool-setup.ts +41 -4
  205. package/src/daemon/conversation.ts +80 -35
  206. package/src/daemon/external-plugins-bootstrap.ts +478 -0
  207. package/src/daemon/first-greeting.ts +191 -14
  208. package/src/daemon/handlers/config-model.ts +11 -0
  209. package/src/daemon/handlers/skills.ts +5 -1
  210. package/src/daemon/lifecycle.ts +33 -68
  211. package/src/daemon/message-types/computer-use.ts +2 -34
  212. package/src/daemon/message-types/conversations.ts +49 -0
  213. package/src/daemon/message-types/messages.ts +12 -0
  214. package/src/daemon/server.ts +5 -3
  215. package/src/daemon/shutdown-handlers.ts +2 -12
  216. package/src/daemon/tool-side-effects.ts +14 -56
  217. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
  218. package/src/heartbeat/heartbeat-service.ts +24 -1
  219. package/src/home/__tests__/feed-population-integration.test.ts +312 -0
  220. package/src/home/emit-feed-event.ts +7 -0
  221. package/src/home/feed-types.ts +41 -2
  222. package/src/home/rewrite-command-preview.ts +66 -0
  223. package/src/ipc/__tests__/socket-path.test.ts +11 -50
  224. package/src/ipc/cli-client.ts +1 -1
  225. package/src/ipc/cli-server.ts +3 -3
  226. package/src/ipc/gateway-client.ts +4 -1
  227. package/src/ipc/routes/browser-context.ts +2 -0
  228. package/src/ipc/routes/browser.ts +1 -0
  229. package/src/ipc/routes/get-contact.ts +16 -0
  230. package/src/ipc/routes/index.ts +14 -0
  231. package/src/ipc/routes/list-clients.ts +31 -0
  232. package/src/ipc/routes/merge-contacts.ts +17 -0
  233. package/src/ipc/routes/notification.ts +133 -0
  234. package/src/ipc/routes/rename-conversation.ts +59 -0
  235. package/src/ipc/routes/search-contacts.ts +19 -0
  236. package/src/ipc/routes/upsert-contact.ts +25 -0
  237. package/src/ipc/socket-path.ts +14 -38
  238. package/src/media/app-icon-generator.ts +23 -46
  239. package/src/media/avatar-router.ts +26 -41
  240. package/src/media/gemini-image-service.ts +8 -41
  241. package/src/media/image-credentials.ts +73 -0
  242. package/src/media/image-service.ts +85 -0
  243. package/src/media/openai-image-service.ts +131 -0
  244. package/src/media/types.ts +46 -0
  245. package/src/memory/conversation-crud.ts +48 -18
  246. package/src/memory/conversation-queries.ts +57 -4
  247. package/src/memory/conversation-title-service.ts +25 -0
  248. package/src/memory/db-init.ts +8 -0
  249. package/src/memory/embedding-gemini.test.ts +41 -2
  250. package/src/memory/embedding-gemini.ts +6 -1
  251. package/src/memory/graph/bootstrap.test.ts +282 -0
  252. package/src/memory/graph/bootstrap.ts +8 -5
  253. package/src/memory/graph/extraction.ts +10 -2
  254. package/src/memory/graph/graph-search.test.ts +1 -0
  255. package/src/memory/graph/inspect.ts +2 -2
  256. package/src/memory/graph/retriever.ts +10 -3
  257. package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
  258. package/src/memory/migrations/149-oauth-tables.ts +1 -0
  259. package/src/memory/migrations/223-schedule-script-column.ts +11 -0
  260. package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
  261. package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
  262. package/src/memory/migrations/index.ts +4 -0
  263. package/src/memory/pkb/pkb-index.test.ts +1 -0
  264. package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
  265. package/src/memory/pkb/pkb-search.test.ts +65 -4
  266. package/src/memory/pkb/pkb-search.ts +40 -18
  267. package/src/memory/qdrant-client.test.ts +60 -0
  268. package/src/memory/qdrant-client.ts +25 -0
  269. package/src/memory/schema/infrastructure.ts +1 -0
  270. package/src/memory/schema/oauth.ts +4 -1
  271. package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
  272. package/src/messaging/providers/slack/render-transcript.ts +58 -0
  273. package/src/notifications/conversation-pairing.ts +78 -19
  274. package/src/notifications/copy-composer.ts +0 -5
  275. package/src/notifications/emit-signal.ts +1 -1
  276. package/src/notifications/signal.ts +1 -2
  277. package/src/oauth/AGENTS.md +1 -1
  278. package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
  279. package/src/oauth/connect-orchestrator.ts +8 -34
  280. package/src/oauth/connect-types.ts +6 -10
  281. package/src/oauth/manual-token-connection.ts +23 -0
  282. package/src/oauth/oauth-store.ts +30 -14
  283. package/src/oauth/provider-serializer.ts +6 -1
  284. package/src/oauth/seed-providers.ts +56 -108
  285. package/src/outbound-proxy/http-forwarder.ts +9 -0
  286. package/src/permissions/approval-policy.test.ts +293 -18
  287. package/src/permissions/approval-policy.ts +110 -58
  288. package/src/permissions/arg-parser.test.ts +161 -0
  289. package/src/permissions/arg-parser.ts +141 -0
  290. package/src/permissions/bash-risk-classifier.test.ts +414 -2
  291. package/src/permissions/bash-risk-classifier.ts +303 -60
  292. package/src/permissions/checker.ts +157 -29
  293. package/src/permissions/command-registry.test.ts +239 -0
  294. package/src/permissions/command-registry.ts +234 -54
  295. package/src/permissions/defaults.ts +5 -4
  296. package/src/permissions/gateway-threshold-reader.ts +196 -0
  297. package/src/permissions/prompter.ts +4 -0
  298. package/src/permissions/risk-types.ts +61 -4
  299. package/src/permissions/schedule-risk-classifier.test.ts +129 -0
  300. package/src/permissions/schedule-risk-classifier.ts +85 -0
  301. package/src/permissions/shell-identity.ts +2 -42
  302. package/src/permissions/types.ts +2 -0
  303. package/src/permissions/workspace-policy.ts +8 -3
  304. package/src/plugins/defaults/circuit-breaker.ts +146 -0
  305. package/src/plugins/defaults/compaction.ts +145 -0
  306. package/src/plugins/defaults/empty-response.ts +126 -0
  307. package/src/plugins/defaults/history-repair.ts +85 -0
  308. package/src/plugins/defaults/index.ts +116 -0
  309. package/src/plugins/defaults/injectors.ts +491 -0
  310. package/src/plugins/defaults/llm-call.ts +82 -0
  311. package/src/plugins/defaults/memory-retrieval.ts +226 -0
  312. package/src/plugins/defaults/overflow-reduce.ts +181 -0
  313. package/src/plugins/defaults/persistence.ts +129 -0
  314. package/src/plugins/defaults/title-generate.ts +95 -0
  315. package/src/plugins/defaults/token-estimate.ts +104 -0
  316. package/src/plugins/defaults/tool-error.ts +126 -0
  317. package/src/plugins/defaults/tool-execute.ts +89 -0
  318. package/src/plugins/defaults/tool-result-truncate.ts +88 -0
  319. package/src/plugins/pipeline.ts +316 -0
  320. package/src/plugins/plugin-skill-contributions.ts +292 -0
  321. package/src/plugins/registry.ts +241 -0
  322. package/src/plugins/types.ts +1134 -0
  323. package/src/plugins/user-loader.ts +177 -0
  324. package/src/prompts/templates/BOOTSTRAP.md +27 -77
  325. package/src/providers/model-catalog.ts +52 -29
  326. package/src/providers/model-intents.ts +1 -1
  327. package/src/providers/openrouter/client.ts +5 -1
  328. package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
  329. package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
  330. package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
  331. package/src/providers/speech-to-text/xai-realtime.ts +39 -14
  332. package/src/runtime/AGENTS.md +25 -16
  333. package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
  334. package/src/runtime/__tests__/client-registry.test.ts +293 -0
  335. package/src/runtime/client-registry.ts +261 -0
  336. package/src/runtime/http-server.ts +77 -8
  337. package/src/runtime/http-types.ts +0 -2
  338. package/src/runtime/migrations/vbundle-builder.ts +1 -22
  339. package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
  340. package/src/runtime/routes/approval-routes.ts +17 -0
  341. package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
  342. package/src/runtime/routes/conversation-routes.ts +223 -116
  343. package/src/runtime/routes/inbound-message-handler.ts +88 -13
  344. package/src/runtime/routes/memory-item-routes.test.ts +1 -0
  345. package/src/runtime/routes/migration-routes.ts +0 -3
  346. package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
  347. package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
  348. package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
  349. package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
  350. package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
  351. package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
  352. package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
  353. package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
  354. package/src/runtime/routes/playground/deps.ts +56 -0
  355. package/src/runtime/routes/playground/force-compact.ts +73 -0
  356. package/src/runtime/routes/playground/guard.ts +37 -0
  357. package/src/runtime/routes/playground/index.ts +28 -0
  358. package/src/runtime/routes/playground/inject-failures.ts +159 -0
  359. package/src/runtime/routes/playground/reset-circuit.ts +115 -0
  360. package/src/runtime/routes/playground/seed-conversation.ts +139 -0
  361. package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
  362. package/src/runtime/routes/playground/state.ts +78 -0
  363. package/src/runtime/routes/schedule-routes.ts +89 -8
  364. package/src/runtime/skill-route-registry.ts +75 -15
  365. package/src/schedule/run-script.ts +68 -0
  366. package/src/schedule/schedule-store.ts +7 -1
  367. package/src/schedule/scheduler.ts +48 -8
  368. package/src/skills/catalog-cache.ts +12 -5
  369. package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
  370. package/src/tools/browser/browser-execution.ts +88 -19
  371. package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
  372. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
  373. package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
  374. package/src/tools/browser/cdp-client/factory.ts +15 -4
  375. package/src/tools/executor.ts +126 -74
  376. package/src/tools/network/script-proxy/session-manager.ts +37 -1
  377. package/src/tools/permission-checker.ts +98 -49
  378. package/src/tools/policy-context.ts +4 -0
  379. package/src/tools/registry.ts +140 -3
  380. package/src/tools/schedule/create.ts +23 -8
  381. package/src/tools/schedule/update.ts +3 -1
  382. package/src/tools/secret-detection-handler.ts +0 -51
  383. package/src/tools/system/avatar-generator.ts +6 -2
  384. package/src/tools/types.ts +28 -2
  385. package/src/util/platform.ts +7 -2
  386. package/src/util/pricing.ts +26 -3
  387. package/src/workspace/migrations/006-services-config.ts +2 -4
  388. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
  389. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
  390. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
  391. package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
  392. package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
  393. package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
  394. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
  395. package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
  396. package/src/workspace/migrations/registry.ts +12 -0
  397. package/tsconfig.json +1 -1
  398. package/hook-templates/debug-prompt-logger/hook.json +0 -7
  399. package/hook-templates/debug-prompt-logger/run.sh +0 -66
  400. package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
  401. package/src/__tests__/context-overflow-approval.test.ts +0 -156
  402. package/src/__tests__/hooks-blocking.test.ts +0 -178
  403. package/src/__tests__/hooks-cli.test.ts +0 -182
  404. package/src/__tests__/hooks-config.test.ts +0 -108
  405. package/src/__tests__/hooks-discovery.test.ts +0 -211
  406. package/src/__tests__/hooks-integration.test.ts +0 -196
  407. package/src/__tests__/hooks-manager.test.ts +0 -226
  408. package/src/__tests__/hooks-runner.test.ts +0 -175
  409. package/src/__tests__/hooks-settings.test.ts +0 -160
  410. package/src/__tests__/hooks-templates.test.ts +0 -169
  411. package/src/__tests__/hooks-ts-runner.test.ts +0 -170
  412. package/src/__tests__/hooks-watch.test.ts +0 -112
  413. package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
  414. package/src/__tests__/oauth-scope-policy.test.ts +0 -180
  415. package/src/__tests__/send-notification-tool.test.ts +0 -83
  416. package/src/cli/commands/shotgun.ts +0 -266
  417. package/src/config/bundled-skills/conversations/SKILL.md +0 -20
  418. package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
  419. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
  420. package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
  421. package/src/config/bundled-skills/notifications/SKILL.md +0 -40
  422. package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
  423. package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
  424. package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
  425. package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
  426. package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
  427. package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
  428. package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
  429. package/src/daemon/context-overflow-approval.ts +0 -52
  430. package/src/daemon/watch-handler.ts +0 -399
  431. package/src/hooks/cli.ts +0 -253
  432. package/src/hooks/config.ts +0 -100
  433. package/src/hooks/discovery.ts +0 -135
  434. package/src/hooks/manager.ts +0 -179
  435. package/src/hooks/runner.ts +0 -117
  436. package/src/hooks/templates.ts +0 -77
  437. package/src/hooks/types.ts +0 -75
  438. package/src/oauth/scope-policy.ts +0 -89
  439. package/src/runtime/gateway-internal-client.ts +0 -94
  440. package/src/runtime/routes/watch-routes.ts +0 -156
  441. package/src/signals/shotgun.ts +0 -203
  442. package/src/tools/watch/screen-watch.ts +0 -144
  443. package/src/tools/watch/watch-state.ts +0 -142
@@ -9,7 +9,10 @@ mock.module("../util/logger.js", () => ({
9
9
 
10
10
  import { getDb, initializeDb } from "../memory/db.js";
11
11
  import { scheduleRouteDefinitions } from "../runtime/routes/schedule-routes.js";
12
- import { createSchedule } from "../schedule/schedule-store.js";
12
+ import {
13
+ createSchedule,
14
+ createScheduleRun,
15
+ } from "../schedule/schedule-store.js";
13
16
  import { scheduleTask } from "../tasks/task-scheduler.js";
14
17
  import { createTask } from "../tasks/task-store.js";
15
18
 
@@ -160,3 +163,130 @@ describe("schedule run-now trust propagation", () => {
160
163
  expect(fakeConversation.taskRunId).toBeUndefined();
161
164
  });
162
165
  });
166
+
167
+ // ── schedules/:id/runs limit handling ─────────────────────────────────────
168
+
169
+ function getRunsHandler() {
170
+ const route = scheduleRouteDefinitions({
171
+ sendMessageDeps: {} as never,
172
+ }).find(
173
+ (candidate) =>
174
+ candidate.endpoint === "schedules/:id/runs" &&
175
+ candidate.method === "GET",
176
+ );
177
+ if (!route) throw new Error("Runs schedule route not found");
178
+ return route.handler;
179
+ }
180
+
181
+ async function callRunsHandler(
182
+ jobId: string,
183
+ limitParam?: string,
184
+ ): Promise<{ status: number; body: unknown }> {
185
+ const handler = getRunsHandler();
186
+ const suffix = limitParam !== undefined ? `?limit=${limitParam}` : "";
187
+ const urlStr = `http://localhost/v1/schedules/${jobId}/runs${suffix}`;
188
+ const response = await handler({
189
+ req: new Request(urlStr),
190
+ url: new URL(urlStr),
191
+ server: {} as never,
192
+ authContext: {} as never,
193
+ params: { id: jobId },
194
+ });
195
+ return { status: response.status, body: await response.json() };
196
+ }
197
+
198
+ describe("schedule runs list — limit handling", () => {
199
+ beforeEach(() => {
200
+ clearTables();
201
+ });
202
+
203
+ test("returns 200 with default limit when no param is provided", async () => {
204
+ const job = createSchedule({
205
+ name: "runs default",
206
+ cronExpression: "* * * * *",
207
+ message: "hi",
208
+ syntax: "cron",
209
+ });
210
+ for (let i = 0; i < 3; i += 1) {
211
+ createScheduleRun(job.id, `conv-${i}`);
212
+ }
213
+ const { status, body } = await callRunsHandler(job.id);
214
+ expect(status).toBe(200);
215
+ expect(Array.isArray((body as { runs: unknown[] }).runs)).toBe(true);
216
+ expect((body as { runs: unknown[] }).runs).toHaveLength(3);
217
+ });
218
+
219
+ test("non-numeric limit falls back to default (does not 500)", async () => {
220
+ const job = createSchedule({
221
+ name: "runs nan",
222
+ cronExpression: "* * * * *",
223
+ message: "hi",
224
+ syntax: "cron",
225
+ });
226
+ createScheduleRun(job.id, "conv");
227
+ const { status } = await callRunsHandler(job.id, "abc");
228
+ expect(status).toBe(200);
229
+ });
230
+
231
+ test("negative limit is clamped to 1 (does not bypass cap)", async () => {
232
+ const job = createSchedule({
233
+ name: "runs negative",
234
+ cronExpression: "* * * * *",
235
+ message: "hi",
236
+ syntax: "cron",
237
+ });
238
+ for (let i = 0; i < 5; i += 1) {
239
+ createScheduleRun(job.id, `conv-${i}`);
240
+ }
241
+ const { status, body } = await callRunsHandler(job.id, "-5");
242
+ expect(status).toBe(200);
243
+ // clamped to 1, not interpreted as "no limit"
244
+ expect((body as { runs: unknown[] }).runs).toHaveLength(1);
245
+ });
246
+
247
+ test("zero limit is clamped to 1", async () => {
248
+ const job = createSchedule({
249
+ name: "runs zero",
250
+ cronExpression: "* * * * *",
251
+ message: "hi",
252
+ syntax: "cron",
253
+ });
254
+ for (let i = 0; i < 3; i += 1) {
255
+ createScheduleRun(job.id, `conv-${i}`);
256
+ }
257
+ const { status, body } = await callRunsHandler(job.id, "0");
258
+ expect(status).toBe(200);
259
+ expect((body as { runs: unknown[] }).runs).toHaveLength(1);
260
+ });
261
+
262
+ test("limit above 100 is capped at 100", async () => {
263
+ const job = createSchedule({
264
+ name: "runs huge",
265
+ cronExpression: "* * * * *",
266
+ message: "hi",
267
+ syntax: "cron",
268
+ });
269
+ // 5 runs, requesting 9999 → bounded at 100, actual returns = 5
270
+ for (let i = 0; i < 5; i += 1) {
271
+ createScheduleRun(job.id, `conv-${i}`);
272
+ }
273
+ const { status, body } = await callRunsHandler(job.id, "9999");
274
+ expect(status).toBe(200);
275
+ expect((body as { runs: unknown[] }).runs).toHaveLength(5);
276
+ });
277
+
278
+ test("fractional limit is floored", async () => {
279
+ const job = createSchedule({
280
+ name: "runs frac",
281
+ cronExpression: "* * * * *",
282
+ message: "hi",
283
+ syntax: "cron",
284
+ });
285
+ for (let i = 0; i < 5; i += 1) {
286
+ createScheduleRun(job.id, `conv-${i}`);
287
+ }
288
+ const { status, body } = await callRunsHandler(job.id, "2.7");
289
+ expect(status).toBe(200);
290
+ expect((body as { runs: unknown[] }).runs).toHaveLength(2);
291
+ });
292
+ });
@@ -126,11 +126,7 @@ describe("scheduler RRULE execution", () => {
126
126
  processedMessages.push({ conversationId, message });
127
127
  };
128
128
 
129
- const scheduler = startScheduler(
130
- processMessage,
131
- () => {},
132
- () => {},
133
- );
129
+ const scheduler = startScheduler(processMessage, () => {});
134
130
  await new Promise((resolve) => setTimeout(resolve, 500));
135
131
  scheduler.stop();
136
132
 
@@ -170,11 +166,7 @@ describe("scheduler RRULE execution", () => {
170
166
  onMessage?.();
171
167
  };
172
168
 
173
- const scheduler = startScheduler(
174
- processMessage,
175
- () => {},
176
- () => {},
177
- );
169
+ const scheduler = startScheduler(processMessage, () => {});
178
170
  // The run_task path involves a dynamic import which can take >50ms in CI,
179
171
  // exceeding the patched setTimeout delay. Await the actual callback instead
180
172
  // of relying on a fixed timeout.
@@ -239,11 +231,7 @@ describe("scheduler RRULE execution", () => {
239
231
  };
240
232
 
241
233
  // First tick: the expired schedule should fire its final due run
242
- const scheduler1 = startScheduler(
243
- processMessage,
244
- () => {},
245
- () => {},
246
- );
234
+ const scheduler1 = startScheduler(processMessage, () => {});
247
235
  await new Promise((resolve) => setTimeout(resolve, 500));
248
236
  scheduler1.stop();
249
237
 
@@ -263,11 +251,7 @@ describe("scheduler RRULE execution", () => {
263
251
 
264
252
  // Second tick: the disabled schedule must NOT fire again
265
253
  processedMessages.length = 0;
266
- const scheduler2 = startScheduler(
267
- processMessage,
268
- () => {},
269
- () => {},
270
- );
254
+ const scheduler2 = startScheduler(processMessage, () => {});
271
255
  await new Promise((resolve) => setTimeout(resolve, 500));
272
256
  scheduler2.stop();
273
257
 
@@ -297,11 +281,7 @@ describe("scheduler RRULE execution", () => {
297
281
  processedMessages.push({ conversationId, message });
298
282
  };
299
283
 
300
- const scheduler = startScheduler(
301
- processMessage,
302
- () => {},
303
- () => {},
304
- );
284
+ const scheduler = startScheduler(processMessage, () => {});
305
285
  await new Promise((resolve) => setTimeout(resolve, 500));
306
286
  scheduler.stop();
307
287
 
@@ -361,11 +341,7 @@ describe("scheduler RRULE execution", () => {
361
341
  processedMessages.push(message);
362
342
  };
363
343
 
364
- const scheduler = startScheduler(
365
- processMessage,
366
- () => {},
367
- () => {},
368
- );
344
+ const scheduler = startScheduler(processMessage, () => {});
369
345
  await new Promise((resolve) => setTimeout(resolve, 500));
370
346
  scheduler.stop();
371
347
 
@@ -414,11 +390,7 @@ describe("scheduler RRULE execution", () => {
414
390
  processedMessages.push(message);
415
391
  };
416
392
 
417
- const scheduler = startScheduler(
418
- processMessage,
419
- () => {},
420
- () => {},
421
- );
393
+ const scheduler = startScheduler(processMessage, () => {});
422
394
  await new Promise((resolve) => setTimeout(resolve, 500));
423
395
  scheduler.stop();
424
396
 
@@ -497,11 +469,7 @@ describe("scheduler RRULE execution", () => {
497
469
  processedMessages.push(message);
498
470
  };
499
471
 
500
- const scheduler = startScheduler(
501
- processMessage,
502
- () => {},
503
- () => {},
504
- );
472
+ const scheduler = startScheduler(processMessage, () => {});
505
473
  await new Promise((resolve) => setTimeout(resolve, 500));
506
474
  scheduler.stop();
507
475
 
@@ -540,11 +508,7 @@ describe("scheduler RRULE execution", () => {
540
508
  const forcedDueAt = getSchedule(schedule.id)!.nextRunAt;
541
509
 
542
510
  const processMessage = async () => {};
543
- const scheduler = startScheduler(
544
- processMessage,
545
- () => {},
546
- () => {},
547
- );
511
+ const scheduler = startScheduler(processMessage, () => {});
548
512
  await new Promise((resolve) => setTimeout(resolve, 500));
549
513
  scheduler.stop();
550
514
 
@@ -575,11 +539,7 @@ describe("scheduler RRULE execution", () => {
575
539
  processedMessages.push({ conversationId, message });
576
540
  };
577
541
 
578
- const scheduler = startScheduler(
579
- processMessage,
580
- () => {},
581
- () => {},
582
- );
542
+ const scheduler = startScheduler(processMessage, () => {});
583
543
  await new Promise((resolve) => setTimeout(resolve, 500));
584
544
  scheduler.stop();
585
545
 
@@ -627,11 +587,7 @@ describe("scheduler RRULE execution", () => {
627
587
  notifyCalls.push(payload);
628
588
  };
629
589
 
630
- const scheduler = startScheduler(
631
- async () => {},
632
- notifyScheduleOneShot,
633
- () => {},
634
- );
590
+ const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
635
591
  await new Promise((resolve) => setTimeout(resolve, 500));
636
592
  scheduler.stop();
637
593
 
@@ -664,11 +620,7 @@ describe("scheduler RRULE execution", () => {
664
620
  throw new Error("Simulated failure");
665
621
  };
666
622
 
667
- const scheduler = startScheduler(
668
- processMessage,
669
- () => {},
670
- () => {},
671
- );
623
+ const scheduler = startScheduler(processMessage, () => {});
672
624
  await new Promise((resolve) => setTimeout(resolve, 500));
673
625
  scheduler.stop();
674
626
 
@@ -710,11 +662,7 @@ describe("scheduler RRULE execution", () => {
710
662
  notifyCalls.push(payload);
711
663
  };
712
664
 
713
- const scheduler = startScheduler(
714
- async () => {},
715
- notifyScheduleOneShot,
716
- () => {},
717
- );
665
+ const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
718
666
  await new Promise((resolve) => setTimeout(resolve, 500));
719
667
  scheduler.stop();
720
668
 
@@ -767,11 +715,7 @@ describe("scheduler RRULE execution", () => {
767
715
  notifyCalls.push(payload);
768
716
  };
769
717
 
770
- const scheduler = startScheduler(
771
- async () => {},
772
- notifyScheduleOneShot,
773
- () => {},
774
- );
718
+ const scheduler = startScheduler(async () => {}, notifyScheduleOneShot);
775
719
  await new Promise((resolve) => setTimeout(resolve, 500));
776
720
  scheduler.stop();
777
721
 
@@ -103,11 +103,7 @@ describe("scheduler conversation reuse", () => {
103
103
  processedMessages.push({ conversationId, message });
104
104
  };
105
105
 
106
- const scheduler1 = startScheduler(
107
- processMessage,
108
- () => {},
109
- () => {},
110
- );
106
+ const scheduler1 = startScheduler(processMessage, () => {});
111
107
  await new Promise((resolve) => setTimeout(resolve, 500));
112
108
  scheduler1.stop();
113
109
 
@@ -126,11 +122,7 @@ describe("scheduler conversation reuse", () => {
126
122
  forceScheduleDue(schedule.id);
127
123
  processedMessages.length = 0;
128
124
 
129
- const scheduler2 = startScheduler(
130
- processMessage,
131
- () => {},
132
- () => {},
133
- );
125
+ const scheduler2 = startScheduler(processMessage, () => {});
134
126
  await new Promise((resolve) => setTimeout(resolve, 500));
135
127
  scheduler2.stop();
136
128
 
@@ -168,11 +160,7 @@ describe("scheduler conversation reuse", () => {
168
160
  processedMessages.push({ conversationId, message });
169
161
  };
170
162
 
171
- const scheduler1 = startScheduler(
172
- processMessage,
173
- () => {},
174
- () => {},
175
- );
163
+ const scheduler1 = startScheduler(processMessage, () => {});
176
164
  await new Promise((resolve) => setTimeout(resolve, 500));
177
165
  scheduler1.stop();
178
166
 
@@ -183,11 +171,7 @@ describe("scheduler conversation reuse", () => {
183
171
  forceScheduleDue(schedule.id);
184
172
  processedMessages.length = 0;
185
173
 
186
- const scheduler2 = startScheduler(
187
- processMessage,
188
- () => {},
189
- () => {},
190
- );
174
+ const scheduler2 = startScheduler(processMessage, () => {});
191
175
  await new Promise((resolve) => setTimeout(resolve, 500));
192
176
  scheduler2.stop();
193
177
 
@@ -220,11 +204,7 @@ describe("scheduler conversation reuse", () => {
220
204
  processedMessages.push({ conversationId, message });
221
205
  };
222
206
 
223
- const scheduler1 = startScheduler(
224
- processMessage,
225
- () => {},
226
- () => {},
227
- );
207
+ const scheduler1 = startScheduler(processMessage, () => {});
228
208
  await new Promise((resolve) => setTimeout(resolve, 500));
229
209
  scheduler1.stop();
230
210
 
@@ -238,11 +218,7 @@ describe("scheduler conversation reuse", () => {
238
218
  forceScheduleDue(schedule.id);
239
219
  processedMessages.length = 0;
240
220
 
241
- const scheduler2 = startScheduler(
242
- processMessage,
243
- () => {},
244
- () => {},
245
- );
221
+ const scheduler2 = startScheduler(processMessage, () => {});
246
222
  await new Promise((resolve) => setTimeout(resolve, 500));
247
223
  scheduler2.stop();
248
224
 
@@ -273,11 +249,7 @@ describe("scheduler conversation reuse", () => {
273
249
  processedMessages.push({ conversationId, message });
274
250
  };
275
251
 
276
- const scheduler = startScheduler(
277
- processMessage,
278
- () => {},
279
- () => {},
280
- );
252
+ const scheduler = startScheduler(processMessage, () => {});
281
253
  await new Promise((resolve) => setTimeout(resolve, 500));
282
254
  scheduler.stop();
283
255
 
@@ -318,11 +290,7 @@ describe("scheduler conversation reuse", () => {
318
290
  if (shouldFail) throw new Error("Simulated failure");
319
291
  };
320
292
 
321
- const scheduler1 = startScheduler(
322
- processMessage,
323
- () => {},
324
- () => {},
325
- );
293
+ const scheduler1 = startScheduler(processMessage, () => {});
326
294
  await new Promise((resolve) => setTimeout(resolve, 500));
327
295
  scheduler1.stop();
328
296
 
@@ -334,11 +302,7 @@ describe("scheduler conversation reuse", () => {
334
302
  processedMessages.length = 0;
335
303
  shouldFail = true;
336
304
 
337
- const scheduler2 = startScheduler(
338
- processMessage,
339
- () => {},
340
- () => {},
341
- );
305
+ const scheduler2 = startScheduler(processMessage, () => {});
342
306
  await new Promise((resolve) => setTimeout(resolve, 500));
343
307
  scheduler2.stop();
344
308
 
@@ -352,11 +316,7 @@ describe("scheduler conversation reuse", () => {
352
316
  processedMessages.length = 0;
353
317
  shouldFail = false;
354
318
 
355
- const scheduler3 = startScheduler(
356
- processMessage,
357
- () => {},
358
- () => {},
359
- );
319
+ const scheduler3 = startScheduler(processMessage, () => {});
360
320
  await new Promise((resolve) => setTimeout(resolve, 500));
361
321
  scheduler3.stop();
362
322
 
@@ -2,7 +2,6 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
2
2
 
3
3
  import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
4
4
 
5
- const triggerMock = mock(async () => {});
6
5
  const scanTextMock = mock(() => [
7
6
  { type: "api_key", redactedValue: "sk-***redacted***" },
8
7
  ]);
@@ -18,12 +17,6 @@ mock.module("../config/loader.js", () => ({
18
17
  }),
19
18
  }));
20
19
 
21
- mock.module("../hooks/manager.js", () => ({
22
- getHookManager: () => ({
23
- trigger: triggerMock,
24
- }),
25
- }));
26
-
27
20
  mock.module("../security/secret-scanner.js", () => ({
28
21
  compileCustomPatterns: () => [],
29
22
  redactSecrets: (content: string) => content,
@@ -35,7 +28,6 @@ import { SecretDetectionHandler } from "../tools/secret-detection-handler.js";
35
28
  describe("SecretDetectionHandler under v2", () => {
36
29
  beforeEach(() => {
37
30
  _setOverridesForTesting({});
38
- triggerMock.mockClear();
39
31
  scanTextMock.mockClear();
40
32
  });
41
33
 
@@ -63,7 +55,6 @@ describe("SecretDetectionHandler under v2", () => {
63
55
  "allow",
64
56
  Date.now(),
65
57
  emitLifecycleEvent,
66
- (_toolName, input) => input,
67
58
  );
68
59
 
69
60
  expect(result.earlyReturn).toBe(true);
@@ -79,6 +70,5 @@ describe("SecretDetectionHandler under v2", () => {
79
70
  decision: "deny",
80
71
  }),
81
72
  );
82
- expect(triggerMock).toHaveBeenCalled();
83
73
  });
84
74
  });
@@ -2,8 +2,6 @@ import { beforeAll, describe, expect, test } from "bun:test";
2
2
 
3
3
  import {
4
4
  analyzeShellCommand,
5
- buildShellAllowlistOptions,
6
- buildShellCommandCandidates,
7
5
  deriveShellActionKeys,
8
6
  } from "../permissions/shell-identity.js";
9
7
  import { parse } from "../tools/terminal/parser.js";
@@ -236,135 +234,3 @@ describe("deriveShellActionKeys", () => {
236
234
  });
237
235
  });
238
236
 
239
- describe("buildShellCommandCandidates", () => {
240
- test("raw candidate is always present", async () => {
241
- const candidates = await buildShellCommandCandidates("ls -la");
242
- expect(candidates[0]).toBe("ls -la");
243
- });
244
-
245
- test("simple action adds canonical and action candidates", async () => {
246
- const candidates = await buildShellCommandCandidates(
247
- "cd repo && gh pr view 5525 --json title",
248
- );
249
- expect(candidates[0]).toBe("cd repo && gh pr view 5525 --json title");
250
- // Should include the canonical primary command
251
- expect(candidates).toContain("gh pr view 5525 --json title");
252
- // Should include action keys
253
- expect(candidates).toContain("action:gh pr view");
254
- expect(candidates).toContain("action:gh pr");
255
- expect(candidates).toContain("action:gh");
256
- });
257
-
258
- test("complex command returns raw-only", async () => {
259
- const candidates = await buildShellCommandCandidates(
260
- 'git add . && git commit -m "fix"',
261
- );
262
- expect(candidates).toEqual(['git add . && git commit -m "fix"']);
263
- });
264
-
265
- test("pipeline returns raw and action key candidates", async () => {
266
- const candidates = await buildShellCommandCandidates("git log | grep fix");
267
- expect(candidates[0]).toBe("git log | grep fix");
268
- expect(candidates).toContain("action:git log");
269
- expect(candidates).toContain("action:git");
270
- });
271
-
272
- test("pipeline with setup prefix includes action candidates", async () => {
273
- const candidates = await buildShellCommandCandidates(
274
- "cd /tmp && pdftotext file.pdf | wc -c",
275
- );
276
- expect(candidates[0]).toBe("cd /tmp && pdftotext file.pdf | wc -c");
277
- expect(candidates).toContain("action:pdftotext");
278
- });
279
-
280
- test("candidate order is stable", async () => {
281
- const c1 = await buildShellCommandCandidates("npm install express");
282
- const c2 = await buildShellCommandCandidates("npm install express");
283
- expect(c1).toEqual(c2);
284
- });
285
-
286
- test("empty command returns raw", async () => {
287
- const candidates = await buildShellCommandCandidates("");
288
- expect(candidates).toEqual([""]);
289
- });
290
-
291
- test("semicolon chain returns raw-only", async () => {
292
- const candidates = await buildShellCommandCandidates(
293
- "cd repo; gh pr view 123",
294
- );
295
- expect(candidates).toHaveLength(1);
296
- });
297
-
298
- test("deduplication preserves order", async () => {
299
- // Single command — raw and canonical are the same
300
- const candidates = await buildShellCommandCandidates("git status");
301
- // raw is 'git status', canonical would also be 'git status' (same segment)
302
- // so it should be deduped to just once
303
- const gitStatusCount = candidates.filter((c) => c === "git status").length;
304
- expect(gitStatusCount).toBe(1);
305
- });
306
- });
307
-
308
- describe("buildShellAllowlistOptions — complex command restrictions", () => {
309
- test("chain with && offers exact only", async () => {
310
- const options = await buildShellAllowlistOptions(
311
- "gh pr view 123 && rm -rf /",
312
- );
313
- expect(options).toHaveLength(1);
314
- expect(options[0].pattern).toBe("gh pr view 123 && rm -rf /");
315
- expect(options[0].description).toContain("compound");
316
- });
317
-
318
- test("pipeline offers exact and action-key options", async () => {
319
- const options = await buildShellAllowlistOptions(
320
- "cat file.txt | grep error | wc -l",
321
- );
322
- expect(options.length).toBeGreaterThanOrEqual(2);
323
- expect(options[0].pattern).toBe("cat file.txt | grep error | wc -l");
324
- expect(options[0].description).toContain("compound");
325
- expect(options.some((o) => o.pattern.startsWith("action:"))).toBe(true);
326
- });
327
-
328
- test("pipeline offers action-key options from first segment", async () => {
329
- const options = await buildShellAllowlistOptions(
330
- "pdftotext file.pdf | head -100",
331
- );
332
- expect(options.length).toBeGreaterThanOrEqual(2);
333
- expect(options[0].pattern).toBe("pdftotext file.pdf | head -100");
334
- expect(
335
- options.some(
336
- (o) =>
337
- o.pattern === "action:pdftotext" &&
338
- o.description.includes('Any "pdftotext" command'),
339
- ),
340
- ).toBe(true);
341
- });
342
-
343
- test("semicolon chain offers exact only", async () => {
344
- const options = await buildShellAllowlistOptions("cd repo; gh pr view 123");
345
- expect(options).toHaveLength(1);
346
- expect(options[0].description).toContain("compound");
347
- });
348
-
349
- test("newline-separated commands offer exact only", async () => {
350
- const options = await buildShellAllowlistOptions("cd repo\ngh pr view 123");
351
- expect(options).toHaveLength(1);
352
- expect(options[0].description).toContain("compound");
353
- });
354
-
355
- test("setup-prefix + single-action still gets action-key options", async () => {
356
- const options = await buildShellAllowlistOptions(
357
- "cd /repo && npm install express",
358
- );
359
- expect(options.length).toBeGreaterThan(1);
360
- expect(options.some((o) => o.pattern.startsWith("action:"))).toBe(true);
361
- });
362
-
363
- test("simple single command gets action-key options", async () => {
364
- const options = await buildShellAllowlistOptions("npm install express");
365
- expect(options.length).toBeGreaterThan(1);
366
- expect(options[0].pattern).toBe("npm install express");
367
- expect(options.some((o) => o.pattern === "action:npm install")).toBe(true);
368
- expect(options.some((o) => o.pattern === "action:npm")).toBe(true);
369
- });
370
- });