vellum 0.0.16 → 0.2.0
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/.dockerignore +27 -0
- package/.env.example +22 -0
- package/Dockerfile +99 -0
- package/Dockerfile.sandbox +5 -0
- package/README.md +150 -3
- package/bun.lock +1768 -0
- package/bunfig.toml +2 -0
- package/docs/skills.md +158 -0
- package/drizzle/0000_dizzy_maggott.sql +301 -0
- package/drizzle/meta/0000_snapshot.json +1999 -0
- package/drizzle/meta/_journal.json +13 -0
- package/drizzle.config.ts +7 -0
- package/eslint.config.mjs +17 -0
- package/hook-templates/debug-prompt-logger/hook.json +7 -0
- package/hook-templates/debug-prompt-logger/run.sh +68 -0
- package/knip.json +9 -0
- package/package.json +60 -10
- package/scripts/ipc/check-contract-inventory.ts +104 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +163 -0
- package/scripts/ipc/generate-swift.ts +492 -0
- package/scripts/test-filesystem-tools.sh +48 -0
- package/scripts/test.sh +122 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2079 -0
- package/src/__tests__/account-registry.test.ts +244 -0
- package/src/__tests__/active-skill-tools.test.ts +378 -0
- package/src/__tests__/agent-loop-thinking.test.ts +81 -0
- package/src/__tests__/agent-loop.test.ts +1135 -0
- package/src/__tests__/anthropic-provider.test.ts +778 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +290 -0
- package/src/__tests__/app-bundler.test.ts +313 -0
- package/src/__tests__/app-executors.test.ts +613 -0
- package/src/__tests__/app-open-proxy.test.ts +62 -0
- package/src/__tests__/asset-materialize-tool.test.ts +451 -0
- package/src/__tests__/asset-search-tool.test.ts +476 -0
- package/src/__tests__/assistant-attachment-directive.test.ts +401 -0
- package/src/__tests__/assistant-attachments.test.ts +437 -0
- package/src/__tests__/assistant-event-hub.test.ts +226 -0
- package/src/__tests__/assistant-event.test.ts +123 -0
- package/src/__tests__/attachments-store.test.ts +547 -0
- package/src/__tests__/attachments.test.ts +134 -0
- package/src/__tests__/audit-log-rotation.test.ts +154 -0
- package/src/__tests__/browser-fill-credential.test.ts +309 -0
- package/src/__tests__/browser-manager.test.ts +203 -0
- package/src/__tests__/browser-runtime-check.test.ts +55 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +67 -0
- package/src/__tests__/browser-skill-endstate.test.ts +198 -0
- package/src/__tests__/bundle-scanner.test.ts +313 -0
- package/src/__tests__/checker.test.ts +3856 -0
- package/src/__tests__/clarification-resolver.test.ts +159 -0
- package/src/__tests__/classifier.test.ts +67 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +127 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +88 -0
- package/src/__tests__/cli-discover.test.ts +85 -0
- package/src/__tests__/cli.test.ts +81 -0
- package/src/__tests__/clipboard.test.ts +80 -0
- package/src/__tests__/commit-guarantee.test.ts +335 -0
- package/src/__tests__/computer-use-session-compaction.test.ts +132 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +293 -0
- package/src/__tests__/computer-use-session-working-dir.test.ts +117 -0
- package/src/__tests__/computer-use-skill-baseline.test.ts +74 -0
- package/src/__tests__/computer-use-skill-endstate.test.ts +89 -0
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +217 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +107 -0
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +54 -0
- package/src/__tests__/config-schema.test.ts +720 -0
- package/src/__tests__/conflict-store.test.ts +329 -0
- package/src/__tests__/connection-policy.test.ts +102 -0
- package/src/__tests__/context-memory-e2e.test.ts +434 -0
- package/src/__tests__/context-token-estimator.test.ts +135 -0
- package/src/__tests__/context-window-manager.test.ts +376 -0
- package/src/__tests__/contradiction-checker.test.ts +216 -0
- package/src/__tests__/conversation-store.test.ts +614 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +517 -0
- package/src/__tests__/credential-broker-server-use.test.ts +554 -0
- package/src/__tests__/credential-broker.test.ts +167 -0
- package/src/__tests__/credential-host-pattern-match.test.ts +104 -0
- package/src/__tests__/credential-metadata-store.test.ts +779 -0
- package/src/__tests__/credential-policy-validate.test.ts +121 -0
- package/src/__tests__/credential-resolve.test.ts +328 -0
- package/src/__tests__/credential-security-e2e.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +563 -0
- package/src/__tests__/credential-selection.test.ts +354 -0
- package/src/__tests__/credential-vault.test.ts +852 -0
- package/src/__tests__/daemon-assistant-events.test.ts +164 -0
- package/src/__tests__/daemon-server-session-init.test.ts +522 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +97 -0
- package/src/__tests__/diff.test.ts +121 -0
- package/src/__tests__/domain-normalize.test.ts +112 -0
- package/src/__tests__/domain-policy.test.ts +124 -0
- package/src/__tests__/doordash-client.test.ts +186 -0
- package/src/__tests__/doordash-session.test.ts +143 -0
- package/src/__tests__/dynamic-page-surface.test.ts +91 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +132 -0
- package/src/__tests__/edit-engine.test.ts +180 -0
- package/src/__tests__/email-cli.test.ts +283 -0
- package/src/__tests__/encrypted-store.test.ts +332 -0
- package/src/__tests__/entity-extractor.test.ts +190 -0
- package/src/__tests__/ephemeral-permissions.test.ts +312 -0
- package/src/__tests__/evaluate-typescript-tool.test.ts +286 -0
- package/src/__tests__/event-bus.test.ts +222 -0
- package/src/__tests__/file-edit-tool.test.ts +122 -0
- package/src/__tests__/file-ops-service.test.ts +330 -0
- package/src/__tests__/file-read-tool.test.ts +75 -0
- package/src/__tests__/file-write-tool.test.ts +113 -0
- package/src/__tests__/fixtures/credential-security-fixtures.ts +181 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +126 -0
- package/src/__tests__/fixtures/mock-signup-server.ts +387 -0
- package/src/__tests__/fixtures/proxy-fixtures.ts +147 -0
- package/src/__tests__/fuzzy-match-property.test.ts +216 -0
- package/src/__tests__/fuzzy-match.test.ts +138 -0
- package/src/__tests__/gemini-image-service.test.ts +261 -0
- package/src/__tests__/gemini-provider.test.ts +651 -0
- package/src/__tests__/get-weather.test.ts +318 -0
- package/src/__tests__/gmail-integration.test.ts +73 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +351 -0
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +190 -0
- package/src/__tests__/handlers-slack-config.test.ts +199 -0
- package/src/__tests__/handlers-task-submit-slash.test.ts +38 -0
- package/src/__tests__/headless-browser-interactions.test.ts +536 -0
- package/src/__tests__/headless-browser-navigate.test.ts +211 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +261 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +185 -0
- package/src/__tests__/history-repair-observability.test.ts +56 -0
- package/src/__tests__/history-repair.test.ts +510 -0
- package/src/__tests__/home-base-bootstrap.test.ts +77 -0
- package/src/__tests__/hooks-blocking.test.ts +128 -0
- package/src/__tests__/hooks-cli.test.ts +144 -0
- package/src/__tests__/hooks-config.test.ts +93 -0
- package/src/__tests__/hooks-discovery.test.ts +199 -0
- package/src/__tests__/hooks-integration.test.ts +189 -0
- package/src/__tests__/hooks-manager.test.ts +187 -0
- package/src/__tests__/hooks-runner.test.ts +178 -0
- package/src/__tests__/hooks-settings.test.ts +154 -0
- package/src/__tests__/hooks-templates.test.ts +137 -0
- package/src/__tests__/hooks-ts-runner.test.ts +125 -0
- package/src/__tests__/hooks-watch.test.ts +100 -0
- package/src/__tests__/host-file-edit-tool.test.ts +104 -0
- package/src/__tests__/host-file-read-tool.test.ts +61 -0
- package/src/__tests__/host-file-write-tool.test.ts +77 -0
- package/src/__tests__/host-shell-tool.test.ts +311 -0
- package/src/__tests__/intent-routing.test.ts +255 -0
- package/src/__tests__/ipc-blob-store.test.ts +315 -0
- package/src/__tests__/ipc-contract-inventory.test.ts +54 -0
- package/src/__tests__/ipc-contract.test.ts +74 -0
- package/src/__tests__/ipc-protocol.test.ts +113 -0
- package/src/__tests__/ipc-snapshot.test.ts +1560 -0
- package/src/__tests__/ipc-validate.test.ts +357 -0
- package/src/__tests__/key-migration.test.ts +183 -0
- package/src/__tests__/keychain.test.ts +258 -0
- package/src/__tests__/llm-usage-store.test.ts +226 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +257 -0
- package/src/__tests__/managed-store.test.ts +608 -0
- package/src/__tests__/media-generate-image.test.ts +238 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +676 -0
- package/src/__tests__/media-visibility-policy.test.ts +141 -0
- package/src/__tests__/memory-context-benchmark.test.ts +235 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +481 -0
- package/src/__tests__/memory-query-builder.test.ts +59 -0
- package/src/__tests__/memory-recall-quality.test.ts +846 -0
- package/src/__tests__/memory-regressions.experimental.test.ts +538 -0
- package/src/__tests__/memory-regressions.test.ts +4238 -0
- package/src/__tests__/memory-retrieval-budget.test.ts +49 -0
- package/src/__tests__/migration-cli-flows.test.ts +169 -0
- package/src/__tests__/migration-ordering.test.ts +249 -0
- package/src/__tests__/mock-signup-server.test.ts +528 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +166 -0
- package/src/__tests__/onboarding-template-contract.test.ts +58 -0
- package/src/__tests__/openai-provider.test.ts +753 -0
- package/src/__tests__/parser.test.ts +472 -0
- package/src/__tests__/path-classifier.test.ts +73 -0
- package/src/__tests__/path-policy.test.ts +435 -0
- package/src/__tests__/platform-move-helper.test.ts +99 -0
- package/src/__tests__/platform-socket-path.test.ts +52 -0
- package/src/__tests__/platform-workspace-migration.test.ts +1000 -0
- package/src/__tests__/platform.test.ts +131 -0
- package/src/__tests__/prebuilt-home-base-seed.test.ts +71 -0
- package/src/__tests__/pricing.test.ts +256 -0
- package/src/__tests__/profile-compiler.test.ts +373 -0
- package/src/__tests__/provider-registry-ollama.test.ts +16 -0
- package/src/__tests__/proxy-approval-callback.test.ts +601 -0
- package/src/__tests__/ratelimit.test.ts +297 -0
- package/src/__tests__/registry.test.ts +487 -0
- package/src/__tests__/reminder-store.test.ts +220 -0
- package/src/__tests__/reminder.test.ts +263 -0
- package/src/__tests__/request-file-tool.test.ts +158 -0
- package/src/__tests__/run-orchestrator.test.ts +200 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +190 -0
- package/src/__tests__/runtime-runs-http.test.ts +451 -0
- package/src/__tests__/runtime-runs.test.ts +273 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +408 -0
- package/src/__tests__/sandbox-host-parity.test.ts +950 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +253 -0
- package/src/__tests__/script-proxy-certs.test.ts +90 -0
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +177 -0
- package/src/__tests__/script-proxy-decision-trace.test.ts +156 -0
- package/src/__tests__/script-proxy-http-forwarder.test.ts +281 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +401 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +407 -0
- package/src/__tests__/script-proxy-policy-runtime.test.ts +287 -0
- package/src/__tests__/script-proxy-policy.test.ts +310 -0
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +135 -0
- package/src/__tests__/script-proxy-router.test.ts +180 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +382 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +113 -0
- package/src/__tests__/secret-allowlist.test.ts +229 -0
- package/src/__tests__/secret-ingress-handler.test.ts +99 -0
- package/src/__tests__/secret-onetime-send.test.ts +130 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +106 -0
- package/src/__tests__/secret-response-routing.test.ts +93 -0
- package/src/__tests__/secret-scanner-executor.test.ts +348 -0
- package/src/__tests__/secret-scanner.test.ts +857 -0
- package/src/__tests__/secure-keys.test.ts +323 -0
- package/src/__tests__/server-history-render.test.ts +430 -0
- package/src/__tests__/session-abort-tool-results.test.ts +240 -0
- package/src/__tests__/session-conflict-gate.test.ts +697 -0
- package/src/__tests__/session-error.test.ts +341 -0
- package/src/__tests__/session-evictor.test.ts +188 -0
- package/src/__tests__/session-load-history-repair.test.ts +222 -0
- package/src/__tests__/session-pre-run-repair.test.ts +213 -0
- package/src/__tests__/session-profile-injection.test.ts +444 -0
- package/src/__tests__/session-provider-retry-repair.test.ts +306 -0
- package/src/__tests__/session-queue.test.ts +1462 -0
- package/src/__tests__/session-runtime-assembly.test.ts +315 -0
- package/src/__tests__/session-runtime-workspace.test.ts +183 -0
- package/src/__tests__/session-skill-tools.test.ts +2431 -0
- package/src/__tests__/session-slash-known.test.ts +368 -0
- package/src/__tests__/session-slash-queue.test.ts +288 -0
- package/src/__tests__/session-slash-unknown.test.ts +271 -0
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +473 -0
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +140 -0
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +140 -0
- package/src/__tests__/session-undo.test.ts +75 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +246 -0
- package/src/__tests__/session-workspace-injection.test.ts +327 -0
- package/src/__tests__/session-workspace-tool-tracking.test.ts +240 -0
- package/src/__tests__/shared-filesystem-errors.test.ts +78 -0
- package/src/__tests__/shell-credential-ref.test.ts +187 -0
- package/src/__tests__/shell-parser-fuzz.test.ts +544 -0
- package/src/__tests__/shell-parser-property.test.ts +433 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +272 -0
- package/src/__tests__/signup-e2e.test.ts +352 -0
- package/src/__tests__/size-guard.test.ts +117 -0
- package/src/__tests__/skill-include-graph.test.ts +303 -0
- package/src/__tests__/skill-load-tool.test.ts +409 -0
- package/src/__tests__/skill-script-runner-host.test.ts +489 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +349 -0
- package/src/__tests__/skill-tool-factory.test.ts +252 -0
- package/src/__tests__/skill-tool-manifest.test.ts +658 -0
- package/src/__tests__/skill-version-hash.test.ts +182 -0
- package/src/__tests__/skills.test.ts +597 -0
- package/src/__tests__/slash-commands-catalog.test.ts +86 -0
- package/src/__tests__/slash-commands-parser.test.ts +119 -0
- package/src/__tests__/slash-commands-resolver.test.ts +193 -0
- package/src/__tests__/slash-commands-rewrite.test.ts +39 -0
- package/src/__tests__/starter-bundle.test.ts +136 -0
- package/src/__tests__/starter-task-flow.test.ts +143 -0
- package/src/__tests__/subagent-manager-notify.test.ts +372 -0
- package/src/__tests__/subagent-tools.test.ts +118 -0
- package/src/__tests__/subagent-types.test.ts +78 -0
- package/src/__tests__/swarm-orchestrator.test.ts +428 -0
- package/src/__tests__/swarm-plan-validator.test.ts +330 -0
- package/src/__tests__/swarm-recursion.test.ts +165 -0
- package/src/__tests__/swarm-router-planner.test.ts +208 -0
- package/src/__tests__/swarm-session-integration.test.ts +274 -0
- package/src/__tests__/swarm-tool.test.ts +145 -0
- package/src/__tests__/swarm-worker-backend.test.ts +129 -0
- package/src/__tests__/swarm-worker-runner.test.ts +272 -0
- package/src/__tests__/system-prompt.test.ts +461 -0
- package/src/__tests__/task-compiler.test.ts +283 -0
- package/src/__tests__/task-runner.test.ts +215 -0
- package/src/__tests__/task-scheduler.test.ts +216 -0
- package/src/__tests__/task-tools.test.ts +602 -0
- package/src/__tests__/terminal-sandbox-docker.test.ts +1064 -0
- package/src/__tests__/terminal-sandbox.integration.test.ts +178 -0
- package/src/__tests__/terminal-sandbox.test.ts +202 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +90 -0
- package/src/__tests__/test-support/computer-use-skill-harness.ts +45 -0
- package/src/__tests__/tool-audit-listener.test.ts +112 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +251 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +516 -0
- package/src/__tests__/tool-executor-redaction.test.ts +289 -0
- package/src/__tests__/tool-executor.test.ts +1971 -0
- package/src/__tests__/tool-metrics-listener.test.ts +225 -0
- package/src/__tests__/tool-notification-listener.test.ts +49 -0
- package/src/__tests__/tool-policy.test.ts +54 -0
- package/src/__tests__/tool-profiling-listener.test.ts +268 -0
- package/src/__tests__/tool-result-truncation.test.ts +217 -0
- package/src/__tests__/tool-trace-listener.test.ts +226 -0
- package/src/__tests__/top-level-renderer.test.ts +121 -0
- package/src/__tests__/top-level-scanner.test.ts +141 -0
- package/src/__tests__/trace-emitter.test.ts +173 -0
- package/src/__tests__/trust-store.test.ts +2030 -0
- package/src/__tests__/turn-commit.test.ts +219 -0
- package/src/__tests__/url-safety.test.ts +418 -0
- package/src/__tests__/weather-skill-regression.test.ts +225 -0
- package/src/__tests__/web-fetch.test.ts +869 -0
- package/src/__tests__/web-search.test.ts +584 -0
- package/src/__tests__/workspace-git-service.test.ts +750 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +347 -0
- package/src/__tests__/workspace-lifecycle.test.ts +292 -0
- package/src/agent/attachments.ts +35 -0
- package/src/agent/loop.ts +500 -0
- package/src/agent/message-types.ts +17 -0
- package/src/autonomy/autonomy-resolver.ts +60 -0
- package/src/autonomy/autonomy-store.ts +122 -0
- package/src/autonomy/disposition-mapper.ts +31 -0
- package/src/autonomy/index.ts +11 -0
- package/src/autonomy/types.ts +39 -0
- package/src/bundler/app-bundler.ts +274 -0
- package/src/bundler/bundle-scanner.ts +535 -0
- package/src/bundler/bundle-signer.ts +124 -0
- package/src/bundler/manifest.ts +21 -0
- package/src/bundler/signature-verifier.ts +184 -0
- package/src/cli/autonomy.ts +188 -0
- package/src/cli/contacts.ts +149 -0
- package/src/cli/doordash.ts +824 -0
- package/src/cli/email-guardrails.ts +200 -0
- package/src/cli/email.ts +405 -0
- package/src/cli/main-screen.tsx +155 -0
- package/src/cli.ts +935 -0
- package/src/config/bundled-skills/.gitkeep +0 -0
- package/src/config/bundled-skills/agentmail/SKILL.md +128 -0
- package/src/config/bundled-skills/agentmail/icon.svg +21 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +1348 -0
- package/src/config/bundled-skills/app-builder/TOOLS.json +279 -0
- package/src/config/bundled-skills/app-builder/icon.svg +9 -0
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +15 -0
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +18 -0
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +11 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +10 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +20 -0
- package/src/config/bundled-skills/browser/SKILL.md +28 -0
- package/src/config/bundled-skills/browser/TOOLS.json +234 -0
- package/src/config/bundled-skills/browser/tools/browser-click.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-close.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-type.ts +9 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +9 -0
- package/src/config/bundled-skills/claude-code/SKILL.md +50 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +40 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +9 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +17 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +326 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +9 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +9 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +108 -0
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +165 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +21 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +42 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +13 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +30 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +41 -0
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +18 -0
- package/src/config/bundled-skills/google-calendar/types.ts +97 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +32 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +42 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +137 -0
- package/src/config/bundled-skills/messaging/SKILL.md +126 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +357 -0
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +26 -0
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +23 -0
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +84 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +18 -0
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +124 -0
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +16 -0
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +49 -0
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +21 -0
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +28 -0
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +29 -0
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +22 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +27 -0
- package/src/config/bundled-skills/messaging/tools/shared.ts +71 -0
- package/src/config/bundled-skills/messaging/tools/slack-add-reaction.ts +25 -0
- package/src/config/bundled-skills/messaging/tools/slack-leave-channel.ts +23 -0
- package/src/config/bundled-skills/self-upgrade/SKILL.md +74 -0
- package/src/config/bundled-skills/start-the-day/SKILL.md +70 -0
- package/src/config/bundled-skills/start-the-day/icon.svg +13 -0
- package/src/config/bundled-skills/weather/SKILL.md +37 -0
- package/src/config/bundled-skills/weather/TOOLS.json +32 -0
- package/src/config/bundled-skills/weather/icon.svg +24 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +9 -0
- package/src/config/computer-use-prompt.ts +97 -0
- package/src/config/defaults.ts +186 -0
- package/src/config/loader.ts +336 -0
- package/src/config/schema.ts +1004 -0
- package/src/config/skill-state.ts +95 -0
- package/src/config/skills.ts +972 -0
- package/src/config/system-prompt.ts +927 -0
- package/src/config/templates/BOOTSTRAP.md +70 -0
- package/src/config/templates/IDENTITY.md +18 -0
- package/src/config/templates/LOOKS.md +25 -0
- package/src/config/templates/SOUL.md +37 -0
- package/src/config/templates/USER.md +19 -0
- package/src/config/types.ts +32 -0
- package/src/config/vellum-skills/deploy-fullstack-vercel/SKILL.md +179 -0
- package/src/config/vellum-skills/document-writer/SKILL.md +195 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +194 -0
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +147 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +105 -0
- package/src/contacts/contact-store.ts +410 -0
- package/src/contacts/index.ts +11 -0
- package/src/contacts/types.ts +28 -0
- package/src/context/token-estimator.ts +108 -0
- package/src/context/tool-result-truncation.ts +128 -0
- package/src/context/window-manager.ts +531 -0
- package/src/daemon/assistant-attachments.ts +679 -0
- package/src/daemon/classifier.ts +108 -0
- package/src/daemon/computer-use-session.ts +900 -0
- package/src/daemon/connection-policy.ts +41 -0
- package/src/daemon/handlers/apps.ts +446 -0
- package/src/daemon/handlers/computer-use.ts +181 -0
- package/src/daemon/handlers/config.ts +434 -0
- package/src/daemon/handlers/diagnostics.ts +334 -0
- package/src/daemon/handlers/documents.ts +184 -0
- package/src/daemon/handlers/home-base.ts +73 -0
- package/src/daemon/handlers/index.ts +355 -0
- package/src/daemon/handlers/misc.ts +323 -0
- package/src/daemon/handlers/open-bundle-handler.ts +80 -0
- package/src/daemon/handlers/publish.ts +182 -0
- package/src/daemon/handlers/sessions.ts +486 -0
- package/src/daemon/handlers/shared.ts +533 -0
- package/src/daemon/handlers/skills.ts +487 -0
- package/src/daemon/handlers/subagents.ts +122 -0
- package/src/daemon/handlers/work-items.ts +176 -0
- package/src/daemon/handlers.ts +17 -0
- package/src/daemon/history-repair.ts +214 -0
- package/src/daemon/ipc-blob-store.ts +231 -0
- package/src/daemon/ipc-contract-inventory.json +407 -0
- package/src/daemon/ipc-contract-inventory.ts +126 -0
- package/src/daemon/ipc-contract.ts +2102 -0
- package/src/daemon/ipc-protocol.ts +70 -0
- package/src/daemon/ipc-validate.ts +171 -0
- package/src/daemon/lifecycle.ts +503 -0
- package/src/daemon/main.ts +15 -0
- package/src/daemon/media-visibility-policy.ts +57 -0
- package/src/daemon/ride-shotgun-handler.ts +244 -0
- package/src/daemon/server.ts +1085 -0
- package/src/daemon/session-attachments.ts +173 -0
- package/src/daemon/session-conflict-gate.ts +219 -0
- package/src/daemon/session-dynamic-profile.ts +63 -0
- package/src/daemon/session-error.ts +269 -0
- package/src/daemon/session-evictor.ts +196 -0
- package/src/daemon/session-history.ts +437 -0
- package/src/daemon/session-memory.ts +212 -0
- package/src/daemon/session-process.ts +264 -0
- package/src/daemon/session-queue-manager.ts +81 -0
- package/src/daemon/session-runtime-assembly.ts +395 -0
- package/src/daemon/session-skill-tools.ts +237 -0
- package/src/daemon/session-slash.ts +302 -0
- package/src/daemon/session-surfaces.ts +624 -0
- package/src/daemon/session-tool-setup.ts +286 -0
- package/src/daemon/session-usage.ts +74 -0
- package/src/daemon/session-workspace.ts +19 -0
- package/src/daemon/session.ts +1651 -0
- package/src/daemon/trace-emitter.ts +82 -0
- package/src/daemon/watch-handler.ts +274 -0
- package/src/doordash/client.ts +905 -0
- package/src/doordash/queries.ts +1312 -0
- package/src/doordash/query-extractor.ts +93 -0
- package/src/doordash/session.ts +82 -0
- package/src/email/provider.ts +117 -0
- package/src/email/providers/agentmail.ts +317 -0
- package/src/email/providers/index.ts +58 -0
- package/src/email/service.ts +303 -0
- package/src/email/types.ts +126 -0
- package/src/events/bus.ts +157 -0
- package/src/events/domain-events.ts +83 -0
- package/src/events/index.ts +18 -0
- package/src/events/tool-audit-listener.ts +80 -0
- package/src/events/tool-domain-event-publisher.ts +111 -0
- package/src/events/tool-metrics-listener.ts +159 -0
- package/src/events/tool-notification-listener.ts +17 -0
- package/src/events/tool-profiling-listener.ts +158 -0
- package/src/events/tool-trace-listener.ts +75 -0
- package/src/export/formatter.ts +96 -0
- package/src/followups/followup-store.ts +166 -0
- package/src/followups/index.ts +10 -0
- package/src/followups/types.ts +23 -0
- package/src/gallery/default-gallery.ts +795 -0
- package/src/gallery/gallery-manifest.ts +24 -0
- package/src/home-base/app-link-store.ts +82 -0
- package/src/home-base/bootstrap.ts +66 -0
- package/src/home-base/prebuilt/index.html +662 -0
- package/src/home-base/prebuilt/seed-metadata.json +21 -0
- package/src/home-base/prebuilt/seed.ts +101 -0
- package/src/home-base/prebuilt-home-base-updater.ts +30 -0
- package/src/hooks/cli.ts +163 -0
- package/src/hooks/config.ts +88 -0
- package/src/hooks/discovery.ts +110 -0
- package/src/hooks/manager.ts +128 -0
- package/src/hooks/runner.ts +123 -0
- package/src/hooks/templates.ts +52 -0
- package/src/hooks/types.ts +72 -0
- package/src/index.ts +1194 -0
- package/src/instrument.ts +60 -0
- package/src/logfire.ts +99 -0
- package/src/media/gemini-image-service.ts +136 -0
- package/src/memory/account-store.ts +108 -0
- package/src/memory/admin.ts +211 -0
- package/src/memory/app-store.ts +556 -0
- package/src/memory/attachments-store.ts +453 -0
- package/src/memory/channel-delivery-store.ts +368 -0
- package/src/memory/checkpoints.ts +52 -0
- package/src/memory/clarification-resolver.ts +297 -0
- package/src/memory/conflict-store.ts +342 -0
- package/src/memory/contradiction-checker.ts +329 -0
- package/src/memory/conversation-key-store.ts +127 -0
- package/src/memory/conversation-store.ts +469 -0
- package/src/memory/db.ts +1105 -0
- package/src/memory/embedding-backend.ts +229 -0
- package/src/memory/embedding-gemini.ts +52 -0
- package/src/memory/embedding-local.ts +75 -0
- package/src/memory/embedding-ollama.ts +55 -0
- package/src/memory/embedding-openai.ts +25 -0
- package/src/memory/entity-extractor.ts +471 -0
- package/src/memory/fingerprint.ts +20 -0
- package/src/memory/indexer.ts +156 -0
- package/src/memory/items-extractor.ts +460 -0
- package/src/memory/job-handlers/backfill.ts +139 -0
- package/src/memory/job-handlers/cleanup.ts +58 -0
- package/src/memory/job-handlers/conflict.ts +99 -0
- package/src/memory/job-handlers/embedding.ts +61 -0
- package/src/memory/job-handlers/extraction.ts +123 -0
- package/src/memory/job-handlers/index-maintenance.ts +54 -0
- package/src/memory/job-handlers/summarization.ts +286 -0
- package/src/memory/job-utils.ts +170 -0
- package/src/memory/jobs-store.ts +400 -0
- package/src/memory/jobs-worker.ts +274 -0
- package/src/memory/llm-request-log-store.ts +45 -0
- package/src/memory/llm-usage-store.ts +62 -0
- package/src/memory/message-content.ts +54 -0
- package/src/memory/profile-compiler.ts +160 -0
- package/src/memory/published-pages-store.ts +137 -0
- package/src/memory/qdrant-client.ts +366 -0
- package/src/memory/qdrant-manager.ts +242 -0
- package/src/memory/query-builder.ts +45 -0
- package/src/memory/retrieval-budget.ts +30 -0
- package/src/memory/retriever.ts +653 -0
- package/src/memory/runs-store.ts +211 -0
- package/src/memory/schema.ts +529 -0
- package/src/memory/search/entity.ts +298 -0
- package/src/memory/search/formatting.ts +207 -0
- package/src/memory/search/lexical.ts +227 -0
- package/src/memory/search/ranking.ts +401 -0
- package/src/memory/search/semantic.ts +121 -0
- package/src/memory/search/types.ts +137 -0
- package/src/memory/segmenter.ts +68 -0
- package/src/memory/shared-app-links-store.ts +138 -0
- package/src/memory/tool-usage-store.ts +62 -0
- package/src/messaging/activity-analyzer.ts +76 -0
- package/src/messaging/draft-store.ts +88 -0
- package/src/messaging/index.ts +3 -0
- package/src/messaging/provider-types.ts +80 -0
- package/src/messaging/provider.ts +43 -0
- package/src/messaging/providers/gmail/adapter.ts +193 -0
- package/src/messaging/providers/gmail/client.ts +204 -0
- package/src/messaging/providers/gmail/types.ts +90 -0
- package/src/messaging/providers/slack/adapter.ts +202 -0
- package/src/messaging/providers/slack/client.ts +198 -0
- package/src/messaging/providers/slack/types.ts +119 -0
- package/src/messaging/registry.ts +34 -0
- package/src/messaging/style-analyzer.ts +158 -0
- package/src/messaging/thread-summarizer.ts +310 -0
- package/src/messaging/triage-engine.ts +321 -0
- package/src/messaging/types.ts +55 -0
- package/src/permissions/checker.ts +636 -0
- package/src/permissions/defaults.ts +243 -0
- package/src/permissions/prompter.ts +102 -0
- package/src/permissions/secret-prompter.ts +114 -0
- package/src/permissions/trust-store.ts +584 -0
- package/src/permissions/types.ts +62 -0
- package/src/playbooks/index.ts +2 -0
- package/src/playbooks/playbook-compiler.ts +90 -0
- package/src/playbooks/types.ts +55 -0
- package/src/providers/anthropic/client.ts +751 -0
- package/src/providers/failover.ts +129 -0
- package/src/providers/fireworks/client.ts +20 -0
- package/src/providers/gemini/client.ts +285 -0
- package/src/providers/ollama/client.ts +30 -0
- package/src/providers/openai/client.ts +337 -0
- package/src/providers/ratelimit.ts +93 -0
- package/src/providers/registry.ts +138 -0
- package/src/providers/retry.ts +106 -0
- package/src/providers/stream-timeout.ts +38 -0
- package/src/providers/types.ts +109 -0
- package/src/runtime/assistant-event-hub.ts +120 -0
- package/src/runtime/assistant-event.ts +82 -0
- package/src/runtime/http-server.ts +478 -0
- package/src/runtime/http-types.ts +68 -0
- package/src/runtime/routes/app-routes.ts +174 -0
- package/src/runtime/routes/attachment-routes.ts +134 -0
- package/src/runtime/routes/channel-routes.ts +342 -0
- package/src/runtime/routes/conversation-routes.ts +349 -0
- package/src/runtime/routes/run-routes.ts +223 -0
- package/src/runtime/routes/secret-routes.ts +76 -0
- package/src/runtime/run-orchestrator.ts +206 -0
- package/src/schedule/schedule-store.ts +452 -0
- package/src/schedule/scheduler.ts +168 -0
- package/src/security/encrypted-store.ts +238 -0
- package/src/security/keychain.ts +252 -0
- package/src/security/oauth2.ts +241 -0
- package/src/security/redaction.ts +89 -0
- package/src/security/secret-allowlist.ts +118 -0
- package/src/security/secret-ingress.ts +57 -0
- package/src/security/secret-scanner.ts +543 -0
- package/src/security/secure-keys.ts +180 -0
- package/src/security/token-manager.ts +141 -0
- package/src/services/published-app-updater.ts +69 -0
- package/src/services/vercel-deploy.ts +73 -0
- package/src/skills/active-skill-tools.ts +81 -0
- package/src/skills/clawhub.ts +414 -0
- package/src/skills/include-graph.ts +146 -0
- package/src/skills/managed-store.ts +233 -0
- package/src/skills/path-classifier.ts +128 -0
- package/src/skills/slash-commands.ts +174 -0
- package/src/skills/tool-manifest.ts +165 -0
- package/src/skills/version-hash.ts +110 -0
- package/src/slack/slack-webhook.ts +61 -0
- package/src/subagent/index.ts +19 -0
- package/src/subagent/manager.ts +477 -0
- package/src/subagent/types.ts +69 -0
- package/src/swarm/backend-claude-code.ts +90 -0
- package/src/swarm/index.ts +44 -0
- package/src/swarm/limits.ts +37 -0
- package/src/swarm/orchestrator.ts +279 -0
- package/src/swarm/plan-validator.ts +151 -0
- package/src/swarm/router-planner.ts +100 -0
- package/src/swarm/router-prompts.ts +36 -0
- package/src/swarm/synthesizer.ts +62 -0
- package/src/swarm/types.ts +62 -0
- package/src/swarm/worker-backend.ts +121 -0
- package/src/swarm/worker-prompts.ts +78 -0
- package/src/swarm/worker-runner.ts +164 -0
- package/src/tasks/SPEC.md +133 -0
- package/src/tasks/candidate-store.ts +86 -0
- package/src/tasks/ephemeral-permissions.ts +41 -0
- package/src/tasks/task-compiler.ts +198 -0
- package/src/tasks/task-runner.ts +85 -0
- package/src/tasks/task-scheduler.ts +20 -0
- package/src/tasks/task-store.ts +127 -0
- package/src/tools/apps/definitions.ts +59 -0
- package/src/tools/apps/executors.ts +313 -0
- package/src/tools/apps/open-proxy.ts +43 -0
- package/src/tools/apps/registry.ts +16 -0
- package/src/tools/assets/materialize.ts +218 -0
- package/src/tools/assets/search.ts +396 -0
- package/src/tools/browser/__tests__/auth-cache.test.ts +219 -0
- package/src/tools/browser/__tests__/auth-detector.test.ts +362 -0
- package/src/tools/browser/__tests__/jit-auth.test.ts +189 -0
- package/src/tools/browser/auth-cache.ts +149 -0
- package/src/tools/browser/auth-detector.ts +347 -0
- package/src/tools/browser/browser-execution.ts +979 -0
- package/src/tools/browser/browser-handoff.ts +79 -0
- package/src/tools/browser/browser-manager.ts +715 -0
- package/src/tools/browser/browser-screencast.ts +217 -0
- package/src/tools/browser/headless-browser.ts +450 -0
- package/src/tools/browser/jit-auth.ts +51 -0
- package/src/tools/browser/network-recorder.ts +348 -0
- package/src/tools/browser/network-recording-types.ts +49 -0
- package/src/tools/browser/recording-store.ts +49 -0
- package/src/tools/browser/runtime-check.ts +43 -0
- package/src/tools/claude-code/claude-code.ts +232 -0
- package/src/tools/computer-use/definitions.ts +443 -0
- package/src/tools/computer-use/registry.ts +22 -0
- package/src/tools/computer-use/request-computer-control.ts +53 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +28 -0
- package/src/tools/contacts/contact-merge.ts +87 -0
- package/src/tools/contacts/contact-search.ts +102 -0
- package/src/tools/contacts/contact-upsert.ts +137 -0
- package/src/tools/contacts/index.ts +4 -0
- package/src/tools/credentials/account-registry.ts +127 -0
- package/src/tools/credentials/broker-types.ts +107 -0
- package/src/tools/credentials/broker.ts +372 -0
- package/src/tools/credentials/domain-policy.ts +51 -0
- package/src/tools/credentials/host-pattern-match.ts +60 -0
- package/src/tools/credentials/metadata-store.ts +335 -0
- package/src/tools/credentials/policy-types.ts +52 -0
- package/src/tools/credentials/policy-validate.ts +80 -0
- package/src/tools/credentials/resolve.ts +122 -0
- package/src/tools/credentials/selection.ts +159 -0
- package/src/tools/credentials/tool-policy.ts +25 -0
- package/src/tools/credentials/vault.ts +641 -0
- package/src/tools/document/document-tool.ts +165 -0
- package/src/tools/document/editor-template.ts +237 -0
- package/src/tools/document/index.ts +5 -0
- package/src/tools/executor.ts +825 -0
- package/src/tools/filesystem/edit.ts +127 -0
- package/src/tools/filesystem/fuzzy-match.ts +202 -0
- package/src/tools/filesystem/read.ts +71 -0
- package/src/tools/filesystem/view-image.ts +199 -0
- package/src/tools/filesystem/write.ts +79 -0
- package/src/tools/followups/followup_create.ts +118 -0
- package/src/tools/followups/followup_list.ts +100 -0
- package/src/tools/followups/followup_resolve.ts +91 -0
- package/src/tools/followups/index.ts +3 -0
- package/src/tools/host-filesystem/edit.ts +125 -0
- package/src/tools/host-filesystem/read.ts +80 -0
- package/src/tools/host-filesystem/write.ts +76 -0
- package/src/tools/host-terminal/cli-discover.ts +179 -0
- package/src/tools/host-terminal/host-shell.ts +181 -0
- package/src/tools/memory/definitions.ts +69 -0
- package/src/tools/memory/handlers.ts +245 -0
- package/src/tools/memory/register.ts +66 -0
- package/src/tools/network/domain-normalize.ts +85 -0
- package/src/tools/network/script-proxy/certs.ts +237 -0
- package/src/tools/network/script-proxy/connect-tunnel.ts +82 -0
- package/src/tools/network/script-proxy/http-forwarder.ts +151 -0
- package/src/tools/network/script-proxy/index.ts +28 -0
- package/src/tools/network/script-proxy/logging.ts +196 -0
- package/src/tools/network/script-proxy/mitm-handler.ts +269 -0
- package/src/tools/network/script-proxy/policy.ts +152 -0
- package/src/tools/network/script-proxy/router.ts +60 -0
- package/src/tools/network/script-proxy/server.ts +136 -0
- package/src/tools/network/script-proxy/session-manager.ts +534 -0
- package/src/tools/network/script-proxy/types.ts +125 -0
- package/src/tools/network/url-safety.ts +227 -0
- package/src/tools/network/web-fetch.ts +701 -0
- package/src/tools/network/web-search.ts +319 -0
- package/src/tools/playbooks/index.ts +5 -0
- package/src/tools/playbooks/playbook-create.ts +140 -0
- package/src/tools/playbooks/playbook-delete.ts +76 -0
- package/src/tools/playbooks/playbook-list.ts +101 -0
- package/src/tools/playbooks/playbook-update.ts +159 -0
- package/src/tools/registry.ts +297 -0
- package/src/tools/reminder/reminder-store.ts +148 -0
- package/src/tools/reminder/reminder.ts +153 -0
- package/src/tools/schedule/create.ts +86 -0
- package/src/tools/schedule/delete.ts +54 -0
- package/src/tools/schedule/list.ts +88 -0
- package/src/tools/schedule/update.ts +97 -0
- package/src/tools/shared/filesystem/edit-engine.ts +56 -0
- package/src/tools/shared/filesystem/errors.ts +85 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +215 -0
- package/src/tools/shared/filesystem/format-diff.ts +35 -0
- package/src/tools/shared/filesystem/path-policy.ts +125 -0
- package/src/tools/shared/filesystem/size-guard.ts +41 -0
- package/src/tools/shared/filesystem/types.ts +80 -0
- package/src/tools/shared/shell-output.ts +52 -0
- package/src/tools/skills/delete-managed.ts +60 -0
- package/src/tools/skills/load.ts +139 -0
- package/src/tools/skills/sandbox-runner.ts +279 -0
- package/src/tools/skills/scaffold-managed.ts +150 -0
- package/src/tools/skills/script-contract.ts +6 -0
- package/src/tools/skills/skill-script-runner.ts +86 -0
- package/src/tools/skills/skill-tool-factory.ts +64 -0
- package/src/tools/skills/vellum-catalog.ts +217 -0
- package/src/tools/subagent/abort.ts +62 -0
- package/src/tools/subagent/index.ts +5 -0
- package/src/tools/subagent/message.ts +72 -0
- package/src/tools/subagent/read.ts +98 -0
- package/src/tools/subagent/spawn.ts +85 -0
- package/src/tools/subagent/status.ts +74 -0
- package/src/tools/swarm/delegate.ts +182 -0
- package/src/tools/system/request-permission.ts +98 -0
- package/src/tools/tasks/index.ts +25 -0
- package/src/tools/tasks/task-delete.ts +69 -0
- package/src/tools/tasks/task-list.ts +65 -0
- package/src/tools/tasks/task-run.ts +125 -0
- package/src/tools/tasks/task-save.ts +79 -0
- package/src/tools/tasks/work-item-enqueue.ts +176 -0
- package/src/tools/tasks/work-item-list.ts +86 -0
- package/src/tools/terminal/backends/docker.ts +372 -0
- package/src/tools/terminal/backends/native.ts +188 -0
- package/src/tools/terminal/backends/types.ts +26 -0
- package/src/tools/terminal/evaluate-typescript.ts +275 -0
- package/src/tools/terminal/parser.ts +393 -0
- package/src/tools/terminal/safe-env.ts +37 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +149 -0
- package/src/tools/terminal/sandbox.ts +44 -0
- package/src/tools/terminal/shell.ts +257 -0
- package/src/tools/tool-manifest.ts +250 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/ui-surface/definitions.ts +232 -0
- package/src/tools/ui-surface/registry.ts +14 -0
- package/src/tools/watch/screen-watch.ts +128 -0
- package/src/tools/watch/watch-state.ts +119 -0
- package/src/tools/watcher/create.ts +110 -0
- package/src/tools/watcher/delete.ts +53 -0
- package/src/tools/watcher/digest.ts +84 -0
- package/src/tools/watcher/list.ts +90 -0
- package/src/tools/watcher/update.ts +102 -0
- package/src/tools/weather/service.ts +551 -0
- package/src/usage/actors.ts +24 -0
- package/src/usage/types.ts +38 -0
- package/src/util/clipboard.ts +33 -0
- package/src/util/content-id.ts +16 -0
- package/src/util/diff.ts +181 -0
- package/src/util/errors.ts +129 -0
- package/src/util/logger.ts +243 -0
- package/src/util/platform.ts +607 -0
- package/src/util/pricing.ts +150 -0
- package/src/util/spinner.ts +51 -0
- package/src/util/time.ts +16 -0
- package/src/util/xml.ts +4 -0
- package/src/version.ts +3 -0
- package/src/watcher/constants.ts +11 -0
- package/src/watcher/engine.ts +199 -0
- package/src/watcher/provider-registry.ts +15 -0
- package/src/watcher/provider-types.ts +48 -0
- package/src/watcher/providers/gmail.ts +198 -0
- package/src/watcher/providers/google-calendar.ts +228 -0
- package/src/watcher/providers/slack.ts +128 -0
- package/src/watcher/watcher-store.ts +418 -0
- package/src/work-items/work-item-store.ts +91 -0
- package/src/workspace/git-service.ts +620 -0
- package/src/workspace/heartbeat-service.ts +288 -0
- package/src/workspace/top-level-renderer.ts +19 -0
- package/src/workspace/top-level-scanner.ts +41 -0
- package/src/workspace/turn-commit.ts +122 -0
- package/tsconfig.json +21 -0
- package/LICENSE +0 -674
- package/dist/cli.js +0 -569
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy server factory — creates an HTTP server configured to handle
|
|
3
|
+
* plain HTTP proxy requests via the forwarder, plain CONNECT tunnelling,
|
|
4
|
+
* and optional MITM interception for credential-injected HTTPS requests.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createServer, type Server } from 'node:http';
|
|
8
|
+
import type { ConnectionOptions } from 'node:tls';
|
|
9
|
+
import type { Socket } from 'node:net';
|
|
10
|
+
import { forwardHttpRequest, type PolicyCallback } from './http-forwarder.js';
|
|
11
|
+
import { handleConnect } from './connect-tunnel.js';
|
|
12
|
+
import { handleMitm, type RewriteCallback } from './mitm-handler.js';
|
|
13
|
+
import type { RouteDecision } from './router.js';
|
|
14
|
+
|
|
15
|
+
export interface MitmHandlerConfig {
|
|
16
|
+
/** Path to the local CA directory containing ca.pem / ca-key.pem. */
|
|
17
|
+
caDir: string;
|
|
18
|
+
/**
|
|
19
|
+
* Decide whether the CONNECT target should be MITM-intercepted.
|
|
20
|
+
* Returns a RouteDecision with action ('mitm' | 'tunnel') and a
|
|
21
|
+
* deterministic reason code for auditing.
|
|
22
|
+
*/
|
|
23
|
+
shouldIntercept: (hostname: string, port: number) => RouteDecision;
|
|
24
|
+
/** Called with the decrypted request; returns headers to merge or null to reject. */
|
|
25
|
+
rewriteCallback: RewriteCallback;
|
|
26
|
+
/** Extra TLS options for the upstream connection (e.g. custom CA for testing). */
|
|
27
|
+
upstreamTlsOptions?: Pick<ConnectionOptions, 'ca' | 'rejectUnauthorized'>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ProxyServerConfig {
|
|
31
|
+
/** Optional policy callback for credential injection / access control. */
|
|
32
|
+
policyCallback?: PolicyCallback;
|
|
33
|
+
/** Called on every forwarded request for logging. */
|
|
34
|
+
onRequest?: (method: string, url: string) => void;
|
|
35
|
+
/** When provided, CONNECT requests matching shouldIntercept are MITM-handled. */
|
|
36
|
+
mitmHandler?: MitmHandlerConfig;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse a CONNECT target of the form `host:port`.
|
|
41
|
+
*/
|
|
42
|
+
function parseConnectTarget(url: string | undefined): { host: string; port: number } | null {
|
|
43
|
+
if (!url) return null;
|
|
44
|
+
const colonIdx = url.lastIndexOf(':');
|
|
45
|
+
if (colonIdx <= 0) return null;
|
|
46
|
+
let host = url.slice(0, colonIdx);
|
|
47
|
+
const portStr = url.slice(colonIdx + 1);
|
|
48
|
+
if (!host || !portStr) return null;
|
|
49
|
+
const port = Number(portStr);
|
|
50
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) return null;
|
|
51
|
+
// Strip brackets from IPv6 literals — net.connect expects the raw address
|
|
52
|
+
if (host.startsWith('[') && host.endsWith(']')) {
|
|
53
|
+
host = host.slice(1, -1);
|
|
54
|
+
if (!host) return null;
|
|
55
|
+
}
|
|
56
|
+
return { host, port };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Create an HTTP server that acts as a forward proxy for plain HTTP
|
|
61
|
+
* requests (absolute-URL form), CONNECT tunnelling for HTTPS pass-through,
|
|
62
|
+
* and optional MITM interception for credential-injected HTTPS requests.
|
|
63
|
+
*/
|
|
64
|
+
export function createProxyServer(config: ProxyServerConfig = {}): Server {
|
|
65
|
+
const server = createServer((req, res) => {
|
|
66
|
+
if (config.onRequest && req.method && req.url) {
|
|
67
|
+
config.onRequest(req.method, req.url);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
forwardHttpRequest(req, res, config.policyCallback);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
server.on('connect', (req, clientSocket: Socket, head: Buffer) => {
|
|
74
|
+
if (config.mitmHandler) {
|
|
75
|
+
const target = parseConnectTarget(req.url);
|
|
76
|
+
const decision = target
|
|
77
|
+
? config.mitmHandler.shouldIntercept(target.host, target.port)
|
|
78
|
+
: undefined;
|
|
79
|
+
|
|
80
|
+
if (target && decision?.action === 'mitm') {
|
|
81
|
+
handleMitm(
|
|
82
|
+
clientSocket,
|
|
83
|
+
head,
|
|
84
|
+
target.host,
|
|
85
|
+
target.port,
|
|
86
|
+
config.mitmHandler.caDir,
|
|
87
|
+
config.mitmHandler.rewriteCallback,
|
|
88
|
+
config.mitmHandler.upstreamTlsOptions,
|
|
89
|
+
).catch(() => {
|
|
90
|
+
if (clientSocket.writable) {
|
|
91
|
+
clientSocket.write('HTTP/1.1 502 Bad Gateway\r\n\r\n');
|
|
92
|
+
}
|
|
93
|
+
clientSocket.destroy();
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Gate CONNECT tunnels through policyCallback the same way HTTP requests are gated
|
|
100
|
+
if (config.policyCallback) {
|
|
101
|
+
const connectTarget = parseConnectTarget(req.url);
|
|
102
|
+
if (!connectTarget) {
|
|
103
|
+
clientSocket.write('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
104
|
+
clientSocket.destroy();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (config.onRequest) {
|
|
109
|
+
config.onRequest('CONNECT', req.url!);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
config.policyCallback(connectTarget.host, connectTarget.port === 443 ? null : connectTarget.port, '/', 'https')
|
|
113
|
+
.then((extraHeaders) => {
|
|
114
|
+
if (extraHeaders === null) {
|
|
115
|
+
clientSocket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
|
|
116
|
+
clientSocket.destroy();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
handleConnect(req, clientSocket, head);
|
|
120
|
+
})
|
|
121
|
+
.catch(() => {
|
|
122
|
+
if (clientSocket.writable) {
|
|
123
|
+
clientSocket.write('HTTP/1.1 502 Bad Gateway\r\n\r\n');
|
|
124
|
+
}
|
|
125
|
+
clientSocket.destroy();
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
if (config.onRequest && req.url) {
|
|
129
|
+
config.onRequest('CONNECT', req.url);
|
|
130
|
+
}
|
|
131
|
+
handleConnect(req, clientSocket, head);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return server;
|
|
136
|
+
}
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import type { Server } from 'node:http';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { createProxyServer } from './server.js';
|
|
5
|
+
import type { ProxyServerConfig } from './server.js';
|
|
6
|
+
import { routeConnection } from './router.js';
|
|
7
|
+
import type {
|
|
8
|
+
ProxySession,
|
|
9
|
+
ProxySessionId,
|
|
10
|
+
ProxySessionConfig,
|
|
11
|
+
ProxyEnvVars,
|
|
12
|
+
ProxyApprovalCallback,
|
|
13
|
+
} from './types.js';
|
|
14
|
+
import type { PolicyCallback } from './http-forwarder.js';
|
|
15
|
+
import { evaluateRequestWithApproval } from './policy.js';
|
|
16
|
+
import { getCAPath, ensureLocalCA, ensureCombinedCABundle } from './certs.js';
|
|
17
|
+
import { matchHostPattern, compareMatchSpecificity, type HostMatchKind } from '../../credentials/host-pattern-match.js';
|
|
18
|
+
import { resolveById } from '../../credentials/resolve.js';
|
|
19
|
+
import { listCredentialMetadata } from '../../credentials/metadata-store.js';
|
|
20
|
+
import type { CredentialInjectionTemplate } from '../../credentials/policy-types.js';
|
|
21
|
+
import { getSecureKey } from '../../../security/secure-keys.js';
|
|
22
|
+
import { buildDecisionTrace, stripQueryString } from './logging.js';
|
|
23
|
+
import { getLogger } from '../../../util/logger.js';
|
|
24
|
+
|
|
25
|
+
const log = getLogger('proxy-session');
|
|
26
|
+
|
|
27
|
+
const DEFAULT_CONFIG: ProxySessionConfig = {
|
|
28
|
+
idleTimeoutMs: 5 * 60 * 1000, // 5 minutes
|
|
29
|
+
maxSessionsPerConversation: 3,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
interface ManagedSession {
|
|
33
|
+
session: ProxySession;
|
|
34
|
+
server: Server | null;
|
|
35
|
+
idleTimer: ReturnType<typeof setTimeout> | null;
|
|
36
|
+
config: ProxySessionConfig;
|
|
37
|
+
dataDir: string | null;
|
|
38
|
+
approvalCallback: ProxyApprovalCallback | null;
|
|
39
|
+
/** The host address the server is bound to (e.g. '127.0.0.1'). */
|
|
40
|
+
listenHost: string;
|
|
41
|
+
/** In-flight stop promise so concurrent callers can await the same shutdown. */
|
|
42
|
+
stopPromise: Promise<void> | null;
|
|
43
|
+
/** Path to the combined CA bundle, set only when ensureCombinedCABundle succeeds. */
|
|
44
|
+
combinedCABundlePath: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const sessions = new Map<ProxySessionId, ManagedSession>();
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Per-conversation mutex for session acquisition. Prevents concurrent
|
|
51
|
+
* proxied commands from each observing "no active session" and creating
|
|
52
|
+
* duplicate sessions (check-then-act race).
|
|
53
|
+
*/
|
|
54
|
+
const acquireLocks = new Map<string, Promise<ProxySession>>();
|
|
55
|
+
|
|
56
|
+
/** Return a defensive copy so callers cannot mutate internal state. */
|
|
57
|
+
function cloneSession(s: ProxySession): ProxySession {
|
|
58
|
+
return {
|
|
59
|
+
...s,
|
|
60
|
+
credentialIds: [...s.credentialIds],
|
|
61
|
+
createdAt: new Date(s.createdAt.getTime()),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resetIdleTimer(managed: ManagedSession): void {
|
|
66
|
+
if (managed.idleTimer !== null) {
|
|
67
|
+
clearTimeout(managed.idleTimer);
|
|
68
|
+
}
|
|
69
|
+
managed.idleTimer = setTimeout(() => {
|
|
70
|
+
if (managed.session.status === 'active') {
|
|
71
|
+
stopSession(managed.session.id).catch(() => {});
|
|
72
|
+
}
|
|
73
|
+
}, managed.config.idleTimeoutMs);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a new proxy session bound to a conversation.
|
|
78
|
+
* The session starts in 'starting' status with no port assigned yet.
|
|
79
|
+
*/
|
|
80
|
+
export function createSession(
|
|
81
|
+
conversationId: string,
|
|
82
|
+
credentialIds: string[],
|
|
83
|
+
config?: Partial<ProxySessionConfig>,
|
|
84
|
+
dataDir?: string,
|
|
85
|
+
approvalCallback?: ProxyApprovalCallback,
|
|
86
|
+
): ProxySession {
|
|
87
|
+
const merged: ProxySessionConfig = { ...DEFAULT_CONFIG, ...config };
|
|
88
|
+
|
|
89
|
+
// Enforce per-conversation limit
|
|
90
|
+
const existing = getSessionsForConversation(conversationId);
|
|
91
|
+
const liveCount = existing.filter(
|
|
92
|
+
(s) => s.status !== 'stopped',
|
|
93
|
+
).length;
|
|
94
|
+
if (liveCount >= merged.maxSessionsPerConversation) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Max sessions (${merged.maxSessionsPerConversation}) reached for conversation ${conversationId}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const session: ProxySession = {
|
|
101
|
+
id: randomUUID(),
|
|
102
|
+
conversationId,
|
|
103
|
+
credentialIds: [...credentialIds],
|
|
104
|
+
status: 'starting',
|
|
105
|
+
createdAt: new Date(),
|
|
106
|
+
port: null,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
sessions.set(session.id, {
|
|
110
|
+
session,
|
|
111
|
+
server: null,
|
|
112
|
+
idleTimer: null,
|
|
113
|
+
config: merged,
|
|
114
|
+
dataDir: dataDir ?? null,
|
|
115
|
+
approvalCallback: approvalCallback ?? null,
|
|
116
|
+
listenHost: '127.0.0.1',
|
|
117
|
+
stopPromise: null,
|
|
118
|
+
combinedCABundlePath: null,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return cloneSession(session);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Start the proxy session — opens an HTTP server on an ephemeral port.
|
|
126
|
+
* When the session has credential IDs with injection templates, the proxy
|
|
127
|
+
* is configured with a MITM handler that selectively intercepts HTTPS
|
|
128
|
+
* connections to credential-matched hosts.
|
|
129
|
+
*/
|
|
130
|
+
export async function startSession(sessionId: ProxySessionId, options?: { listenHost?: string }): Promise<ProxySession> {
|
|
131
|
+
const managed = sessions.get(sessionId);
|
|
132
|
+
if (!managed) throw new Error(`Session not found: ${sessionId}`);
|
|
133
|
+
if (managed.session.status !== 'starting') {
|
|
134
|
+
throw new Error(`Session ${sessionId} is ${managed.session.status}, expected starting`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const config: ProxyServerConfig = {};
|
|
138
|
+
|
|
139
|
+
// Build a templates map from credential metadata so the router and policy
|
|
140
|
+
// engine can match request targets against injection host patterns.
|
|
141
|
+
const templates = new Map<string, CredentialInjectionTemplate[]>();
|
|
142
|
+
for (const credId of managed.session.credentialIds) {
|
|
143
|
+
const resolved = resolveById(credId);
|
|
144
|
+
if (resolved?.injectionTemplates?.length) {
|
|
145
|
+
templates.set(credId, resolved.injectionTemplates);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (managed.dataDir && managed.session.credentialIds.length > 0) {
|
|
150
|
+
const caDir = join(managed.dataDir, 'proxy-ca');
|
|
151
|
+
|
|
152
|
+
if (templates.size > 0) {
|
|
153
|
+
// Ensure the CA directory and cert/key exist before starting MITM.
|
|
154
|
+
// If this fails (e.g. missing openssl, unwritable dir), clean up the
|
|
155
|
+
// session so it doesn't linger as 'starting' and count toward the
|
|
156
|
+
// per-conversation limit.
|
|
157
|
+
try {
|
|
158
|
+
await ensureLocalCA(managed.dataDir);
|
|
159
|
+
// Build a combined CA bundle (system roots + proxy CA) so
|
|
160
|
+
// non-Node clients like curl, Python, and Go trust the proxy's
|
|
161
|
+
// leaf certs via SSL_CERT_FILE (see getSessionEnv).
|
|
162
|
+
managed.combinedCABundlePath = await ensureCombinedCABundle(managed.dataDir);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
sessions.delete(sessionId);
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
config.mitmHandler = {
|
|
168
|
+
caDir,
|
|
169
|
+
shouldIntercept: (hostname: string, port: number) =>
|
|
170
|
+
routeConnection(hostname, port, managed.session.credentialIds, templates),
|
|
171
|
+
rewriteCallback: async (req) => {
|
|
172
|
+
// Per-credential best-match selection, mirroring the policy engine's
|
|
173
|
+
// specificity logic (PR 04). For each credential, pick the single
|
|
174
|
+
// best header template by specificity (exact > wildcard).
|
|
175
|
+
const perCredentialBest: { credId: string; tpl: CredentialInjectionTemplate }[] = [];
|
|
176
|
+
|
|
177
|
+
for (const [credId, tpls] of templates) {
|
|
178
|
+
let bestMatch: HostMatchKind = 'none';
|
|
179
|
+
let bestCandidates: CredentialInjectionTemplate[] = [];
|
|
180
|
+
|
|
181
|
+
for (const tpl of tpls) {
|
|
182
|
+
if (tpl.injectionType === 'query') continue;
|
|
183
|
+
const match = matchHostPattern(req.hostname, tpl.hostPattern, { includeApexForWildcard: true });
|
|
184
|
+
if (match === 'none') continue;
|
|
185
|
+
|
|
186
|
+
const cmp = compareMatchSpecificity(match, bestMatch);
|
|
187
|
+
if (cmp < 0) {
|
|
188
|
+
bestMatch = match;
|
|
189
|
+
bestCandidates = [tpl];
|
|
190
|
+
} else if (cmp === 0) {
|
|
191
|
+
bestCandidates.push(tpl);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (bestCandidates.length === 1) {
|
|
196
|
+
perCredentialBest.push({ credId, tpl: bestCandidates[0] });
|
|
197
|
+
} else if (bestCandidates.length > 1) {
|
|
198
|
+
// Same credential, same-specificity tie — ambiguous, block
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (perCredentialBest.length === 0) return req.headers;
|
|
204
|
+
// Cross-credential ambiguity — block
|
|
205
|
+
if (perCredentialBest.length > 1) return null;
|
|
206
|
+
|
|
207
|
+
const { credId, tpl } = perCredentialBest[0];
|
|
208
|
+
log.debug({ host: req.hostname, pattern: tpl.hostPattern, credentialId: credId }, 'MITM rewrite: injecting credential');
|
|
209
|
+
|
|
210
|
+
if (tpl.injectionType === 'header' && tpl.headerName) {
|
|
211
|
+
const resolved = resolveById(credId);
|
|
212
|
+
if (!resolved) return req.headers;
|
|
213
|
+
const value = getSecureKey(resolved.storageKey);
|
|
214
|
+
if (!value) return req.headers;
|
|
215
|
+
|
|
216
|
+
req.headers[tpl.headerName.toLowerCase()] =
|
|
217
|
+
(tpl.valuePrefix ?? '') + value;
|
|
218
|
+
return req.headers;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return req.headers;
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Cache the full credential registry with a TTL so the policy callback
|
|
228
|
+
// doesn't hit disk on every proxied request (listCredentialMetadata uses
|
|
229
|
+
// synchronous readFileSync + JSON.parse) while still picking up changes
|
|
230
|
+
// to credential metadata within the session lifetime.
|
|
231
|
+
let allKnownCache: CredentialInjectionTemplate[] | null = null;
|
|
232
|
+
let allKnownCacheTime = 0;
|
|
233
|
+
const CACHE_TTL_MS = 30_000; // 30 seconds
|
|
234
|
+
|
|
235
|
+
function getAllKnown(): CredentialInjectionTemplate[] {
|
|
236
|
+
const now = Date.now();
|
|
237
|
+
if (!allKnownCache || now - allKnownCacheTime > CACHE_TTL_MS) {
|
|
238
|
+
allKnownCache = [];
|
|
239
|
+
for (const meta of listCredentialMetadata()) {
|
|
240
|
+
if (meta.injectionTemplates?.length) {
|
|
241
|
+
allKnownCache.push(...meta.injectionTemplates);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
allKnownCacheTime = now;
|
|
245
|
+
}
|
|
246
|
+
return allKnownCache;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Build the policy callback for HTTP/CONNECT request gating
|
|
250
|
+
const policyCallback: PolicyCallback = async (hostname: string, port: number | null, reqPath: string, scheme: 'http' | 'https') => {
|
|
251
|
+
|
|
252
|
+
const decision = evaluateRequestWithApproval(
|
|
253
|
+
hostname, port, reqPath,
|
|
254
|
+
managed.session.credentialIds, templates, getAllKnown(), scheme,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
log.debug({ trace: buildDecisionTrace(hostname, port, stripQueryString(reqPath), scheme, decision) }, 'Policy decision');
|
|
258
|
+
|
|
259
|
+
switch (decision.kind) {
|
|
260
|
+
case 'matched': {
|
|
261
|
+
// Inject the credential value into the outbound request headers.
|
|
262
|
+
// Secret values are read from secure storage at injection time and
|
|
263
|
+
// MUST NEVER be logged — sanitizeHeaders in logging.ts handles redaction.
|
|
264
|
+
const { credentialId, template } = decision;
|
|
265
|
+
const resolved = resolveById(credentialId);
|
|
266
|
+
if (!resolved) return {};
|
|
267
|
+
const value = getSecureKey(resolved.storageKey);
|
|
268
|
+
if (!value) return {};
|
|
269
|
+
|
|
270
|
+
if (template.injectionType === 'header' && template.headerName) {
|
|
271
|
+
const headerValue = (template.valuePrefix ?? '') + value;
|
|
272
|
+
return { [template.headerName.toLowerCase()]: headerValue };
|
|
273
|
+
}
|
|
274
|
+
// Query param injection is handled via URL rewriting in the MITM path
|
|
275
|
+
return {};
|
|
276
|
+
}
|
|
277
|
+
case 'ambiguous':
|
|
278
|
+
return null; // block — can't auto-resolve
|
|
279
|
+
case 'ask_missing_credential':
|
|
280
|
+
case 'ask_unauthenticated':
|
|
281
|
+
if (managed.approvalCallback) {
|
|
282
|
+
const approved = await managed.approvalCallback({
|
|
283
|
+
decision,
|
|
284
|
+
sessionId: managed.session.id,
|
|
285
|
+
});
|
|
286
|
+
return approved ? {} : null;
|
|
287
|
+
}
|
|
288
|
+
return decision.kind === 'ask_unauthenticated' ? {} : null;
|
|
289
|
+
case 'missing':
|
|
290
|
+
return null;
|
|
291
|
+
case 'unauthenticated':
|
|
292
|
+
return {};
|
|
293
|
+
default:
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
config.policyCallback = policyCallback;
|
|
299
|
+
|
|
300
|
+
const server = createProxyServer(config);
|
|
301
|
+
|
|
302
|
+
const listenHost = options?.listenHost ?? '127.0.0.1';
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
return await new Promise<ProxySession>((resolve, reject) => {
|
|
306
|
+
server.listen(0, listenHost, () => {
|
|
307
|
+
const addr = server.address();
|
|
308
|
+
if (!addr || typeof addr === 'string') {
|
|
309
|
+
reject(new Error('Failed to get server address'));
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
managed.server = server;
|
|
313
|
+
managed.session.port = addr.port;
|
|
314
|
+
managed.session.status = 'active';
|
|
315
|
+
managed.listenHost = listenHost;
|
|
316
|
+
resetIdleTimer(managed);
|
|
317
|
+
resolve(cloneSession(managed.session));
|
|
318
|
+
});
|
|
319
|
+
server.on('error', reject);
|
|
320
|
+
});
|
|
321
|
+
} catch (err) {
|
|
322
|
+
// Clean up: close the server if it started, and remove the session so it
|
|
323
|
+
// doesn't linger as 'starting' and block future session creation.
|
|
324
|
+
server.close(() => {});
|
|
325
|
+
sessions.delete(sessionId);
|
|
326
|
+
throw err;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Gracefully stop a session — closes the HTTP server and clears the idle timer.
|
|
332
|
+
*/
|
|
333
|
+
export async function stopSession(sessionId: ProxySessionId): Promise<void> {
|
|
334
|
+
const managed = sessions.get(sessionId);
|
|
335
|
+
if (!managed) throw new Error(`Session not found: ${sessionId}`);
|
|
336
|
+
if (managed.session.status === 'stopped') return;
|
|
337
|
+
|
|
338
|
+
// If a shutdown is already in flight, await it instead of returning early.
|
|
339
|
+
if (managed.session.status === 'stopping' && managed.stopPromise) {
|
|
340
|
+
return managed.stopPromise;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
managed.session.status = 'stopping';
|
|
344
|
+
|
|
345
|
+
const doStop = async () => {
|
|
346
|
+
if (managed.idleTimer !== null) {
|
|
347
|
+
clearTimeout(managed.idleTimer);
|
|
348
|
+
managed.idleTimer = null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (managed.server) {
|
|
352
|
+
await new Promise<void>((resolve, reject) => {
|
|
353
|
+
managed.server!.close((err) => (err ? reject(err) : resolve()));
|
|
354
|
+
});
|
|
355
|
+
managed.server = null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
managed.session.status = 'stopped';
|
|
359
|
+
managed.session.port = null;
|
|
360
|
+
managed.approvalCallback = null;
|
|
361
|
+
managed.stopPromise = null;
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
managed.stopPromise = doStop();
|
|
365
|
+
return managed.stopPromise;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Build environment variables to inject into a subprocess so its HTTP
|
|
370
|
+
* traffic flows through this proxy session.
|
|
371
|
+
*/
|
|
372
|
+
export function getSessionEnv(
|
|
373
|
+
sessionId: ProxySessionId,
|
|
374
|
+
options?: { dockerMode?: boolean },
|
|
375
|
+
): ProxyEnvVars {
|
|
376
|
+
const managed = sessions.get(sessionId);
|
|
377
|
+
if (!managed) throw new Error(`Session not found: ${sessionId}`);
|
|
378
|
+
if (managed.session.status !== 'active' || managed.session.port === null) {
|
|
379
|
+
throw new Error(`Session ${sessionId} is not active`);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Touch the idle timer on access
|
|
383
|
+
resetIdleTimer(managed);
|
|
384
|
+
|
|
385
|
+
// Inside Docker, 127.0.0.1 is the container's own loopback — use
|
|
386
|
+
// host.docker.internal so traffic reaches the host-side proxy.
|
|
387
|
+
const host = options?.dockerMode ? 'host.docker.internal' : '127.0.0.1';
|
|
388
|
+
const proxyUrl = `http://${host}:${managed.session.port}`;
|
|
389
|
+
const env: ProxyEnvVars = {
|
|
390
|
+
HTTP_PROXY: proxyUrl,
|
|
391
|
+
HTTPS_PROXY: proxyUrl,
|
|
392
|
+
NO_PROXY: 'localhost,127.0.0.1,::1',
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
if (managed.dataDir) {
|
|
396
|
+
env.NODE_EXTRA_CA_CERTS = getCAPath(managed.dataDir);
|
|
397
|
+
// Combined bundle lets non-Node clients (curl, Python, Go) trust
|
|
398
|
+
// the proxy CA alongside system roots via SSL_CERT_FILE.
|
|
399
|
+
// Only set when the bundle was actually created — pointing at a
|
|
400
|
+
// missing file would replace the system trust store with nothing.
|
|
401
|
+
if (managed.combinedCABundlePath) {
|
|
402
|
+
env.SSL_CERT_FILE = managed.combinedCABundlePath;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return env;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** Sorted comparison so order doesn't matter. */
|
|
410
|
+
function credentialIdsMatch(a: string[], b: string[]): boolean {
|
|
411
|
+
if (a.length !== b.length) return false;
|
|
412
|
+
const sa = [...a].sort();
|
|
413
|
+
const sb = [...b].sort();
|
|
414
|
+
return sa.every((v, i) => v === sb[i]);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Atomically acquire a proxy session for a conversation — reuses an active
|
|
419
|
+
* session or creates + starts a new one. Serialized per conversation so
|
|
420
|
+
* concurrent callers share the same session instead of each spawning one.
|
|
421
|
+
*
|
|
422
|
+
* If the active session was created with different `credentialIds`, it is
|
|
423
|
+
* stopped and a fresh session is created so callers always get a session
|
|
424
|
+
* bound to the requested credentials.
|
|
425
|
+
*
|
|
426
|
+
* Returns `{ session, created }` so the caller knows whether it owns the
|
|
427
|
+
* session lifecycle (and should stop it) or is borrowing a shared one.
|
|
428
|
+
*/
|
|
429
|
+
export async function getOrStartSession(
|
|
430
|
+
conversationId: string,
|
|
431
|
+
credentialIds: string[],
|
|
432
|
+
config?: Partial<ProxySessionConfig>,
|
|
433
|
+
dataDir?: string,
|
|
434
|
+
approvalCallback?: ProxyApprovalCallback,
|
|
435
|
+
options?: { listenHost?: string },
|
|
436
|
+
): Promise<{ session: ProxySession; created: boolean }> {
|
|
437
|
+
const requestedHost = options?.listenHost ?? '127.0.0.1';
|
|
438
|
+
|
|
439
|
+
// Fast path — session already active with matching credentials and listen host, no lock needed.
|
|
440
|
+
const existing = getActiveSession(conversationId);
|
|
441
|
+
if (existing && credentialIdsMatch(existing.credentialIds, credentialIds)) {
|
|
442
|
+
const managed = sessions.get(existing.id);
|
|
443
|
+
if (managed && managed.listenHost === requestedHost) {
|
|
444
|
+
return { session: existing, created: false };
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// If credentials don't match (or no session exists), fall through to the
|
|
448
|
+
// lock-protected section. Stopping a mismatched session outside the lock
|
|
449
|
+
// would let another caller slip in and create a different-credential session.
|
|
450
|
+
|
|
451
|
+
// Serialize: if another caller is already creating a session for this
|
|
452
|
+
// conversation, wait for it rather than creating a second one.
|
|
453
|
+
// Loop so that after a credential-mismatch teardown we re-check for a new
|
|
454
|
+
// inflight lock — otherwise 3+ concurrent callers with different credentials
|
|
455
|
+
// can all fall through and create duplicate sessions.
|
|
456
|
+
for (;;) {
|
|
457
|
+
const inflight = acquireLocks.get(conversationId);
|
|
458
|
+
if (!inflight) break;
|
|
459
|
+
const session = await inflight;
|
|
460
|
+
if (credentialIdsMatch(session.credentialIds, credentialIds)) {
|
|
461
|
+
const m = sessions.get(session.id);
|
|
462
|
+
if (m && m.listenHost === requestedHost) {
|
|
463
|
+
return { session, created: false };
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// Credential or listenHost mismatch — tear down and loop back to re-check
|
|
467
|
+
// whether another waiter has already started a replacement session.
|
|
468
|
+
await stopSession(session.id);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const promise = (async () => {
|
|
472
|
+
// Re-check after winning the lock — a session may have become active
|
|
473
|
+
// between our initial check and acquiring the lock.
|
|
474
|
+
const recheck = getActiveSession(conversationId);
|
|
475
|
+
if (recheck) {
|
|
476
|
+
const m = sessions.get(recheck.id);
|
|
477
|
+
if (credentialIdsMatch(recheck.credentialIds, credentialIds) && m && m.listenHost === requestedHost) {
|
|
478
|
+
return { session: recheck, created: false };
|
|
479
|
+
}
|
|
480
|
+
await stopSession(recheck.id);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const session = createSession(conversationId, credentialIds, config, dataDir, approvalCallback);
|
|
484
|
+
const started = await startSession(session.id, options);
|
|
485
|
+
return { session: started, created: true };
|
|
486
|
+
})();
|
|
487
|
+
|
|
488
|
+
// Wrap the inner promise to extract just the session for lock waiters.
|
|
489
|
+
const sessionPromise = promise.then((r) => r.session);
|
|
490
|
+
sessionPromise.catch(() => {}); // Rejection handled by `await promise` below
|
|
491
|
+
acquireLocks.set(conversationId, sessionPromise);
|
|
492
|
+
try {
|
|
493
|
+
return await promise;
|
|
494
|
+
} finally {
|
|
495
|
+
acquireLocks.delete(conversationId);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Find an active session for a conversation (returns the first match).
|
|
501
|
+
*/
|
|
502
|
+
export function getActiveSession(conversationId: string): ProxySession | undefined {
|
|
503
|
+
for (const managed of sessions.values()) {
|
|
504
|
+
if (
|
|
505
|
+
managed.session.conversationId === conversationId &&
|
|
506
|
+
managed.session.status === 'active'
|
|
507
|
+
) {
|
|
508
|
+
return cloneSession(managed.session);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return undefined;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Get all sessions for a given conversation.
|
|
516
|
+
*/
|
|
517
|
+
export function getSessionsForConversation(conversationId: string): ProxySession[] {
|
|
518
|
+
const result: ProxySession[] = [];
|
|
519
|
+
for (const managed of sessions.values()) {
|
|
520
|
+
if (managed.session.conversationId === conversationId) {
|
|
521
|
+
result.push(cloneSession(managed.session));
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Stop all sessions and clear internal state. Useful for daemon shutdown.
|
|
529
|
+
*/
|
|
530
|
+
export async function stopAllSessions(): Promise<void> {
|
|
531
|
+
const ids = [...sessions.keys()];
|
|
532
|
+
await Promise.all(ids.map((id) => stopSession(id).catch(() => {})));
|
|
533
|
+
sessions.clear();
|
|
534
|
+
}
|