@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.
- package/AGENTS.md +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- 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 {
|
|
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
|
-
});
|