@vellumai/assistant 0.5.5 → 0.5.7
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/.env.example +16 -2
- package/ARCHITECTURE.md +6 -75
- package/Dockerfile +4 -5
- package/README.md +0 -2
- package/bun.lock +0 -414
- package/docs/architecture/keychain-broker.md +45 -240
- package/docs/architecture/security.md +0 -17
- package/docs/credential-execution-service.md +2 -2
- package/node_modules/@vellumai/ces-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +119 -0
- package/node_modules/@vellumai/credential-storage/package.json +1 -0
- package/node_modules/@vellumai/egress-proxy/package.json +1 -0
- package/package.json +2 -3
- package/src/__tests__/actor-token-service.test.ts +1 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +30 -29
- package/src/__tests__/browser-skill-endstate.test.ts +6 -5
- package/src/__tests__/btw-routes.test.ts +0 -39
- package/src/__tests__/call-domain.test.ts +0 -128
- package/src/__tests__/ces-rpc-credential-backend.test.ts +199 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -5
- package/src/__tests__/channel-readiness-service.test.ts +1 -60
- package/src/__tests__/checker.test.ts +4 -2
- package/src/__tests__/cli-command-risk-guard.test.ts +112 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +3 -3
- package/src/__tests__/context-window-manager.test.ts +78 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -5
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-skill-tools.test.ts +0 -54
- package/src/__tests__/conversation-title-service.test.ts +117 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +28 -14
- package/src/__tests__/credential-execution-managed-contract.test.ts +33 -18
- package/src/__tests__/credential-security-e2e.test.ts +0 -66
- package/src/__tests__/credential-security-invariants.test.ts +4 -45
- package/src/__tests__/credentials-cli.test.ts +78 -0
- package/src/__tests__/db-migration-rollback.test.ts +2015 -1
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +98 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +6 -4
- package/src/__tests__/guardian-routing-state.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -7
- package/src/__tests__/http-user-message-parity.test.ts +3 -103
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -4
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -8
- package/src/__tests__/intent-routing.test.ts +0 -13
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +178 -0
- package/src/__tests__/keychain-broker-client.test.ts +161 -22
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +150 -0
- package/src/__tests__/memory-regressions.test.ts +8 -30
- package/src/__tests__/migration-export-http.test.ts +2 -2
- package/src/__tests__/migration-import-commit-http.test.ts +2 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +2 -2
- package/src/__tests__/migration-validate-http.test.ts +2 -2
- package/src/__tests__/non-member-access-request.test.ts +0 -5
- package/src/__tests__/notification-decision-fallback.test.ts +4 -0
- package/src/__tests__/notification-decision-identity.test.ts +4 -0
- package/src/__tests__/permission-types.test.ts +1 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +5 -6
- package/src/__tests__/qdrant-manager.test.ts +28 -2
- package/src/__tests__/registry.test.ts +0 -6
- package/src/__tests__/require-fresh-approval.test.ts +4 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -4
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -4
- package/src/__tests__/secure-keys.test.ts +83 -263
- package/src/__tests__/shell-identity.test.ts +96 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +22 -14
- package/src/__tests__/skill-feature-flags.test.ts +46 -45
- package/src/__tests__/skill-load-feature-flag.test.ts +7 -10
- package/src/__tests__/skill-load-inline-command.test.ts +8 -12
- package/src/__tests__/skill-load-inline-includes.test.ts +6 -10
- package/src/__tests__/skill-load-tool.test.ts +0 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +33 -29
- package/src/__tests__/skills.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +0 -4
- package/src/__tests__/suggestion-routes.test.ts +1 -32
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +5 -3
- package/src/__tests__/tool-executor.test.ts +4 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -5
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -4
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +6 -9
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -6
- package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +252 -0
- package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +218 -0
- package/src/__tests__/workspace-migration-down-functions.test.ts +1009 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +114 -0
- package/src/calls/audio-store.test.ts +97 -0
- package/src/calls/audio-store.ts +205 -0
- package/src/calls/call-controller.ts +85 -7
- package/src/calls/call-domain.ts +3 -0
- package/src/calls/call-store.ts +10 -3
- package/src/calls/fish-audio-client.ts +117 -0
- package/src/calls/relay-server.ts +27 -0
- package/src/calls/twilio-routes.ts +2 -1
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-ingress-preflight.ts +0 -42
- package/src/calls/voice-quality.ts +26 -5
- package/src/calls/voice-session-bridge.ts +6 -12
- package/src/cli/commands/config.ts +1 -4
- package/src/cli/commands/conversations.ts +0 -18
- package/src/cli/commands/credentials.ts +34 -4
- package/src/cli/commands/oauth/index.ts +7 -0
- package/src/cli/commands/oauth/platform.ts +179 -0
- package/src/cli/commands/platform.ts +3 -3
- package/src/config/assistant-feature-flags.ts +186 -5
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/phone-calls/TOOLS.json +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +42 -0
- package/src/config/bundled-tool-registry.ts +1 -11
- package/src/config/env-registry.ts +1 -1
- package/src/config/env.ts +16 -16
- package/src/config/feature-flag-registry.json +48 -16
- package/src/config/loader.ts +98 -31
- package/src/config/schema.ts +4 -25
- package/src/config/schemas/calls.ts +13 -0
- package/src/config/schemas/fish-audio.ts +39 -0
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/platform.ts +1 -1
- package/src/config/schemas/security.ts +4 -4
- package/src/config/types.ts +0 -1
- package/src/contacts/contact-store.ts +39 -0
- package/src/contacts/types.ts +2 -0
- package/src/context/window-manager.ts +53 -2
- package/src/credential-execution/approval-bridge.ts +1 -0
- package/src/credential-execution/executable-discovery.ts +28 -4
- package/src/credential-execution/feature-gates.ts +16 -0
- package/src/credential-execution/process-manager.ts +38 -0
- package/src/daemon/assistant-attachments.ts +9 -0
- package/src/daemon/config-watcher.ts +6 -4
- package/src/daemon/conversation-agent-loop.ts +0 -60
- package/src/daemon/conversation-memory.ts +0 -117
- package/src/daemon/conversation-runtime-assembly.ts +0 -2
- package/src/daemon/conversation-tool-setup.ts +0 -105
- package/src/daemon/conversation.ts +10 -1
- package/src/daemon/handlers/config-vercel.ts +92 -0
- package/src/daemon/handlers/conversations.ts +0 -11
- package/src/daemon/handlers/skills.ts +2 -15
- package/src/daemon/install-symlink.ts +195 -0
- package/src/daemon/lifecycle.ts +229 -96
- package/src/daemon/message-types/conversations.ts +3 -4
- package/src/daemon/message-types/diagnostics.ts +3 -22
- package/src/daemon/message-types/messages.ts +0 -2
- package/src/daemon/message-types/upgrades.ts +8 -0
- package/src/daemon/server.ts +30 -92
- package/src/events/domain-events.ts +2 -1
- package/src/followups/followup-store.ts +5 -2
- package/src/inbound/platform-callback-registration.ts +3 -3
- package/src/instrument.ts +8 -5
- package/src/memory/conversation-crud.ts +0 -236
- package/src/memory/conversation-title-service.ts +76 -11
- package/src/memory/db-init.ts +15 -11
- package/src/memory/indexer.ts +15 -106
- package/src/memory/items-extractor.ts +15 -1
- package/src/memory/job-handlers/conversation-starters.ts +4 -1
- package/src/memory/job-handlers/embedding.ts +0 -79
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +30 -13
- package/src/memory/jobs-worker.ts +31 -27
- package/src/memory/migrations/001-job-deferrals.ts +19 -0
- package/src/memory/migrations/004-entity-relation-dedup.ts +10 -0
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +76 -0
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +50 -0
- package/src/memory/migrations/007-assistant-id-to-self.ts +10 -0
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +34 -0
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +26 -0
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +10 -0
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -0
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +12 -0
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +121 -0
- package/src/memory/migrations/024-embedding-vector-blob.ts +74 -0
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +82 -0
- package/src/memory/migrations/036-normalize-phone-identities.ts +11 -0
- package/src/memory/migrations/116-messages-fts.ts +106 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +52 -0
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +77 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +13 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +20 -0
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +13 -0
- package/src/memory/migrations/141-rename-verification-table.ts +54 -0
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +25 -0
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +35 -0
- package/src/memory/migrations/144-rename-voice-to-phone.ts +136 -0
- package/src/memory/migrations/145-drop-accounts-table.ts +32 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +14 -1
- package/src/memory/migrations/148-drop-reminders-table.ts +35 -1
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +69 -1
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +290 -0
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +51 -1
- package/src/memory/migrations/174-rename-thread-starters-table.ts +47 -1
- package/src/memory/migrations/176-drop-capability-card-state.ts +13 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +16 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +28 -1
- package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
- package/src/memory/migrations/190-call-session-skip-disclosure.ts +15 -0
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +64 -0
- package/src/memory/migrations/192-contacts-user-file-column.ts +15 -0
- package/src/memory/migrations/index.ts +5 -3
- package/src/memory/migrations/registry.ts +90 -0
- package/src/memory/migrations/validate-migration-state.ts +137 -11
- package/src/memory/qdrant-circuit-breaker.ts +9 -0
- package/src/memory/qdrant-client.ts +4 -6
- package/src/memory/qdrant-manager.ts +64 -7
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/conversations.ts +0 -3
- package/src/memory/schema/index.ts +0 -2
- package/src/messaging/draft-store.ts +2 -2
- package/src/notifications/decision-engine.ts +4 -1
- package/src/oauth/connection-resolver.ts +6 -4
- package/src/permissions/checker.ts +0 -38
- package/src/permissions/defaults.ts +3 -3
- package/src/permissions/shell-identity.ts +76 -22
- package/src/permissions/trust-client.ts +2 -13
- package/src/permissions/trust-store.ts +8 -3
- package/src/permissions/types.ts +4 -2
- package/src/platform/client.ts +35 -7
- package/src/prompts/persona-resolver.ts +138 -0
- package/src/prompts/system-prompt.ts +36 -4
- package/src/prompts/templates/users/default.md +1 -0
- package/src/providers/registry.ts +27 -40
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/external-assistant-id.test.ts +13 -68
- package/src/runtime/auth/external-assistant-id.ts +13 -59
- package/src/runtime/auth/route-policy.ts +29 -1
- package/src/runtime/auth/token-service.ts +53 -15
- package/src/runtime/channel-readiness-service.ts +1 -16
- package/src/runtime/http-server.ts +29 -2
- package/src/runtime/middleware/error-handler.ts +1 -9
- package/src/runtime/routes/audio-routes.ts +40 -0
- package/src/runtime/routes/btw-routes.ts +0 -17
- package/src/runtime/routes/conversation-management-routes.ts +0 -36
- package/src/runtime/routes/conversation-query-routes.ts +106 -2
- package/src/runtime/routes/conversation-routes.ts +4 -43
- package/src/runtime/routes/diagnostics-routes.ts +1 -477
- package/src/runtime/routes/identity-routes.ts +18 -29
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -33
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +1 -1
- package/src/runtime/routes/integrations/vercel.ts +89 -0
- package/src/runtime/routes/log-export-routes.ts +5 -0
- package/src/runtime/routes/memory-item-routes.test.ts +221 -3
- package/src/runtime/routes/memory-item-routes.ts +144 -4
- package/src/runtime/routes/migration-rollback-routes.ts +209 -0
- package/src/runtime/routes/migration-routes.ts +17 -1
- package/src/runtime/routes/notification-routes.ts +58 -0
- package/src/runtime/routes/schedule-routes.ts +65 -0
- package/src/runtime/routes/settings-routes.ts +41 -1
- package/src/runtime/routes/tts-routes.ts +86 -0
- package/src/runtime/routes/upgrade-broadcast-routes.ts +175 -0
- package/src/runtime/routes/workspace-commit-routes.ts +62 -0
- package/src/runtime/routes/workspace-routes.test.ts +22 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +86 -2
- package/src/schedule/schedule-store.ts +0 -21
- package/src/security/ces-credential-client.ts +59 -22
- package/src/security/ces-rpc-credential-backend.ts +85 -0
- package/src/security/credential-backend.ts +12 -88
- package/src/security/keychain-broker-client.ts +10 -2
- package/src/security/secure-keys.ts +94 -113
- package/src/skills/catalog-install.ts +13 -7
- package/src/skills/inline-command-render.ts +5 -1
- package/src/skills/inline-command-runner.ts +30 -2
- package/src/telemetry/usage-telemetry-reporter.ts +4 -2
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/executor.ts +0 -4
- package/src/tools/memory/handlers.ts +1 -129
- package/src/tools/network/script-proxy/session-manager.ts +19 -4
- package/src/tools/network/web-fetch.ts +3 -1
- package/src/tools/permission-checker.ts +18 -0
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +9 -2
- package/src/tools/types.ts +0 -8
- package/src/util/errors.ts +0 -12
- package/src/util/platform.ts +8 -55
- package/src/util/xml.ts +8 -0
- package/src/workspace/git-service.ts +5 -2
- package/src/workspace/heartbeat-service.ts +5 -24
- package/src/workspace/migrations/001-avatar-rename.ts +15 -0
- package/src/workspace/migrations/003-seed-device-id.ts +17 -1
- package/src/workspace/migrations/004-extract-collect-usage-data.ts +33 -0
- package/src/workspace/migrations/005-add-send-diagnostics.ts +3 -0
- package/src/workspace/migrations/006-services-config.ts +49 -0
- package/src/workspace/migrations/007-web-search-provider-rename.ts +27 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +3 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +4 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +78 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +11 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +44 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +5 -0
- package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +153 -0
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +156 -0
- package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +150 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +95 -0
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +23 -1
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/migrations/runner.ts +106 -2
- package/src/workspace/migrations/types.ts +4 -0
- package/src/__tests__/archive-recall.test.ts +0 -560
- package/src/__tests__/claude-code-skill-regression.test.ts +0 -206
- package/src/__tests__/claude-code-tool-profiles.test.ts +0 -99
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
- package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
- package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
- package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
- package/src/__tests__/diagnostics-export.test.ts +0 -288
- package/src/__tests__/local-gateway-health.test.ts +0 -209
- package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
- package/src/__tests__/memory-brief-time.test.ts +0 -285
- package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
- package/src/__tests__/memory-chunk-archive.test.ts +0 -400
- package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
- package/src/__tests__/memory-episode-archive.test.ts +0 -370
- package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
- package/src/__tests__/memory-observation-archive.test.ts +0 -375
- package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
- package/src/__tests__/memory-reducer-job.test.ts +0 -538
- package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
- package/src/__tests__/memory-reducer-store.test.ts +0 -728
- package/src/__tests__/memory-reducer-types.test.ts +0 -707
- package/src/__tests__/memory-reducer.test.ts +0 -704
- package/src/__tests__/memory-simplified-config.test.ts +0 -281
- package/src/__tests__/secret-ingress-handler.test.ts +0 -120
- package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
- package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
- package/src/__tests__/swarm-conversation-integration.test.ts +0 -358
- package/src/__tests__/swarm-dag-pathological.test.ts +0 -547
- package/src/__tests__/swarm-orchestrator.test.ts +0 -463
- package/src/__tests__/swarm-plan-validator.test.ts +0 -384
- package/src/__tests__/swarm-recursion.test.ts +0 -197
- package/src/__tests__/swarm-router-planner.test.ts +0 -234
- package/src/__tests__/swarm-tool.test.ts +0 -185
- package/src/__tests__/swarm-worker-backend.test.ts +0 -144
- package/src/__tests__/swarm-worker-runner.test.ts +0 -288
- package/src/commands/__tests__/cc-command-registry.test.ts +0 -396
- package/src/commands/cc-command-registry.ts +0 -248
- package/src/config/bundled-skills/claude-code/SKILL.md +0 -53
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -47
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +0 -12
- package/src/config/bundled-skills/orchestration/SKILL.md +0 -33
- package/src/config/bundled-skills/orchestration/TOOLS.json +0 -35
- package/src/config/bundled-skills/orchestration/tools/swarm-delegate.ts +0 -12
- package/src/config/schemas/memory-simplified.ts +0 -101
- package/src/config/schemas/swarm.ts +0 -82
- package/src/logfire.ts +0 -135
- package/src/memory/archive-recall.ts +0 -516
- package/src/memory/archive-store.ts +0 -400
- package/src/memory/brief-formatting.ts +0 -33
- package/src/memory/brief-open-loops.ts +0 -266
- package/src/memory/brief-time.ts +0 -162
- package/src/memory/brief.ts +0 -75
- package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
- package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
- package/src/memory/migrations/185-memory-brief-state.ts +0 -52
- package/src/memory/migrations/186-memory-archive.ts +0 -109
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
- package/src/memory/reducer-scheduler.ts +0 -242
- package/src/memory/reducer-store.ts +0 -271
- package/src/memory/reducer-types.ts +0 -106
- package/src/memory/reducer.ts +0 -467
- package/src/memory/schema/memory-archive.ts +0 -121
- package/src/memory/schema/memory-brief.ts +0 -55
- package/src/runtime/local-gateway-health.ts +0 -275
- package/src/security/secret-ingress.ts +0 -68
- package/src/swarm/backend-claude-code.ts +0 -225
- package/src/swarm/checkpoint.ts +0 -137
- package/src/swarm/graph-utils.ts +0 -53
- package/src/swarm/index.ts +0 -55
- package/src/swarm/limits.ts +0 -66
- package/src/swarm/orchestrator.ts +0 -424
- package/src/swarm/plan-validator.ts +0 -117
- package/src/swarm/router-planner.ts +0 -162
- package/src/swarm/router-prompts.ts +0 -39
- package/src/swarm/synthesizer.ts +0 -81
- package/src/swarm/types.ts +0 -72
- package/src/swarm/worker-backend.ts +0 -131
- package/src/swarm/worker-prompts.ts +0 -80
- package/src/swarm/worker-runner.ts +0 -170
- package/src/tools/claude-code/claude-code.ts +0 -610
- package/src/tools/swarm/delegate.ts +0 -205
|
@@ -82,12 +82,76 @@ describe("deriveShellActionKeys", () => {
|
|
|
82
82
|
]);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
test("pipelines are marked non-simple", async () => {
|
|
85
|
+
test("pipelines are marked non-simple but produce action keys", async () => {
|
|
86
86
|
const analysis = await analyzeShellCommand("git log | grep fix");
|
|
87
87
|
const result = deriveShellActionKeys(analysis);
|
|
88
88
|
|
|
89
89
|
expect(result.isSimpleAction).toBe(false);
|
|
90
|
-
expect(result.keys).
|
|
90
|
+
expect(result.keys).toEqual([
|
|
91
|
+
{ key: "action:git log", depth: 2 },
|
|
92
|
+
{ key: "action:git", depth: 1 },
|
|
93
|
+
]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("pipeline extracts action keys from first segment", async () => {
|
|
97
|
+
const analysis = await analyzeShellCommand(
|
|
98
|
+
"pdftotext file.pdf | head -100",
|
|
99
|
+
);
|
|
100
|
+
const result = deriveShellActionKeys(analysis);
|
|
101
|
+
|
|
102
|
+
expect(result.isSimpleAction).toBe(false);
|
|
103
|
+
// file.pdf is treated as a subcommand token (doesn't start with . or contain /)
|
|
104
|
+
expect(result.keys).toEqual([
|
|
105
|
+
{ key: "action:pdftotext file.pdf", depth: 2 },
|
|
106
|
+
{ key: "action:pdftotext", depth: 1 },
|
|
107
|
+
]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("setup-prefix + pipeline extracts action keys", async () => {
|
|
111
|
+
const analysis = await analyzeShellCommand(
|
|
112
|
+
"cd /tmp && pdftotext file.pdf | grep oil",
|
|
113
|
+
);
|
|
114
|
+
const result = deriveShellActionKeys(analysis);
|
|
115
|
+
|
|
116
|
+
expect(result.isSimpleAction).toBe(false);
|
|
117
|
+
expect(result.keys).toEqual([
|
|
118
|
+
{ key: "action:pdftotext file.pdf", depth: 2 },
|
|
119
|
+
{ key: "action:pdftotext", depth: 1 },
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("pipeline with subcommand extracts deeper keys", async () => {
|
|
124
|
+
const analysis = await analyzeShellCommand("cd repo && gh pr list | head");
|
|
125
|
+
const result = deriveShellActionKeys(analysis);
|
|
126
|
+
|
|
127
|
+
expect(result.isSimpleAction).toBe(false);
|
|
128
|
+
expect(result.keys).toEqual([
|
|
129
|
+
{ key: "action:gh pr list", depth: 3 },
|
|
130
|
+
{ key: "action:gh pr", depth: 2 },
|
|
131
|
+
{ key: "action:gh", depth: 1 },
|
|
132
|
+
]);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("multi-pipe pipeline extracts first segment only", async () => {
|
|
136
|
+
const analysis = await analyzeShellCommand("cat file | grep error | wc -l");
|
|
137
|
+
const result = deriveShellActionKeys(analysis);
|
|
138
|
+
|
|
139
|
+
expect(result.isSimpleAction).toBe(false);
|
|
140
|
+
expect(result.keys).toEqual([
|
|
141
|
+
{ key: "action:cat file", depth: 2 },
|
|
142
|
+
{ key: "action:cat", depth: 1 },
|
|
143
|
+
]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("dangerous pipe_to_shell still extracts keys", async () => {
|
|
147
|
+
const analysis = await analyzeShellCommand("curl url | bash");
|
|
148
|
+
const result = deriveShellActionKeys(analysis);
|
|
149
|
+
|
|
150
|
+
expect(result.isSimpleAction).toBe(false);
|
|
151
|
+
expect(result.keys).toEqual([
|
|
152
|
+
{ key: "action:curl url", depth: 2 },
|
|
153
|
+
{ key: "action:curl", depth: 1 },
|
|
154
|
+
]);
|
|
91
155
|
});
|
|
92
156
|
|
|
93
157
|
test("complex chains with multiple actions are non-simple", async () => {
|
|
@@ -198,9 +262,19 @@ describe("buildShellCommandCandidates", () => {
|
|
|
198
262
|
expect(candidates).toEqual(['git add . && git commit -m "fix"']);
|
|
199
263
|
});
|
|
200
264
|
|
|
201
|
-
test("pipeline returns raw
|
|
265
|
+
test("pipeline returns raw and action key candidates", async () => {
|
|
202
266
|
const candidates = await buildShellCommandCandidates("git log | grep fix");
|
|
203
|
-
expect(candidates).
|
|
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");
|
|
204
278
|
});
|
|
205
279
|
|
|
206
280
|
test("candidate order is stable", async () => {
|
|
@@ -241,13 +315,29 @@ describe("buildShellAllowlistOptions — complex command restrictions", () => {
|
|
|
241
315
|
expect(options[0].description).toContain("compound");
|
|
242
316
|
});
|
|
243
317
|
|
|
244
|
-
test("pipeline offers exact
|
|
318
|
+
test("pipeline offers exact and action-key options", async () => {
|
|
245
319
|
const options = await buildShellAllowlistOptions(
|
|
246
320
|
"cat file.txt | grep error | wc -l",
|
|
247
321
|
);
|
|
248
|
-
expect(options).
|
|
322
|
+
expect(options.length).toBeGreaterThanOrEqual(2);
|
|
249
323
|
expect(options[0].pattern).toBe("cat file.txt | grep error | wc -l");
|
|
250
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);
|
|
251
341
|
});
|
|
252
342
|
|
|
253
343
|
test("semicolon chain offers exact only", async () => {
|
|
@@ -5,9 +5,20 @@
|
|
|
5
5
|
* parses it via the real frontmatter parser, and verifies that `skillFlagKey()`
|
|
6
6
|
* returns the correct key and `resolveSkillStates()` correctly gates the skill.
|
|
7
7
|
*/
|
|
8
|
-
import { describe, expect, test } from "bun:test";
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
_setOverridesForTesting,
|
|
12
|
+
isAssistantFeatureFlagEnabled,
|
|
13
|
+
} from "../config/assistant-feature-flags.js";
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
_setOverridesForTesting({});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
_setOverridesForTesting({});
|
|
21
|
+
});
|
|
11
22
|
import type { AssistantConfig } from "../config/schema.js";
|
|
12
23
|
import { resolveSkillStates, skillFlagKey } from "../config/skill-state.js";
|
|
13
24
|
import type { SkillSummary } from "../config/skills.js";
|
|
@@ -150,12 +161,11 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
150
161
|
});
|
|
151
162
|
|
|
152
163
|
test("resolveSkillStates includes skill with featureFlag when flag is ON", () => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
assistantFeatureFlagValues: {
|
|
156
|
-
"feature_flags.contacts.enabled": true,
|
|
157
|
-
},
|
|
164
|
+
_setOverridesForTesting({
|
|
165
|
+
"feature_flags.contacts.enabled": true,
|
|
158
166
|
});
|
|
167
|
+
const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG)!;
|
|
168
|
+
const config = makeConfig();
|
|
159
169
|
|
|
160
170
|
const resolved = resolveSkillStates([skill], config);
|
|
161
171
|
expect(resolved.length).toBe(1);
|
|
@@ -165,11 +175,10 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
165
175
|
test("resolveSkillStates never gates skill without featureFlag", () => {
|
|
166
176
|
const skill = buildSkillSummary("plain-skill", SKILL_MD_WITHOUT_FLAG)!;
|
|
167
177
|
// Even with an explicit false override for this skill ID, it should pass through
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
"feature_flags.plain-skill.enabled": false,
|
|
171
|
-
},
|
|
178
|
+
_setOverridesForTesting({
|
|
179
|
+
"feature_flags.plain-skill.enabled": false,
|
|
172
180
|
});
|
|
181
|
+
const config = makeConfig();
|
|
173
182
|
|
|
174
183
|
const resolved = resolveSkillStates([skill], config);
|
|
175
184
|
expect(resolved.length).toBe(1);
|
|
@@ -203,9 +212,8 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
203
212
|
expect(resolvedDefault[0].summary.id).toBe("contacts");
|
|
204
213
|
|
|
205
214
|
// Step 6: With override disabled, skill is filtered out
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
215
|
+
_setOverridesForTesting({ [key!]: false });
|
|
216
|
+
const configOff = makeConfig();
|
|
209
217
|
expect(isAssistantFeatureFlagEnabled(key!, configOff)).toBe(false);
|
|
210
218
|
|
|
211
219
|
const resolvedOff = resolveSkillStates([skill], configOff);
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
_setOverridesForTesting,
|
|
5
|
+
isAssistantFeatureFlagEnabled,
|
|
6
|
+
} from "../config/assistant-feature-flags.js";
|
|
4
7
|
import type { AssistantConfig } from "../config/schema.js";
|
|
5
8
|
import { resolveSkillStates, skillFlagKey } from "../config/skill-state.js";
|
|
6
9
|
import type { SkillSummary } from "../config/skills.js";
|
|
7
10
|
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
_setOverridesForTesting({});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
_setOverridesForTesting({});
|
|
17
|
+
});
|
|
18
|
+
|
|
8
19
|
const DECLARED_FLAG_ID = "contacts";
|
|
9
20
|
const DECLARED_FLAG_KEY = `feature_flags.${DECLARED_FLAG_ID}.enabled`;
|
|
10
21
|
const DECLARED_SKILL_ID = "contacts";
|
|
@@ -92,9 +103,8 @@ describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
|
92
103
|
});
|
|
93
104
|
|
|
94
105
|
test("returns true when skill key is explicitly true", () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
106
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: true });
|
|
107
|
+
const config = makeConfig();
|
|
98
108
|
expect(
|
|
99
109
|
isAssistantFeatureFlagEnabled(
|
|
100
110
|
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
@@ -104,9 +114,8 @@ describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
|
104
114
|
});
|
|
105
115
|
|
|
106
116
|
test("returns false when skill key is explicitly false", () => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
117
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: false });
|
|
118
|
+
const config = makeConfig();
|
|
110
119
|
expect(
|
|
111
120
|
isAssistantFeatureFlagEnabled(
|
|
112
121
|
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
@@ -128,11 +137,9 @@ describe("isAssistantFeatureFlagEnabled", () => {
|
|
|
128
137
|
).toBe(true);
|
|
129
138
|
});
|
|
130
139
|
|
|
131
|
-
test("
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
135
|
-
} as AssistantConfig;
|
|
140
|
+
test("file-based override overrides registry default", () => {
|
|
141
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: false });
|
|
142
|
+
const config = makeConfig();
|
|
136
143
|
expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(
|
|
137
144
|
false,
|
|
138
145
|
);
|
|
@@ -145,9 +152,8 @@ describe("isAssistantFeatureFlagEnabled", () => {
|
|
|
145
152
|
});
|
|
146
153
|
|
|
147
154
|
test("respects persisted overrides for undeclared keys", () => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
});
|
|
155
|
+
_setOverridesForTesting({ "feature_flags.browser.enabled": false });
|
|
156
|
+
const config = makeConfig();
|
|
151
157
|
expect(
|
|
152
158
|
isAssistantFeatureFlagEnabled("feature_flags.browser.enabled", config),
|
|
153
159
|
).toBe(false);
|
|
@@ -168,16 +174,15 @@ describe("isAssistantFeatureFlagEnabled", () => {
|
|
|
168
174
|
|
|
169
175
|
describe("resolveSkillStates with feature flags", () => {
|
|
170
176
|
test("flag OFF skill does not appear in resolved list", () => {
|
|
177
|
+
_setOverridesForTesting({
|
|
178
|
+
[DECLARED_FLAG_KEY]: false,
|
|
179
|
+
"feature_flags.browser.enabled": true,
|
|
180
|
+
});
|
|
171
181
|
const catalog = [
|
|
172
182
|
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
173
183
|
makeSkill("browser", "bundled", "browser"),
|
|
174
184
|
];
|
|
175
|
-
const config = makeConfig(
|
|
176
|
-
assistantFeatureFlagValues: {
|
|
177
|
-
[DECLARED_FLAG_KEY]: false,
|
|
178
|
-
"feature_flags.browser.enabled": true,
|
|
179
|
-
},
|
|
180
|
-
});
|
|
185
|
+
const config = makeConfig();
|
|
181
186
|
|
|
182
187
|
const resolved = resolveSkillStates(catalog, config);
|
|
183
188
|
const ids = resolved.map((r) => r.summary.id);
|
|
@@ -187,16 +192,15 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
187
192
|
});
|
|
188
193
|
|
|
189
194
|
test("flag ON skill appears normally", () => {
|
|
195
|
+
_setOverridesForTesting({
|
|
196
|
+
[DECLARED_FLAG_KEY]: true,
|
|
197
|
+
"feature_flags.browser.enabled": true,
|
|
198
|
+
});
|
|
190
199
|
const catalog = [
|
|
191
200
|
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
192
201
|
makeSkill("browser", "bundled", "browser"),
|
|
193
202
|
];
|
|
194
|
-
const config = makeConfig(
|
|
195
|
-
assistantFeatureFlagValues: {
|
|
196
|
-
[DECLARED_FLAG_KEY]: true,
|
|
197
|
-
"feature_flags.browser.enabled": true,
|
|
198
|
-
},
|
|
199
|
-
});
|
|
203
|
+
const config = makeConfig();
|
|
200
204
|
|
|
201
205
|
const resolved = resolveSkillStates(catalog, config);
|
|
202
206
|
const ids = resolved.map((r) => r.summary.id);
|
|
@@ -227,9 +231,9 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
227
231
|
});
|
|
228
232
|
|
|
229
233
|
test("feature flag OFF takes precedence over user-enabled config entry", () => {
|
|
234
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: false });
|
|
230
235
|
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
231
236
|
const config = makeConfig({
|
|
232
|
-
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
233
237
|
skills: {
|
|
234
238
|
entries: { [DECLARED_SKILL_ID]: { enabled: true } },
|
|
235
239
|
load: { extraDirs: [], watch: true, watchDebounceMs: 250 },
|
|
@@ -253,18 +257,17 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
253
257
|
});
|
|
254
258
|
|
|
255
259
|
test("multiple skills with mixed flags — persisted overrides respected", () => {
|
|
260
|
+
_setOverridesForTesting({
|
|
261
|
+
[DECLARED_FLAG_KEY]: false,
|
|
262
|
+
"feature_flags.browser.enabled": true,
|
|
263
|
+
"feature_flags.deploy.enabled": false,
|
|
264
|
+
});
|
|
256
265
|
const catalog = [
|
|
257
266
|
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
258
267
|
makeSkill("browser", "bundled", "browser"),
|
|
259
268
|
makeSkill("deploy", "bundled", "deploy"),
|
|
260
269
|
];
|
|
261
|
-
const config = makeConfig(
|
|
262
|
-
assistantFeatureFlagValues: {
|
|
263
|
-
[DECLARED_FLAG_KEY]: false,
|
|
264
|
-
"feature_flags.browser.enabled": true,
|
|
265
|
-
"feature_flags.deploy.enabled": false,
|
|
266
|
-
},
|
|
267
|
-
});
|
|
270
|
+
const config = makeConfig();
|
|
268
271
|
|
|
269
272
|
const resolved = resolveSkillStates(catalog, config);
|
|
270
273
|
const ids = resolved.map((r) => r.summary.id);
|
|
@@ -290,11 +293,10 @@ describe("resolveSkillStates with frontmatter featureFlag", () => {
|
|
|
290
293
|
expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
|
|
291
294
|
});
|
|
292
295
|
|
|
293
|
-
test("skill with featureFlag is included when
|
|
296
|
+
test("skill with featureFlag is included when override enables it", () => {
|
|
297
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: true });
|
|
294
298
|
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
295
|
-
const config = makeConfig(
|
|
296
|
-
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: true },
|
|
297
|
-
});
|
|
299
|
+
const config = makeConfig();
|
|
298
300
|
|
|
299
301
|
const resolved = resolveSkillStates(catalog, config);
|
|
300
302
|
const ids = resolved.map((r) => r.summary.id);
|
|
@@ -316,12 +318,11 @@ describe("resolveSkillStates with frontmatter featureFlag", () => {
|
|
|
316
318
|
// This proves the implicit skillId→flag mapping is gone:
|
|
317
319
|
// setting feature_flags.my-skill.enabled = false has no effect
|
|
318
320
|
// when the skill itself does not declare a featureFlag.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
assistantFeatureFlagValues: {
|
|
322
|
-
"feature_flags.my-skill.enabled": false,
|
|
323
|
-
},
|
|
321
|
+
_setOverridesForTesting({
|
|
322
|
+
"feature_flags.my-skill.enabled": false,
|
|
324
323
|
});
|
|
324
|
+
const catalog = [makeSkill("my-skill")];
|
|
325
|
+
const config = makeConfig();
|
|
325
326
|
|
|
326
327
|
const resolved = resolveSkillStates(catalog, config);
|
|
327
328
|
const ids = resolved.map((r) => r.summary.id);
|
|
@@ -7,6 +7,8 @@ import { tmpdir } from "node:os";
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
9
9
|
|
|
10
|
+
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
11
|
+
|
|
10
12
|
const TEST_DIR = join(
|
|
11
13
|
tmpdir(),
|
|
12
14
|
`vellum-skill-load-flag-test-${crypto.randomUUID()}`,
|
|
@@ -75,7 +77,6 @@ mock.module("../config/loader.js", () => ({
|
|
|
75
77
|
invalidateConfigCache: () => {},
|
|
76
78
|
getNestedValue: () => undefined,
|
|
77
79
|
setNestedValue: () => {},
|
|
78
|
-
syncConfigToLockfile: () => {},
|
|
79
80
|
}));
|
|
80
81
|
|
|
81
82
|
await import("../tools/skills/load.js");
|
|
@@ -113,9 +114,11 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
113
114
|
beforeEach(() => {
|
|
114
115
|
mkdirSync(join(TEST_DIR, "skills"), { recursive: true });
|
|
115
116
|
currentConfig = {};
|
|
117
|
+
_setOverridesForTesting({});
|
|
116
118
|
});
|
|
117
119
|
|
|
118
120
|
afterEach(() => {
|
|
121
|
+
_setOverridesForTesting({});
|
|
119
122
|
if (existsSync(TEST_DIR)) {
|
|
120
123
|
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
121
124
|
}
|
|
@@ -133,9 +136,7 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
133
136
|
`- ${DECLARED_SKILL_ID}\n`,
|
|
134
137
|
);
|
|
135
138
|
|
|
136
|
-
|
|
137
|
-
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
138
|
-
};
|
|
139
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: false });
|
|
139
140
|
|
|
140
141
|
const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
|
|
141
142
|
|
|
@@ -156,9 +157,7 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
156
157
|
`- ${DECLARED_SKILL_ID}\n`,
|
|
157
158
|
);
|
|
158
159
|
|
|
159
|
-
|
|
160
|
-
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: true },
|
|
161
|
-
};
|
|
160
|
+
_setOverridesForTesting({ [DECLARED_FLAG_KEY]: true });
|
|
162
161
|
|
|
163
162
|
const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
|
|
164
163
|
|
|
@@ -178,9 +177,7 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
178
177
|
`- ${DECLARED_SKILL_ID}\n`,
|
|
179
178
|
);
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
assistantFeatureFlagValues: {},
|
|
183
|
-
};
|
|
180
|
+
// No overrides — uses registry defaults
|
|
184
181
|
|
|
185
182
|
const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
|
|
186
183
|
|
|
@@ -21,6 +21,8 @@ import { tmpdir } from "node:os";
|
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
23
23
|
|
|
24
|
+
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
25
|
+
|
|
24
26
|
// ── Test directory ────────────────────────────────────────────────────────────
|
|
25
27
|
|
|
26
28
|
const TEST_DIR = mkdtempSync(
|
|
@@ -50,9 +52,7 @@ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
|
|
|
50
52
|
getSessionTokenPath: () => join(TEST_DIR, "session-token"),
|
|
51
53
|
readSessionToken: () => null,
|
|
52
54
|
getClipboardCommand: () => null,
|
|
53
|
-
readLockfile: () => null,
|
|
54
55
|
normalizeAssistantId: (id: unknown) => String(id),
|
|
55
|
-
writeLockfile: () => {},
|
|
56
56
|
getEmbeddingModelsDir: () => join(TEST_DIR, "embedding-models"),
|
|
57
57
|
getTCPPort: () => 8765,
|
|
58
58
|
isTCPEnabled: () => false,
|
|
@@ -127,7 +127,6 @@ interface TestConfig {
|
|
|
127
127
|
permissions: { mode: "strict" | "workspace" };
|
|
128
128
|
skills: { load: { extraDirs: string[] } };
|
|
129
129
|
sandbox: { enabled: boolean };
|
|
130
|
-
assistantFeatureFlagValues?: Record<string, boolean>;
|
|
131
130
|
[key: string]: unknown;
|
|
132
131
|
}
|
|
133
132
|
|
|
@@ -135,9 +134,6 @@ const testConfig: TestConfig = {
|
|
|
135
134
|
permissions: { mode: "workspace" },
|
|
136
135
|
skills: { load: { extraDirs: [] } },
|
|
137
136
|
sandbox: { enabled: true },
|
|
138
|
-
assistantFeatureFlagValues: {
|
|
139
|
-
"feature_flags.inline-skill-commands.enabled": true,
|
|
140
|
-
},
|
|
141
137
|
};
|
|
142
138
|
|
|
143
139
|
mock.module("../config/loader.js", () => ({
|
|
@@ -215,9 +211,9 @@ describe("skill_load inline command expansion", () => {
|
|
|
215
211
|
}));
|
|
216
212
|
|
|
217
213
|
// Enable the feature flag
|
|
218
|
-
|
|
214
|
+
_setOverridesForTesting({
|
|
219
215
|
"feature_flags.inline-skill-commands.enabled": true,
|
|
220
|
-
};
|
|
216
|
+
});
|
|
221
217
|
testConfig.skills = { load: { extraDirs: [] } };
|
|
222
218
|
});
|
|
223
219
|
|
|
@@ -316,9 +312,9 @@ describe("skill_load inline command expansion", () => {
|
|
|
316
312
|
|
|
317
313
|
describe("feature flag disabled", () => {
|
|
318
314
|
test("returns error when flag is off and skill has inline commands", async () => {
|
|
319
|
-
|
|
315
|
+
_setOverridesForTesting({
|
|
320
316
|
"feature_flags.inline-skill-commands.enabled": false,
|
|
321
|
-
};
|
|
317
|
+
});
|
|
322
318
|
|
|
323
319
|
writeSkill(
|
|
324
320
|
"flagged-off-skill",
|
|
@@ -337,9 +333,9 @@ describe("skill_load inline command expansion", () => {
|
|
|
337
333
|
});
|
|
338
334
|
|
|
339
335
|
test("plain skill still loads when flag is off", async () => {
|
|
340
|
-
|
|
336
|
+
_setOverridesForTesting({
|
|
341
337
|
"feature_flags.inline-skill-commands.enabled": false,
|
|
342
|
-
};
|
|
338
|
+
});
|
|
343
339
|
|
|
344
340
|
writeSkill(
|
|
345
341
|
"plain-flag-off",
|
|
@@ -23,6 +23,8 @@ import { tmpdir } from "node:os";
|
|
|
23
23
|
import { join } from "node:path";
|
|
24
24
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
25
25
|
|
|
26
|
+
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
27
|
+
|
|
26
28
|
// ── Test directory ────────────────────────────────────────────────────────────
|
|
27
29
|
|
|
28
30
|
const TEST_DIR = mkdtempSync(
|
|
@@ -52,9 +54,7 @@ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
|
|
|
52
54
|
getSessionTokenPath: () => join(TEST_DIR, "session-token"),
|
|
53
55
|
readSessionToken: () => null,
|
|
54
56
|
getClipboardCommand: () => null,
|
|
55
|
-
readLockfile: () => null,
|
|
56
57
|
normalizeAssistantId: (id: unknown) => String(id),
|
|
57
|
-
writeLockfile: () => {},
|
|
58
58
|
getEmbeddingModelsDir: () => join(TEST_DIR, "embedding-models"),
|
|
59
59
|
getTCPPort: () => 8765,
|
|
60
60
|
isTCPEnabled: () => false,
|
|
@@ -129,7 +129,6 @@ interface TestConfig {
|
|
|
129
129
|
permissions: { mode: "strict" | "workspace" };
|
|
130
130
|
skills: { load: { extraDirs: string[] } };
|
|
131
131
|
sandbox: { enabled: boolean };
|
|
132
|
-
assistantFeatureFlagValues?: Record<string, boolean>;
|
|
133
132
|
[key: string]: unknown;
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -137,9 +136,6 @@ const testConfig: TestConfig = {
|
|
|
137
136
|
permissions: { mode: "workspace" },
|
|
138
137
|
skills: { load: { extraDirs: [] } },
|
|
139
138
|
sandbox: { enabled: true },
|
|
140
|
-
assistantFeatureFlagValues: {
|
|
141
|
-
"feature_flags.inline-skill-commands.enabled": true,
|
|
142
|
-
},
|
|
143
139
|
};
|
|
144
140
|
|
|
145
141
|
mock.module("../config/loader.js", () => ({
|
|
@@ -225,9 +221,9 @@ describe("skill_load inline command expansion for included skills", () => {
|
|
|
225
221
|
}));
|
|
226
222
|
|
|
227
223
|
// Enable the feature flag
|
|
228
|
-
|
|
224
|
+
_setOverridesForTesting({
|
|
229
225
|
"feature_flags.inline-skill-commands.enabled": true,
|
|
230
|
-
};
|
|
226
|
+
});
|
|
231
227
|
testConfig.skills = { load: { extraDirs: [] } };
|
|
232
228
|
});
|
|
233
229
|
|
|
@@ -575,9 +571,9 @@ describe("skill_load inline command expansion for included skills", () => {
|
|
|
575
571
|
|
|
576
572
|
describe("feature flag disabled for included skills", () => {
|
|
577
573
|
test("skill_load returns error when child has inline commands and flag is off", async () => {
|
|
578
|
-
|
|
574
|
+
_setOverridesForTesting({
|
|
579
575
|
"feature_flags.inline-skill-commands.enabled": false,
|
|
580
|
-
};
|
|
576
|
+
});
|
|
581
577
|
|
|
582
578
|
writeSkill(
|
|
583
579
|
"child-flag-off",
|
|
@@ -38,9 +38,7 @@ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
|
|
|
38
38
|
getSessionTokenPath: () => join(TEST_DIR, "session-token"),
|
|
39
39
|
readSessionToken: () => null,
|
|
40
40
|
getClipboardCommand: () => null,
|
|
41
|
-
readLockfile: () => null,
|
|
42
41
|
normalizeAssistantId: (id: unknown) => String(id),
|
|
43
|
-
writeLockfile: () => {},
|
|
44
42
|
getEmbeddingModelsDir: () => join(TEST_DIR, "embedding-models"),
|
|
45
43
|
getTCPPort: () => 8765,
|
|
46
44
|
isTCPEnabled: () => false,
|