@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2
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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
|
@@ -1,543 +0,0 @@
|
|
|
1
|
-
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import { basename, join, relative } from "node:path";
|
|
3
|
-
|
|
4
|
-
import { minimatch } from "minimatch";
|
|
5
|
-
import { RE2JS } from "re2js";
|
|
6
|
-
|
|
7
|
-
import { RiskLevel } from "../../permissions/types.js";
|
|
8
|
-
import { registerTool } from "../registry.js";
|
|
9
|
-
import {
|
|
10
|
-
isDeniedBasename,
|
|
11
|
-
sandboxPolicy,
|
|
12
|
-
} from "../shared/filesystem/path-policy.js";
|
|
13
|
-
import type {
|
|
14
|
-
ToolContext,
|
|
15
|
-
ToolDefinition,
|
|
16
|
-
ToolExecutionResult,
|
|
17
|
-
} from "../types.js";
|
|
18
|
-
|
|
19
|
-
// Directory names that are never worth searching and would otherwise dominate
|
|
20
|
-
// the file budget (dependencies, VCS metadata).
|
|
21
|
-
const IGNORED_DIRS = new Set(["node_modules", ".git"]);
|
|
22
|
-
|
|
23
|
-
// Defensive caps so a search over a huge tree cannot read the whole disk into
|
|
24
|
-
// memory. These bound the walk regardless of `max_results`.
|
|
25
|
-
const MAX_FILES_SCANNED = 20_000;
|
|
26
|
-
const MAX_TOTAL_BYTES = 256 * 1024 * 1024; // 256 MiB
|
|
27
|
-
const MAX_FILE_BYTES = 8 * 1024 * 1024; // skip files larger than 8 MiB
|
|
28
|
-
|
|
29
|
-
// Hard cap on directory entries visited during the walk, independent of
|
|
30
|
-
// wall-clock time. `MAX_FILES_SCANNED`/`MAX_TOTAL_BYTES` only count files that
|
|
31
|
-
// are actually READ, so a pathological tree full of oversized, unreadable,
|
|
32
|
-
// permission-denied, or glob-filtered files (which never increment those
|
|
33
|
-
// counters) could otherwise traverse unbounded. This bounds the readdir/stat
|
|
34
|
-
// work even when every individual operation is fast.
|
|
35
|
-
const MAX_ENTRIES_TRAVERSED = 200_000;
|
|
36
|
-
|
|
37
|
-
// Display-only cap on emitted output lines (ripgrep-style long-line bound). The
|
|
38
|
-
// pattern is matched against the FULL line, so a token anywhere on a long line
|
|
39
|
-
// is found; this cap only bounds the PRINTED line text (matched and context
|
|
40
|
-
// lines) so a single pathological line (e.g. a minified bundle on one line)
|
|
41
|
-
// can't emit a multi-megabyte output line. Normal code/log lines are well under
|
|
42
|
-
// the cap and print verbatim.
|
|
43
|
-
const MAX_DISPLAY_LINE_LENGTH = 2000;
|
|
44
|
-
|
|
45
|
-
// Output-byte budget: when `context_lines` is large and many nearby lines
|
|
46
|
-
// match, the surrounding block is appended for every match, so a single large
|
|
47
|
-
// file with many matches could allocate hundreds of MB before the post-tool
|
|
48
|
-
// truncation hook runs. Stop accumulating once this budget is exceeded and
|
|
49
|
-
// report the result as truncated.
|
|
50
|
-
const MAX_OUTPUT_BYTES = 4 * 1024 * 1024; // 4 MiB
|
|
51
|
-
|
|
52
|
-
// Wall-clock deadline for the whole search. The synchronous scan never yields,
|
|
53
|
-
// so the promise-based tool timeout / abort signal can't fire mid-scan. Checking
|
|
54
|
-
// this deadline (and the abort signal) once per line bounds how long a search
|
|
55
|
-
// over a very large tree can block the event loop and lets an external abort
|
|
56
|
-
// stop the walk promptly.
|
|
57
|
-
const MAX_SEARCH_MS = 10_000; // 10 s
|
|
58
|
-
|
|
59
|
-
const DEFAULT_MAX_RESULTS = 200;
|
|
60
|
-
const DEFAULT_CONTEXT_LINES = 0;
|
|
61
|
-
// Clamp `context_lines` so a single match cannot request unbounded surrounding
|
|
62
|
-
// context (which would blow past the output budget on its own).
|
|
63
|
-
const MAX_CONTEXT_LINES = 20;
|
|
64
|
-
|
|
65
|
-
/** Heuristic binary-file detection: a NUL byte in the leading bytes. */
|
|
66
|
-
function looksBinary(buf: Buffer): boolean {
|
|
67
|
-
const len = Math.min(buf.length, 8000);
|
|
68
|
-
for (let i = 0; i < len; i++) {
|
|
69
|
-
if (buf[i] === 0) return true;
|
|
70
|
-
}
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const codeSearchTool = {
|
|
75
|
-
name: "code_search",
|
|
76
|
-
description:
|
|
77
|
-
"Search file contents for a regular-expression pattern across a directory tree on your own machine, returning matching `path:line: text` lines. Read-only — never modifies files. Skips node_modules, .git, and binary files. Use this to grep across files without a shell.",
|
|
78
|
-
category: "filesystem",
|
|
79
|
-
executionTarget: "sandbox",
|
|
80
|
-
defaultRiskLevel: RiskLevel.Low,
|
|
81
|
-
|
|
82
|
-
input_schema: {
|
|
83
|
-
type: "object",
|
|
84
|
-
properties: {
|
|
85
|
-
pattern: {
|
|
86
|
-
type: "string",
|
|
87
|
-
description:
|
|
88
|
-
"Regular-expression pattern to search for in file contents",
|
|
89
|
-
},
|
|
90
|
-
path: {
|
|
91
|
-
type: "string",
|
|
92
|
-
description:
|
|
93
|
-
"Directory to search under (defaults to the working directory)",
|
|
94
|
-
},
|
|
95
|
-
glob: {
|
|
96
|
-
type: "string",
|
|
97
|
-
description:
|
|
98
|
-
"Only search files whose path (relative to the search root) matches this glob, e.g. '*.ts' or 'src/**'",
|
|
99
|
-
},
|
|
100
|
-
case_insensitive: {
|
|
101
|
-
type: "boolean",
|
|
102
|
-
description: "Match the pattern case-insensitively",
|
|
103
|
-
},
|
|
104
|
-
context_lines: {
|
|
105
|
-
type: "number",
|
|
106
|
-
description:
|
|
107
|
-
"Number of lines of context to include before and after each match (default 0)",
|
|
108
|
-
},
|
|
109
|
-
max_results: {
|
|
110
|
-
type: "number",
|
|
111
|
-
description: "Maximum number of matches to return (default 200)",
|
|
112
|
-
},
|
|
113
|
-
activity: {
|
|
114
|
-
type: "string",
|
|
115
|
-
description:
|
|
116
|
-
"Brief non-technical explanation of what you are doing and why, shown as a status update.",
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
required: ["pattern", "activity"],
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
async execute(
|
|
123
|
-
input: Record<string, unknown>,
|
|
124
|
-
context: ToolContext,
|
|
125
|
-
): Promise<ToolExecutionResult> {
|
|
126
|
-
const pattern = input.pattern;
|
|
127
|
-
if (!pattern || typeof pattern !== "string") {
|
|
128
|
-
return {
|
|
129
|
-
content: "Error: pattern is required and must be a non-empty string",
|
|
130
|
-
isError: true,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const rawPath =
|
|
135
|
-
typeof input.path === "string" && input.path.length > 0
|
|
136
|
-
? input.path
|
|
137
|
-
: context.workingDir;
|
|
138
|
-
|
|
139
|
-
const pathCheck = sandboxPolicy(rawPath, context.workingDir);
|
|
140
|
-
if (!pathCheck.ok) {
|
|
141
|
-
return {
|
|
142
|
-
content: `Error: ${pathCheck.error}. To search outside the workspace, use the host_bash tool instead.`,
|
|
143
|
-
isError: true,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
const root = pathCheck.resolved;
|
|
147
|
-
|
|
148
|
-
const caseInsensitive = input.case_insensitive === true;
|
|
149
|
-
// Match with the linear-time RE2 engine (via re2js) instead of V8's
|
|
150
|
-
// backtracking RegExp. RE2 guarantees linear-time matching, so a
|
|
151
|
-
// user/subagent-supplied pattern cannot trigger catastrophic backtracking
|
|
152
|
-
// and block the synchronous scan. The trade-off is that RE2 rejects
|
|
153
|
-
// backreferences and lookarounds; compile() throws on those, surfaced as a
|
|
154
|
-
// clean error below.
|
|
155
|
-
let regex: RE2JS;
|
|
156
|
-
try {
|
|
157
|
-
regex = RE2JS.compile(
|
|
158
|
-
pattern,
|
|
159
|
-
caseInsensitive ? RE2JS.CASE_INSENSITIVE : 0,
|
|
160
|
-
);
|
|
161
|
-
} catch (err) {
|
|
162
|
-
return {
|
|
163
|
-
content: `Error: invalid or unsupported pattern "${pattern}": ${
|
|
164
|
-
err instanceof Error ? err.message : String(err)
|
|
165
|
-
}. The RE2 engine does not support backreferences or lookarounds.`,
|
|
166
|
-
isError: true,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const glob =
|
|
171
|
-
typeof input.glob === "string" && input.glob.length > 0
|
|
172
|
-
? input.glob
|
|
173
|
-
: undefined;
|
|
174
|
-
|
|
175
|
-
const contextLines =
|
|
176
|
-
typeof input.context_lines === "number" && input.context_lines > 0
|
|
177
|
-
? Math.min(Math.floor(input.context_lines), MAX_CONTEXT_LINES)
|
|
178
|
-
: DEFAULT_CONTEXT_LINES;
|
|
179
|
-
|
|
180
|
-
const maxResults =
|
|
181
|
-
typeof input.max_results === "number" && input.max_results > 0
|
|
182
|
-
? Math.floor(input.max_results)
|
|
183
|
-
: DEFAULT_MAX_RESULTS;
|
|
184
|
-
|
|
185
|
-
// Validate the search root before walking so a missing/unreadable/typo'd
|
|
186
|
-
// path surfaces a hard error instead of being swallowed like an unreadable
|
|
187
|
-
// child directory and returning a false "No matches found". Mirrors the
|
|
188
|
-
// NOT_FOUND / NOT_A_DIRECTORY reporting in file_list.
|
|
189
|
-
let rootStat: import("node:fs").Stats;
|
|
190
|
-
try {
|
|
191
|
-
rootStat = statSync(root);
|
|
192
|
-
} catch {
|
|
193
|
-
return {
|
|
194
|
-
content: `Error: path not found: ${rawPath}`,
|
|
195
|
-
isError: true,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Start the wall-clock deadline before walking so a pathological regex
|
|
200
|
-
// (or an external abort) can stop the synchronous scan mid-flight instead
|
|
201
|
-
// of blocking the event loop until the whole tree is exhausted.
|
|
202
|
-
const searchStart = Date.now();
|
|
203
|
-
|
|
204
|
-
const lines: string[] = [];
|
|
205
|
-
let matchCount = 0;
|
|
206
|
-
let truncated = false;
|
|
207
|
-
// Set when the output-byte budget (not the max-results cap) stopped the
|
|
208
|
-
// accumulation, so the truncation note can explain why.
|
|
209
|
-
let outputBudgetHit = false;
|
|
210
|
-
// Set when the wall-clock deadline (or an abort signal) stopped the scan,
|
|
211
|
-
// so the result can report that the search timed out and is incomplete —
|
|
212
|
-
// distinct from the scan-cap and output-budget truncation notes.
|
|
213
|
-
let timedOut = false;
|
|
214
|
-
// Set when the search stopped because it reached the `max_results` cap (as
|
|
215
|
-
// opposed to a scan/traversal cap). Only this cause is helped by raising
|
|
216
|
-
// `max_results`, so the matched-branch truncation note keys off this flag to
|
|
217
|
-
// avoid suggesting a larger `max_results` when a scan cap stopped the walk.
|
|
218
|
-
let maxResultsHit = false;
|
|
219
|
-
// Set when a file was skipped mid-walk because it exceeds MAX_FILE_BYTES.
|
|
220
|
-
// Unlike the truncation flags this does NOT halt the walk — other files may
|
|
221
|
-
// still match — but it does mark the overall result incomplete, since the
|
|
222
|
-
// skipped file could have contained the pattern. Kept separate from
|
|
223
|
-
// `truncated` so the zero-match invariant ("truncated => scan cap/timeout")
|
|
224
|
-
// stays intact.
|
|
225
|
-
let skippedLargeFile = false;
|
|
226
|
-
let filesScanned = 0;
|
|
227
|
-
let totalBytes = 0;
|
|
228
|
-
// Number of directory entries visited during the walk (files + subdirs),
|
|
229
|
-
// bounded by MAX_ENTRIES_TRAVERSED so a pathological tree can't run the
|
|
230
|
-
// synchronous readdir/stat work unbounded even when no file is ever read.
|
|
231
|
-
let entriesTraversed = 0;
|
|
232
|
-
// Set when an EXPLICIT file root (not a child discovered mid-walk) can't be
|
|
233
|
-
// read — e.g. EACCES/EPERM. A child file's read failure is optional and
|
|
234
|
-
// silently skipped, but an unreadable explicit root means nothing was
|
|
235
|
-
// searched, so we surface it as an error instead of a false "No matches".
|
|
236
|
-
let rootReadError: string | null = null;
|
|
237
|
-
// Running size of the accumulated output (lines joined by "\n") so we can
|
|
238
|
-
// stop before allocating an unbounded result. Each pushed line contributes
|
|
239
|
-
// its UTF-8 byte length plus one byte for the joining newline.
|
|
240
|
-
let outputBytes = 0;
|
|
241
|
-
|
|
242
|
-
// Bound a single emitted line's length for display only. Matching always
|
|
243
|
-
// runs against the full line; this just keeps the PRINTED text readable and
|
|
244
|
-
// prevents one pathological line (minified bundle, huge JSON/log line) from
|
|
245
|
-
// emitting a multi-megabyte output line. Normal lines pass through verbatim.
|
|
246
|
-
const truncateForDisplay = (text: string): string =>
|
|
247
|
-
text.length > MAX_DISPLAY_LINE_LENGTH
|
|
248
|
-
? `${text.slice(0, MAX_DISPLAY_LINE_LENGTH)} …[line truncated]`
|
|
249
|
-
: text;
|
|
250
|
-
|
|
251
|
-
// Append an output line, tracking its byte cost. Returns false once the
|
|
252
|
-
// output-byte budget is exhausted so callers can stop accumulating.
|
|
253
|
-
const pushLine = (line: string): boolean => {
|
|
254
|
-
outputBytes += Buffer.byteLength(line, "utf8") + 1;
|
|
255
|
-
lines.push(line);
|
|
256
|
-
if (outputBytes > MAX_OUTPUT_BYTES) {
|
|
257
|
-
truncated = true;
|
|
258
|
-
outputBudgetHit = true;
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
return true;
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
// Scan a single regular file for matches. Applies the denied-basename guard
|
|
265
|
-
// and per-file size caps. Returns nothing; mutates the shared accumulators.
|
|
266
|
-
const scanFile = (full: string, isExplicitRoot = false): void => {
|
|
267
|
-
if (truncated) return;
|
|
268
|
-
|
|
269
|
-
// Honor the wall-clock deadline / abort signal before doing any stat/size
|
|
270
|
-
// work, not just inside the per-line loop. A tree full of oversized or
|
|
271
|
-
// unreadable files (which never reach the per-line loop) could otherwise
|
|
272
|
-
// run far past the advertised deadline.
|
|
273
|
-
if (Date.now() - searchStart > MAX_SEARCH_MS || context.signal?.aborted) {
|
|
274
|
-
truncated = true;
|
|
275
|
-
timedOut = true;
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Never read files the assistant is forbidden from touching, even if a
|
|
280
|
-
// broad pattern would otherwise match them. Reuses the same denylist as
|
|
281
|
-
// file_read/file_write so the policies stay in sync.
|
|
282
|
-
if (isDeniedBasename(full)) return;
|
|
283
|
-
|
|
284
|
-
const rel = relative(root, full);
|
|
285
|
-
// matchBase lets a slash-free pattern like "*.ts" match files at any
|
|
286
|
-
// depth (against the basename); patterns with slashes match the full
|
|
287
|
-
// relative path. dot so dotfiles aren't silently excluded. When the root
|
|
288
|
-
// is a single file, `rel` is empty, so match against the basename.
|
|
289
|
-
const globTarget = rel.length > 0 ? rel : basename(full);
|
|
290
|
-
if (
|
|
291
|
-
glob &&
|
|
292
|
-
!minimatch(globTarget, glob, { matchBase: true, dot: true })
|
|
293
|
-
) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (filesScanned >= MAX_FILES_SCANNED) {
|
|
298
|
-
truncated = true;
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
let size: number;
|
|
303
|
-
try {
|
|
304
|
-
size = statSync(full).size;
|
|
305
|
-
} catch {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
if (size > MAX_FILE_BYTES) {
|
|
309
|
-
// Skip just this file (others may still match), but record that the
|
|
310
|
-
// search is incomplete so the result doesn't read as a definitive miss.
|
|
311
|
-
skippedLargeFile = true;
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
if (totalBytes + size > MAX_TOTAL_BYTES) {
|
|
315
|
-
truncated = true;
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
let buf: Buffer;
|
|
320
|
-
try {
|
|
321
|
-
buf = readFileSync(full);
|
|
322
|
-
} catch (err) {
|
|
323
|
-
// A child file discovered mid-walk is optional — skip it silently. But
|
|
324
|
-
// an explicit file root that can't be read was never searched, so record
|
|
325
|
-
// the failure for the caller to surface as an error.
|
|
326
|
-
if (isExplicitRoot) {
|
|
327
|
-
const code = (err as NodeJS.ErrnoException)?.code;
|
|
328
|
-
rootReadError = `Error: failed to read file (${code ?? "unreadable"}): ${rawPath}`;
|
|
329
|
-
}
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
filesScanned++;
|
|
333
|
-
totalBytes += buf.length;
|
|
334
|
-
if (looksBinary(buf)) return;
|
|
335
|
-
|
|
336
|
-
// Display path: when searching a single file at the root, `rel` is empty;
|
|
337
|
-
// fall back to the basename so output stays readable.
|
|
338
|
-
const display = rel.length > 0 ? rel : basename(full);
|
|
339
|
-
const fileLines = buf.toString("utf8").split("\n");
|
|
340
|
-
for (let i = 0; i < fileLines.length; i++) {
|
|
341
|
-
// Bound the total event-loop block: check the wall-clock deadline and
|
|
342
|
-
// the abort signal before every regex test (the per-line Date.now() and
|
|
343
|
-
// .aborted reads are negligible next to a catastrophic-backtracking
|
|
344
|
-
// test). When either trips, mark the search timed out / aborted and
|
|
345
|
-
// stop the whole walk so partial results are still reported.
|
|
346
|
-
if (
|
|
347
|
-
Date.now() - searchStart > MAX_SEARCH_MS ||
|
|
348
|
-
context.signal?.aborted
|
|
349
|
-
) {
|
|
350
|
-
truncated = true;
|
|
351
|
-
timedOut = true;
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
// Match against the FULL line so a token that appears past any display
|
|
355
|
-
// cap (e.g. after column 2000 on a long log/JSON/minified line) is still
|
|
356
|
-
// found. RE2's linear-time matching makes this safe — there is no
|
|
357
|
-
// backtracking blowup to bound, so no need to slice before matching.
|
|
358
|
-
const line = fileLines[i];
|
|
359
|
-
// Unanchored partial match anywhere in the line — the RE2 equivalent of
|
|
360
|
-
// RegExp.prototype.test(). The compiled pattern is stateless per call.
|
|
361
|
-
if (!regex.test(line)) continue;
|
|
362
|
-
if (matchCount >= maxResults) {
|
|
363
|
-
truncated = true;
|
|
364
|
-
maxResultsHit = true;
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
// Count the match before emitting its lines: a single match whose output
|
|
368
|
-
// alone exceeds the output-byte budget would otherwise leave matchCount
|
|
369
|
-
// at 0, making the zero-match branch report a false "no matches / scan
|
|
370
|
-
// cap" instead of a truncated result that acknowledges the match.
|
|
371
|
-
matchCount++;
|
|
372
|
-
const lineNo = i + 1;
|
|
373
|
-
if (contextLines > 0) {
|
|
374
|
-
const start = Math.max(0, i - contextLines);
|
|
375
|
-
const end = Math.min(fileLines.length - 1, i + contextLines);
|
|
376
|
-
for (let j = start; j <= end; j++) {
|
|
377
|
-
const sep = j === i ? ":" : "-";
|
|
378
|
-
if (
|
|
379
|
-
!pushLine(
|
|
380
|
-
`${display}:${j + 1}${sep} ${truncateForDisplay(fileLines[j])}`,
|
|
381
|
-
)
|
|
382
|
-
)
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
if (!pushLine("--")) return;
|
|
386
|
-
} else {
|
|
387
|
-
if (
|
|
388
|
-
!pushLine(
|
|
389
|
-
`${display}:${lineNo}: ${truncateForDisplay(fileLines[i])}`,
|
|
390
|
-
)
|
|
391
|
-
)
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
const walk = (dir: string, isExplicitRoot = false): void => {
|
|
398
|
-
if (truncated) return;
|
|
399
|
-
// Bound the traversal itself, not just file reads: a deep/wide tree of
|
|
400
|
-
// directories (or many entries that never get read) could otherwise run
|
|
401
|
-
// the synchronous readdir/stat work far past the advertised deadline.
|
|
402
|
-
if (Date.now() - searchStart > MAX_SEARCH_MS || context.signal?.aborted) {
|
|
403
|
-
truncated = true;
|
|
404
|
-
timedOut = true;
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
let entries: import("node:fs").Dirent[];
|
|
408
|
-
try {
|
|
409
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
410
|
-
} catch (err) {
|
|
411
|
-
// A child directory discovered mid-walk is optional — skip it silently.
|
|
412
|
-
// But an explicit directory root that can't be read (e.g. EACCES/EPERM)
|
|
413
|
-
// was never searched, so record the failure for the caller to surface
|
|
414
|
-
// as an error instead of a false "No matches found".
|
|
415
|
-
if (isExplicitRoot) {
|
|
416
|
-
const code = (err as NodeJS.ErrnoException)?.code;
|
|
417
|
-
rootReadError = `Error: failed to read directory (${code ?? "unreadable"}): ${rawPath}`;
|
|
418
|
-
}
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
for (const entry of entries) {
|
|
422
|
-
if (truncated) return;
|
|
423
|
-
// Per-entry deadline/abort check (the Date.now()/.aborted reads are
|
|
424
|
-
// negligible) plus a hard entry cap independent of wall-clock time so a
|
|
425
|
-
// pathological tree is bounded even when every operation is fast.
|
|
426
|
-
if (
|
|
427
|
-
Date.now() - searchStart > MAX_SEARCH_MS ||
|
|
428
|
-
context.signal?.aborted
|
|
429
|
-
) {
|
|
430
|
-
truncated = true;
|
|
431
|
-
timedOut = true;
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
entriesTraversed++;
|
|
435
|
-
if (entriesTraversed > MAX_ENTRIES_TRAVERSED) {
|
|
436
|
-
truncated = true;
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
const full = join(dir, entry.name);
|
|
440
|
-
if (entry.isDirectory()) {
|
|
441
|
-
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
442
|
-
walk(full);
|
|
443
|
-
continue;
|
|
444
|
-
}
|
|
445
|
-
if (!entry.isFile()) continue;
|
|
446
|
-
scanFile(full);
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
if (rootStat.isDirectory()) {
|
|
451
|
-
walk(root, true);
|
|
452
|
-
// An explicit directory root that statSync sees but readdirSync can't read
|
|
453
|
-
// (EACCES/EPERM) was never searched — surface a hard error instead of a
|
|
454
|
-
// false "No matches found", mirroring the unreadable explicit-file root.
|
|
455
|
-
if (rootReadError) {
|
|
456
|
-
return { content: rootReadError, isError: true };
|
|
457
|
-
}
|
|
458
|
-
} else if (rootStat.isFile()) {
|
|
459
|
-
// A regular-file root is a valid single-file search. Unlike an oversized
|
|
460
|
-
// file skipped mid-walk (where other files may still match), an oversized
|
|
461
|
-
// explicit root means nothing was searched at all — surface a hard error
|
|
462
|
-
// instead of falling through to a false "No matches found".
|
|
463
|
-
if (rootStat.size > MAX_FILE_BYTES) {
|
|
464
|
-
return {
|
|
465
|
-
content: `Error: file too large to search (${rootStat.size} bytes): ${rawPath}`,
|
|
466
|
-
isError: true,
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
scanFile(root, true);
|
|
470
|
-
if (rootReadError) {
|
|
471
|
-
return { content: rootReadError, isError: true };
|
|
472
|
-
}
|
|
473
|
-
} else {
|
|
474
|
-
return {
|
|
475
|
-
content: `Error: path not found: ${rawPath}`,
|
|
476
|
-
isError: true,
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
if (matchCount === 0) {
|
|
481
|
-
// With zero matches, `truncated` can only have been set by a scan cap
|
|
482
|
-
// (MAX_FILES_SCANNED / MAX_TOTAL_BYTES / MAX_ENTRIES_TRAVERSED) or the
|
|
483
|
-
// wall-clock deadline, never the max-results path. In either case the tree
|
|
484
|
-
// was only partially scanned, so a definitive "No matches found" would be
|
|
485
|
-
// a false negative.
|
|
486
|
-
if (timedOut) {
|
|
487
|
-
return {
|
|
488
|
-
content: `Search timed out after ${MAX_SEARCH_MS / 1000}s before finding any match for /${pattern}/${caseInsensitive ? "i" : ""} under ${basename(root)}. Results are incomplete — narrow your pattern, glob, or path and search again.`,
|
|
489
|
-
isError: false,
|
|
490
|
-
status: "truncated",
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
if (truncated) {
|
|
494
|
-
return {
|
|
495
|
-
content: `Search stopped early after hitting a scan cap before finding any match for /${pattern}/${caseInsensitive ? "i" : ""} under ${basename(root)}. Results are incomplete — narrow your glob or path and search again.`,
|
|
496
|
-
isError: false,
|
|
497
|
-
status: "truncated",
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
if (skippedLargeFile) {
|
|
501
|
-
return {
|
|
502
|
-
content: `No matches found for /${pattern}/${caseInsensitive ? "i" : ""} under ${basename(root)}, but one or more files were skipped because they exceed the ${Math.round(MAX_FILE_BYTES / (1024 * 1024))} MiB per-file size limit, so results may be incomplete.`,
|
|
503
|
-
isError: false,
|
|
504
|
-
status: "truncated",
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
return {
|
|
508
|
-
content: `No matches found for /${pattern}/${caseInsensitive ? "i" : ""} under ${basename(root)}`,
|
|
509
|
-
isError: false,
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
let content = lines.join("\n");
|
|
514
|
-
if (truncated) {
|
|
515
|
-
// Distinguish the truncation cause in priority order so the note doesn't
|
|
516
|
-
// mislead. Only `maxResultsHit` is helped by raising `max_results`; a
|
|
517
|
-
// scan/traversal cap (MAX_FILES_SCANNED / MAX_TOTAL_BYTES /
|
|
518
|
-
// MAX_ENTRIES_TRAVERSED) is not, so it gets its own note.
|
|
519
|
-
if (timedOut) {
|
|
520
|
-
content += `\n\n[Search timed out after ${MAX_SEARCH_MS / 1000}s. Results are incomplete. Narrow your pattern, glob, or path to see more.]`;
|
|
521
|
-
} else if (outputBudgetHit) {
|
|
522
|
-
content += `\n\n[Output capped at ${Math.round(MAX_OUTPUT_BYTES / (1024 * 1024))} MiB. Narrow your pattern, glob, or path, or reduce context_lines, to see more.]`;
|
|
523
|
-
} else if (maxResultsHit) {
|
|
524
|
-
content += `\n\n[Results truncated at ${maxResults} matches. Narrow your pattern, glob, or path to see more.]`;
|
|
525
|
-
} else {
|
|
526
|
-
content += `\n\n[Search stopped early after hitting a scan/traversal cap — some files weren't searched. Narrow your glob or path (raising max_results won't help).]`;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (skippedLargeFile) {
|
|
530
|
-
// Independent of the truncation reasons above: note any files skipped for
|
|
531
|
-
// exceeding the per-file size limit so the result isn't read as complete.
|
|
532
|
-
content += `\n\n[One or more files were skipped because they exceed the ${Math.round(MAX_FILE_BYTES / (1024 * 1024))} MiB per-file size limit. Results may be incomplete.]`;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
return {
|
|
536
|
-
content,
|
|
537
|
-
isError: false,
|
|
538
|
-
...(truncated || skippedLargeFile ? { status: "truncated" } : {}),
|
|
539
|
-
};
|
|
540
|
-
},
|
|
541
|
-
} satisfies ToolDefinition;
|
|
542
|
-
|
|
543
|
-
registerTool(codeSearchTool);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
|
|
3
|
-
import { getDataDir } from "./platform.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Path to the dedicated SQLite file that houses telemetry event tables
|
|
7
|
-
* (starting with `watchdog_events`). It lives in the same `data/db` directory
|
|
8
|
-
* as the main DB and is opened on its own connection (see `getTelemetryDb()`
|
|
9
|
-
* in `memory/db-connection.ts`). Splitting telemetry tables into their own
|
|
10
|
-
* file keeps the main DB — and its WAL — small and lets the two files
|
|
11
|
-
* VACUUM/checkpoint independently, so a burst of watchdog events can no longer
|
|
12
|
-
* bloat the main database.
|
|
13
|
-
*
|
|
14
|
-
* Kept in its own leaf module rather than alongside `getDbPath()` in
|
|
15
|
-
* `platform.ts`: `platform.ts` is imported very early and widely, and adding an
|
|
16
|
-
* export to it that low-level consumers (e.g. `db-connection.ts`) pull in
|
|
17
|
-
* across the daemon's large, cyclic import graph trips a Bun link-order bug
|
|
18
|
-
* ("Export named 'getTelemetryDbPath' not found"). Isolating it here keeps
|
|
19
|
-
* `platform.ts`'s module shape stable — same reasoning as `logs-db-path.ts`
|
|
20
|
-
* and `memory-db-path.ts`.
|
|
21
|
-
*/
|
|
22
|
-
export function getTelemetryDbPath(): string {
|
|
23
|
-
return join(getDataDir(), "db", "assistant-telemetry.db");
|
|
24
|
-
}
|