apex-code 0.0.1-alpha.0 → 0.0.1-alpha.10
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/CHANGELOG.md +471 -0
- package/README.md +74 -680
- package/dist/cli/args.d.ts +21 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +119 -15
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +3 -3
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/concurrent-session.d.ts +3 -0
- package/dist/cli/concurrent-session.d.ts.map +1 -0
- package/dist/cli/concurrent-session.js +13 -0
- package/dist/cli/concurrent-session.js.map +1 -0
- package/dist/cli/cost-command.d.ts +19 -0
- package/dist/cli/cost-command.d.ts.map +1 -0
- package/dist/cli/cost-command.js +107 -0
- package/dist/cli/cost-command.js.map +1 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +99 -16
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -20
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +28 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +140 -4
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +121 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +364 -123
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +17 -14
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +11 -10
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +41 -32
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context/deferred-schemas.d.ts +92 -0
- package/dist/core/context/deferred-schemas.d.ts.map +1 -0
- package/dist/core/context/deferred-schemas.js +74 -0
- package/dist/core/context/deferred-schemas.js.map +1 -0
- package/dist/core/context/eviction.d.ts +47 -0
- package/dist/core/context/eviction.d.ts.map +1 -0
- package/dist/core/context/eviction.js +83 -0
- package/dist/core/context/eviction.js.map +1 -0
- package/dist/core/context/pipeline.d.ts +90 -0
- package/dist/core/context/pipeline.d.ts.map +1 -0
- package/dist/core/context/pipeline.js +109 -0
- package/dist/core/context/pipeline.js.map +1 -0
- package/dist/core/credential-failover.d.ts +30 -0
- package/dist/core/credential-failover.d.ts.map +1 -0
- package/dist/core/credential-failover.js +46 -0
- package/dist/core/credential-failover.js.map +1 -0
- package/dist/core/credential-pool.d.ts +60 -0
- package/dist/core/credential-pool.d.ts.map +1 -0
- package/dist/core/credential-pool.js +84 -0
- package/dist/core/credential-pool.js.map +1 -0
- package/dist/core/defaults.d.ts +1 -0
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js +9 -0
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/delegation/agents.d.ts +15 -0
- package/dist/core/delegation/agents.d.ts.map +1 -0
- package/dist/core/delegation/agents.js +55 -0
- package/dist/core/delegation/agents.js.map +1 -0
- package/dist/core/delegation/ceiling.d.ts +29 -0
- package/dist/core/delegation/ceiling.d.ts.map +1 -0
- package/dist/core/delegation/ceiling.js +34 -0
- package/dist/core/delegation/ceiling.js.map +1 -0
- package/dist/core/delegation/runtime.d.ts +94 -0
- package/dist/core/delegation/runtime.d.ts.map +1 -0
- package/dist/core/delegation/runtime.js +117 -0
- package/dist/core/delegation/runtime.js.map +1 -0
- package/dist/core/durable-state/daemon.d.ts +37 -0
- package/dist/core/durable-state/daemon.d.ts.map +1 -0
- package/dist/core/durable-state/daemon.js +62 -0
- package/dist/core/durable-state/daemon.js.map +1 -0
- package/dist/core/durable-state/provenance.d.ts +7 -0
- package/dist/core/durable-state/provenance.d.ts.map +1 -0
- package/dist/core/durable-state/provenance.js +24 -0
- package/dist/core/durable-state/provenance.js.map +1 -0
- package/dist/core/durable-state/sqlite.d.ts +84 -0
- package/dist/core/durable-state/sqlite.d.ts.map +1 -0
- package/dist/core/durable-state/sqlite.js +355 -0
- package/dist/core/durable-state/sqlite.js.map +1 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.d.ts.map +1 -0
- package/dist/core/environment.js +69 -0
- package/dist/core/environment.js.map +1 -0
- package/dist/core/evidence-policy.d.ts +17 -0
- package/dist/core/evidence-policy.d.ts.map +1 -0
- package/dist/core/evidence-policy.js +25 -0
- package/dist/core/evidence-policy.js.map +1 -0
- package/dist/core/evidence.d.ts +16 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +51 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +6 -1
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +115 -48
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +44 -9
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +1 -2
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -17
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/http-idle-timeout.d.ts +12 -0
- package/dist/core/http-idle-timeout.d.ts.map +1 -0
- package/dist/core/http-idle-timeout.js +27 -0
- package/dist/core/http-idle-timeout.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +38 -13
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +26 -5
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/lsp/client.d.ts +78 -0
- package/dist/core/lsp/client.d.ts.map +1 -0
- package/dist/core/lsp/client.js +494 -0
- package/dist/core/lsp/client.js.map +1 -0
- package/dist/core/lsp/diagnostics.d.ts +47 -0
- package/dist/core/lsp/diagnostics.d.ts.map +1 -0
- package/dist/core/lsp/diagnostics.js +224 -0
- package/dist/core/lsp/diagnostics.js.map +1 -0
- package/dist/core/lsp/pool.d.ts +48 -0
- package/dist/core/lsp/pool.d.ts.map +1 -0
- package/dist/core/lsp/pool.js +150 -0
- package/dist/core/lsp/pool.js.map +1 -0
- package/dist/core/lsp/registry.d.ts +49 -0
- package/dist/core/lsp/registry.d.ts.map +1 -0
- package/dist/core/lsp/registry.js +215 -0
- package/dist/core/lsp/registry.js.map +1 -0
- package/dist/core/lsp/status.d.ts +23 -0
- package/dist/core/lsp/status.d.ts.map +1 -0
- package/dist/core/lsp/status.js +35 -0
- package/dist/core/lsp/status.js.map +1 -0
- package/dist/core/lsp/sync.d.ts +13 -0
- package/dist/core/lsp/sync.d.ts.map +1 -0
- package/dist/core/lsp/sync.js +71 -0
- package/dist/core/lsp/sync.js.map +1 -0
- package/dist/core/model-config.d.ts +18 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +25 -6
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts +21 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +73 -8
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +73 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +225 -8
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +2 -1
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/observability/aggregate.d.ts +21 -0
- package/dist/core/observability/aggregate.d.ts.map +1 -0
- package/dist/core/observability/aggregate.js +36 -0
- package/dist/core/observability/aggregate.js.map +1 -0
- package/dist/core/observability/otlp.d.ts +66 -0
- package/dist/core/observability/otlp.d.ts.map +1 -0
- package/dist/core/observability/otlp.js +95 -0
- package/dist/core/observability/otlp.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +40 -16
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions/gate.d.ts +42 -0
- package/dist/core/permissions/gate.d.ts.map +1 -0
- package/dist/core/permissions/gate.js +72 -0
- package/dist/core/permissions/gate.js.map +1 -0
- package/dist/core/permissions/modes.d.ts +18 -0
- package/dist/core/permissions/modes.d.ts.map +1 -0
- package/dist/core/permissions/modes.js +57 -0
- package/dist/core/permissions/modes.js.map +1 -0
- package/dist/core/permissions/responder.d.ts +30 -0
- package/dist/core/permissions/responder.d.ts.map +1 -0
- package/dist/core/permissions/responder.js +32 -0
- package/dist/core/permissions/responder.js.map +1 -0
- package/dist/core/permissions/rules.d.ts +34 -0
- package/dist/core/permissions/rules.d.ts.map +1 -0
- package/dist/core/permissions/rules.js +74 -0
- package/dist/core/permissions/rules.js.map +1 -0
- package/dist/core/permissions/startup.d.ts +45 -0
- package/dist/core/permissions/startup.d.ts.map +1 -0
- package/dist/core/permissions/startup.js +63 -0
- package/dist/core/permissions/startup.js.map +1 -0
- package/dist/core/permissions/store.d.ts +114 -0
- package/dist/core/permissions/store.d.ts.map +1 -0
- package/dist/core/permissions/store.js +229 -0
- package/dist/core/permissions/store.js.map +1 -0
- package/dist/core/pi-manifest.d.ts.map +1 -1
- package/dist/core/pi-manifest.js +2 -1
- package/dist/core/pi-manifest.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js +6 -7
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +2 -2
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +22 -17
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +3 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sandbox/bwrap-arguments.d.ts +52 -0
- package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
- package/dist/core/sandbox/bwrap-arguments.js +86 -0
- package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
- package/dist/core/sandbox/child-entry.d.ts +2 -0
- package/dist/core/sandbox/child-entry.d.ts.map +1 -0
- package/dist/core/sandbox/child-entry.js +22 -0
- package/dist/core/sandbox/child-entry.js.map +1 -0
- package/dist/core/sandbox/cli-launch.d.ts +88 -0
- package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
- package/dist/core/sandbox/cli-launch.js +272 -0
- package/dist/core/sandbox/cli-launch.js.map +1 -0
- package/dist/core/sandbox/cli-supervisor.d.ts +30 -0
- package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/cli-supervisor.js +123 -0
- package/dist/core/sandbox/cli-supervisor.js.map +1 -0
- package/dist/core/sandbox/default-hosts.d.ts +28 -0
- package/dist/core/sandbox/default-hosts.d.ts.map +1 -0
- package/dist/core/sandbox/default-hosts.js +69 -0
- package/dist/core/sandbox/default-hosts.js.map +1 -0
- package/dist/core/sandbox/full-access.d.ts +28 -0
- package/dist/core/sandbox/full-access.d.ts.map +1 -0
- package/dist/core/sandbox/full-access.js +63 -0
- package/dist/core/sandbox/full-access.js.map +1 -0
- package/dist/core/sandbox/git-identity.d.ts +57 -0
- package/dist/core/sandbox/git-identity.d.ts.map +1 -0
- package/dist/core/sandbox/git-identity.js +78 -0
- package/dist/core/sandbox/git-identity.js.map +1 -0
- package/dist/core/sandbox/host-approval.d.ts +42 -0
- package/dist/core/sandbox/host-approval.d.ts.map +1 -0
- package/dist/core/sandbox/host-approval.js +99 -0
- package/dist/core/sandbox/host-approval.js.map +1 -0
- package/dist/core/sandbox/linux-backend.d.ts +46 -0
- package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
- package/dist/core/sandbox/linux-backend.js +304 -0
- package/dist/core/sandbox/linux-backend.js.map +1 -0
- package/dist/core/sandbox/macos-backend.d.ts +28 -0
- package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
- package/dist/core/sandbox/macos-backend.js +313 -0
- package/dist/core/sandbox/macos-backend.js.map +1 -0
- package/dist/core/sandbox/network-proxy.d.ts +38 -0
- package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/network-proxy.js +153 -0
- package/dist/core/sandbox/network-proxy.js.map +1 -0
- package/dist/core/sandbox/network-refusal.d.ts +24 -0
- package/dist/core/sandbox/network-refusal.d.ts.map +1 -0
- package/dist/core/sandbox/network-refusal.js +72 -0
- package/dist/core/sandbox/network-refusal.js.map +1 -0
- package/dist/core/sandbox/policy.d.ts +40 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -0
- package/dist/core/sandbox/policy.js +55 -0
- package/dist/core/sandbox/policy.js.map +1 -0
- package/dist/core/sandbox/profiles.d.ts +25 -0
- package/dist/core/sandbox/profiles.d.ts.map +1 -0
- package/dist/core/sandbox/profiles.js +23 -0
- package/dist/core/sandbox/profiles.js.map +1 -0
- package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
- package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-client.js +86 -0
- package/dist/core/sandbox/rpc/command-client.js.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.js +120 -0
- package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
- package/dist/core/sandbox/rpc/credential-client.d.ts +20 -0
- package/dist/core/sandbox/rpc/credential-client.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/credential-client.js +170 -0
- package/dist/core/sandbox/rpc/credential-client.js.map +1 -0
- package/dist/core/sandbox/rpc/credential-proxy.d.ts +44 -0
- package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/credential-proxy.js +287 -0
- package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -0
- package/dist/core/sandbox/rpc/framing.d.ts +35 -0
- package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/framing.js +114 -0
- package/dist/core/sandbox/rpc/framing.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts +40 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js +152 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +48 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js +142 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
- package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
- package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor-temp.js +21 -0
- package/dist/core/sandbox/supervisor-temp.js.map +1 -0
- package/dist/core/sandbox/supervisor.d.ts +51 -0
- package/dist/core/sandbox/supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor.js +18 -0
- package/dist/core/sandbox/supervisor.js.map +1 -0
- package/dist/core/sandbox/terminal-handoff.d.ts +45 -0
- package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
- package/dist/core/sandbox/terminal-handoff.js +176 -0
- package/dist/core/sandbox/terminal-handoff.js.map +1 -0
- package/dist/core/sandbox/terminal-size.d.ts +40 -0
- package/dist/core/sandbox/terminal-size.d.ts.map +1 -0
- package/dist/core/sandbox/terminal-size.js +105 -0
- package/dist/core/sandbox/terminal-size.js.map +1 -0
- package/dist/core/sandbox/violations.d.ts +23 -0
- package/dist/core/sandbox/violations.d.ts.map +1 -0
- package/dist/core/sandbox/violations.js +30 -0
- package/dist/core/sandbox/violations.js.map +1 -0
- package/dist/core/sdk.d.ts +32 -41
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +161 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +4 -0
- package/dist/core/session-export.d.ts.map +1 -0
- package/dist/core/session-export.js +32 -0
- package/dist/core/session-export.js.map +1 -0
- package/dist/core/session-lease.d.ts +31 -0
- package/dist/core/session-lease.d.ts.map +1 -0
- package/dist/core/session-lease.js +138 -0
- package/dist/core/session-lease.js.map +1 -0
- package/dist/core/session-manager.d.ts +46 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +62 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-share.d.ts +31 -0
- package/dist/core/session-share.d.ts.map +1 -0
- package/dist/core/session-share.js +45 -0
- package/dist/core/session-share.js.map +1 -0
- package/dist/core/settings-diagnostics.d.ts +9 -0
- package/dist/core/settings-diagnostics.d.ts.map +1 -0
- package/dist/core/settings-diagnostics.js +21 -0
- package/dist/core/settings-diagnostics.js.map +1 -0
- package/dist/core/settings-manager.d.ts +92 -9
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +138 -36
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +19 -7
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +128 -52
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +5 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -2
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +59 -68
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.d.ts +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +3 -2
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/ask-user.d.ts +25 -0
- package/dist/core/tools/ask-user.d.ts.map +1 -0
- package/dist/core/tools/ask-user.js +49 -0
- package/dist/core/tools/ask-user.js.map +1 -0
- package/dist/core/tools/bash-command-segments.d.ts +22 -0
- package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
- package/dist/core/tools/bash-command-segments.js +128 -0
- package/dist/core/tools/bash-command-segments.js.map +1 -0
- package/dist/core/tools/bash.d.ts +40 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +183 -32
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/contract.d.ts +183 -0
- package/dist/core/tools/contract.d.ts.map +1 -0
- package/dist/core/tools/contract.js +48 -0
- package/dist/core/tools/contract.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +38 -0
- package/dist/core/tools/delegate.d.ts.map +1 -0
- package/dist/core/tools/delegate.js +90 -0
- package/dist/core/tools/delegate.js.map +1 -0
- package/dist/core/tools/diagnostics.d.ts +39 -0
- package/dist/core/tools/diagnostics.d.ts.map +1 -0
- package/dist/core/tools/diagnostics.js +62 -0
- package/dist/core/tools/diagnostics.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +2 -5
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +12 -2
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +61 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +2 -2
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +13 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +4 -2
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +47 -10
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +51 -6
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +145 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +4 -2
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +17 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/lsp.d.ts +62 -0
- package/dist/core/tools/lsp.d.ts.map +1 -0
- package/dist/core/tools/lsp.js +216 -0
- package/dist/core/tools/lsp.js.map +1 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-permission.d.ts +18 -0
- package/dist/core/tools/path-permission.d.ts.map +1 -0
- package/dist/core/tools/path-permission.js +28 -0
- package/dist/core/tools/path-permission.js.map +1 -0
- package/dist/core/tools/plan-present.d.ts +27 -0
- package/dist/core/tools/plan-present.d.ts.map +1 -0
- package/dist/core/tools/plan-present.js +55 -0
- package/dist/core/tools/plan-present.js.map +1 -0
- package/dist/core/tools/powershell.d.ts +16 -0
- package/dist/core/tools/powershell.d.ts.map +1 -0
- package/dist/core/tools/powershell.js +39 -0
- package/dist/core/tools/powershell.js.map +1 -0
- package/dist/core/tools/read.d.ts +2 -2
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +14 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/skill-search.d.ts +32 -0
- package/dist/core/tools/skill-search.d.ts.map +1 -0
- package/dist/core/tools/skill-search.js +56 -0
- package/dist/core/tools/skill-search.js.map +1 -0
- package/dist/core/tools/test.d.ts +34 -0
- package/dist/core/tools/test.d.ts.map +1 -0
- package/dist/core/tools/test.js +75 -0
- package/dist/core/tools/test.js.map +1 -0
- package/dist/core/tools/todo-write.d.ts +31 -0
- package/dist/core/tools/todo-write.d.ts.map +1 -0
- package/dist/core/tools/todo-write.js +51 -0
- package/dist/core/tools/todo-write.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +11 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-schema.d.ts +22 -0
- package/dist/core/tools/tool-schema.d.ts.map +1 -0
- package/dist/core/tools/tool-schema.js +45 -0
- package/dist/core/tools/tool-schema.js.map +1 -0
- package/dist/core/tools/web-fetch.d.ts +26 -0
- package/dist/core/tools/web-fetch.d.ts.map +1 -0
- package/dist/core/tools/web-fetch.js +62 -0
- package/dist/core/tools/web-fetch.js.map +1 -0
- package/dist/core/tools/web-search-exa.d.ts +33 -0
- package/dist/core/tools/web-search-exa.d.ts.map +1 -0
- package/dist/core/tools/web-search-exa.js +128 -0
- package/dist/core/tools/web-search-exa.js.map +1 -0
- package/dist/core/tools/web-search.d.ts +26 -0
- package/dist/core/tools/web-search.d.ts.map +1 -0
- package/dist/core/tools/web-search.js +53 -0
- package/dist/core/tools/web-search.js.map +1 -0
- package/dist/core/tools/write.d.ts +16 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +48 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/usage-performance-store.d.ts +56 -0
- package/dist/core/usage-performance-store.d.ts.map +1 -0
- package/dist/core/usage-performance-store.js +85 -0
- package/dist/core/usage-performance-store.js.map +1 -0
- package/dist/core/web-search-provider.d.ts +64 -0
- package/dist/core/web-search-provider.d.ts.map +1 -0
- package/dist/core/web-search-provider.js +149 -0
- package/dist/core/web-search-provider.js.map +1 -0
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +2 -0
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +6 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +87 -22
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +6 -5
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +9 -6
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +72 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +338 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +7 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +11 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +4 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +24 -6
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +17 -41
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/first-use-hints.d.ts +8 -0
- package/dist/modes/interactive/components/first-use-hints.d.ts.map +1 -0
- package/dist/modes/interactive/components/first-use-hints.js +22 -0
- package/dist/modes/interactive/components/first-use-hints.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +23 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +182 -21
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +31 -9
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +236 -96
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +25 -5
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +226 -58
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-submenu.js +165 -0
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
- package/dist/modes/interactive/components/splash-header.d.ts +66 -0
- package/dist/modes/interactive/components/splash-header.d.ts.map +1 -0
- package/dist/modes/interactive/components/splash-header.js +180 -0
- package/dist/modes/interactive/components/splash-header.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +74 -17
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +16 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +113 -35
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-panel.d.ts +30 -0
- package/dist/modes/interactive/components/tool-panel.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-panel.js +130 -0
- package/dist/modes/interactive/components/tool-panel.js.map +1 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +60 -10
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +61 -5
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +642 -203
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +34 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/theme/apex.json +93 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +3 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +25 -11
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +11 -3
- package/dist/modes/interactive/theme/theme.d.ts +14 -3
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +65 -10
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +18 -12
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +22 -5
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts +1 -0
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +211 -14
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +2 -1
- package/dist/rpc-entry.js.map +1 -1
- package/dist/server/create-harness.d.ts +1 -1
- package/dist/server/create-harness.d.ts.map +1 -1
- package/dist/server/create-harness.js +8 -5
- package/dist/server/create-harness.js.map +1 -1
- package/dist/testing/replay/metrics.d.ts +24 -0
- package/dist/testing/replay/metrics.d.ts.map +1 -0
- package/dist/testing/replay/metrics.js +35 -0
- package/dist/testing/replay/metrics.js.map +1 -0
- package/dist/testing/replay/recorded-provider.d.ts +10 -0
- package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
- package/dist/testing/replay/recorded-provider.js +108 -0
- package/dist/testing/replay/recorded-provider.js.map +1 -0
- package/dist/testing/replay/runner.d.ts +56 -0
- package/dist/testing/replay/runner.d.ts.map +1 -0
- package/dist/testing/replay/runner.js +406 -0
- package/dist/testing/replay/runner.js.map +1 -0
- package/dist/themes/apex-logo.d.ts +41 -0
- package/dist/themes/apex-logo.d.ts.map +1 -0
- package/dist/themes/apex-logo.js +35 -0
- package/dist/themes/apex-logo.js.map +1 -0
- package/dist/utils/apex-code-user-agent.d.ts +2 -0
- package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
- package/dist/utils/apex-code-user-agent.js +5 -0
- package/dist/utils/apex-code-user-agent.js.map +1 -0
- package/dist/utils/changelog.d.ts +7 -2
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +82 -13
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +2 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/management-http.d.ts +5 -3
- package/dist/utils/management-http.d.ts.map +1 -1
- package/dist/utils/management-http.js +14 -10
- package/dist/utils/management-http.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +17 -5
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +60 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/text.d.ts +8 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +9 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +70 -2
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +280 -124
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +7 -5
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +25 -14
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/dist/utils/windows-self-update.js +1 -1
- package/dist/utils/windows-self-update.js.map +1 -1
- package/docs/compaction.md +39 -24
- package/docs/containerization.md +24 -21
- package/docs/custom-provider.md +15 -12
- package/docs/development.md +11 -11
- package/docs/environment-variables.md +37 -77
- package/docs/extensions.md +68 -54
- package/docs/index.md +12 -24
- package/docs/json.md +18 -11
- package/docs/keybindings.md +18 -12
- package/docs/llama-cpp.md +9 -7
- package/docs/models.md +17 -11
- package/docs/packages.md +47 -43
- package/docs/prompt-templates.md +3 -3
- package/docs/providers.md +10 -10
- package/docs/quickstart.md +49 -32
- package/docs/rpc.md +35 -18
- package/docs/sdk.md +20 -6
- package/docs/security.md +18 -18
- package/docs/session-format.md +9 -9
- package/docs/sessions.md +13 -13
- package/docs/settings.md +83 -16
- package/docs/shell-aliases.md +1 -1
- package/docs/skills.md +66 -15
- package/docs/terminal-setup.md +44 -19
- package/docs/termux.md +4 -4
- package/docs/themes.md +32 -11
- package/docs/tmux.md +4 -4
- package/docs/tui.md +5 -5
- package/docs/usage.md +61 -53
- package/docs/windows.md +24 -2
- package/examples/extensions/border-status-editor.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/git-checkpoint.ts +2 -2
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/notify.ts +3 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +3 -1
- package/examples/extensions/subagent/agents.ts +40 -9
- package/examples/extensions/subagent/index.ts +27 -4
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +280 -445
- package/package.json +9 -12
- package/dist/core/telemetry.d.ts +0 -3
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -9
- package/dist/core/telemetry.js.map +0 -1
- package/dist/utils/pi-user-agent.d.ts +0 -2
- package/dist/utils/pi-user-agent.d.ts.map +0 -1
- package/dist/utils/pi-user-agent.js +0 -5
- package/dist/utils/pi-user-agent.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trust-manager.js","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { canonicalizePath, resolvePath } from \"../utils/paths.ts\";\n\nexport type ProjectTrustDecision = boolean | null;\n\nexport interface ProjectTrustStoreEntry {\n\tpath: string;\n\tdecision: boolean;\n}\n\nexport interface ProjectTrustUpdate {\n\tpath: string;\n\tdecision: ProjectTrustDecision;\n}\n\nexport interface ProjectTrustOption {\n\tlabel: string;\n\ttrusted: boolean;\n\tupdates: ProjectTrustUpdate[];\n\tsavedPath?: string;\n}\n\ntype TrustFile = Record<string, boolean | null | undefined>;\n\nconst TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [\n\t\"settings.json\",\n\t\"extensions\",\n\t\"skills\",\n\t\"prompts\",\n\t\"themes\",\n\t\"SYSTEM.md\",\n\t\"APPEND_SYSTEM.md\",\n] as const;\n\nfunction normalizeCwd(cwd: string): string {\n\treturn canonicalizePath(resolvePath(cwd));\n}\n\nfunction findNearestTrustEntry(data: TrustFile, cwd: string): ProjectTrustStoreEntry | null {\n\tlet currentDir = normalizeCwd(cwd);\n\twhile (true) {\n\t\tconst value = data[currentDir];\n\t\tif (value === true || value === false) {\n\t\t\treturn { path: currentDir, decision: value };\n\t\t}\n\n\t\tconst parentDir = dirname(currentDir);\n\t\tif (parentDir === currentDir) {\n\t\t\treturn null;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport function getProjectTrustParentPath(cwd: string): string | undefined {\n\tconst trustPath = normalizeCwd(cwd);\n\tconst parentDir = dirname(trustPath);\n\treturn parentDir === trustPath ? undefined : parentDir;\n}\n\nexport function getProjectTrustOptions(cwd: string, options?: { includeSessionOnly?: boolean }): ProjectTrustOption[] {\n\tconst trustPath = normalizeCwd(cwd);\n\tconst trustOptions: ProjectTrustOption[] = [\n\t\t{ label: \"Trust\", trusted: true, updates: [{ path: trustPath, decision: true }], savedPath: trustPath },\n\t];\n\tconst parentPath = getProjectTrustParentPath(cwd);\n\tif (parentPath !== undefined) {\n\t\ttrustOptions.push({\n\t\t\tlabel: `Trust parent folder (${parentPath})`,\n\t\t\ttrusted: true,\n\t\t\tupdates: [\n\t\t\t\t{ path: parentPath, decision: true },\n\t\t\t\t{ path: trustPath, decision: null },\n\t\t\t],\n\t\t\tsavedPath: parentPath,\n\t\t});\n\t}\n\tif (options?.includeSessionOnly) {\n\t\ttrustOptions.push({ label: \"Trust (this session only)\", trusted: true, updates: [] });\n\t}\n\ttrustOptions.push({\n\t\tlabel: \"Do not trust\",\n\t\ttrusted: false,\n\t\tupdates: [{ path: trustPath, decision: false }],\n\t\tsavedPath: trustPath,\n\t});\n\tif (options?.includeSessionOnly) {\n\t\ttrustOptions.push({ label: \"Do not trust (this session only)\", trusted: false, updates: [] });\n\t}\n\treturn trustOptions;\n}\n\nfunction readTrustFile(path: string): TrustFile {\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(readFileSync(path, \"utf-8\"));\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Failed to read trust store ${path}: ${message}`);\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid trust store ${path}: expected an object`);\n\t}\n\n\tconst data: TrustFile = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (value !== true && value !== false && value !== null) {\n\t\t\tthrow new Error(`Invalid trust store ${path}: value for ${JSON.stringify(key)} must be true, false, or null`);\n\t\t}\n\t\tdata[key] = value;\n\t}\n\treturn data;\n}\n\nfunction writeTrustFile(path: string, data: TrustFile): void {\n\tconst sorted: TrustFile = {};\n\tfor (const key of Object.keys(data).sort()) {\n\t\tconst value = data[key];\n\t\tif (value === true || value === false || value === null) {\n\t\t\tsorted[key] = value;\n\t\t}\n\t}\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(sorted, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction acquireTrustLockSync(path: string): () => void {\n\tconst trustDir = dirname(path);\n\tmkdirSync(trustDir, { recursive: true });\n\tconst maxAttempts = 10;\n\tconst delayMs = 20;\n\tlet lastError: unknown;\n\n\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(trustDir, { realpath: false, lockfilePath: `${path}.lock` });\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t: undefined;\n\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tlastError = error;\n\t\t\tconst start = Date.now();\n\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t// Sleep synchronously to avoid changing trust store callers to async.\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lastError instanceof Error) {\n\t\tthrow lastError;\n\t}\n\tthrow new Error(\"Failed to acquire trust store lock\");\n}\n\nfunction withTrustFileLock<T>(path: string, fn: () => T): T {\n\tconst release = acquireTrustLockSync(path);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\trelease();\n\t}\n}\n\n/**\n * Returns true when cwd has project-local resources that must be gated by\n * project trust: trust-requiring entries under cwd/.pi, or .agents/skills in\n * cwd or one of its ancestors. Returns false when no such project resources\n * exist. The user/global ~/.agents/skills directory is always treated as a\n * trusted user resource and is ignored here, even when cwd is $HOME.\n */\nexport function hasTrustRequiringProjectResources(cwd: string): boolean {\n\tconst homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir()));\n\tconst userAgentsSkillsDir = join(homeDir, \".agents\", \"skills\");\n\tlet currentDir = canonicalizePath(resolvePath(cwd));\n\n\tconst configDir = join(currentDir, CONFIG_DIR_NAME);\n\tif (TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync(join(configDir, entry)))) {\n\t\treturn true;\n\t}\n\n\twhile (true) {\n\t\tconst agentsSkillsDir = join(currentDir, \".agents\", \"skills\");\n\t\tif (agentsSkillsDir !== userAgentsSkillsDir && existsSync(agentsSkillsDir)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst parentDir = dirname(currentDir);\n\t\tif (parentDir === currentDir) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport class ProjectTrustStore {\n\tprivate trustPath: string;\n\n\tconstructor(agentDir: string) {\n\t\tthis.trustPath = join(resolvePath(agentDir), \"trust.json\");\n\t}\n\n\tget(cwd: string): ProjectTrustDecision {\n\t\treturn this.getEntry(cwd)?.decision ?? null;\n\t}\n\n\tgetEntry(cwd: string): ProjectTrustStoreEntry | null {\n\t\treturn withTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\treturn findNearestTrustEntry(data, cwd);\n\t\t});\n\t}\n\n\tset(cwd: string, decision: ProjectTrustDecision): void {\n\t\tthis.setMany([{ path: cwd, decision }]);\n\t}\n\n\tsetMany(decisions: ProjectTrustUpdate[]): void {\n\t\twithTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tfor (const { path, decision } of decisions) {\n\t\t\t\tconst key = normalizeCwd(path);\n\t\t\t\tif (decision === null) {\n\t\t\t\t\tdelete data[key];\n\t\t\t\t} else {\n\t\t\t\t\tdata[key] = decision;\n\t\t\t\t}\n\t\t\t}\n\t\t\twriteTrustFile(this.trustPath, data);\n\t\t});\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"trust-manager.js","sourceRoot":"","sources":["../../src/core/trust-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME } from \"../config.ts\";\nimport { canonicalizePath, resolvePath } from \"../utils/paths.ts\";\nimport { stripBom } from \"../utils/text.ts\";\n\nexport type ProjectTrustDecision = boolean | null;\n\nexport interface ProjectTrustStoreEntry {\n\tpath: string;\n\tdecision: boolean;\n}\n\nexport interface ProjectTrustUpdate {\n\tpath: string;\n\tdecision: ProjectTrustDecision;\n}\n\nexport interface ProjectTrustOption {\n\tlabel: string;\n\ttrusted: boolean;\n\tupdates: ProjectTrustUpdate[];\n\tsavedPath?: string;\n}\n\ntype TrustFile = Record<string, boolean | null | undefined>;\n\nconst TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [\n\t\"settings.json\",\n\t\"extensions\",\n\t\"skills\",\n\t\"prompts\",\n\t\"themes\",\n\t\"SYSTEM.md\",\n\t\"APPEND_SYSTEM.md\",\n] as const;\n\nfunction normalizeCwd(cwd: string): string {\n\treturn canonicalizePath(resolvePath(cwd));\n}\n\nfunction findNearestTrustEntry(data: TrustFile, cwd: string): ProjectTrustStoreEntry | null {\n\tlet currentDir = normalizeCwd(cwd);\n\twhile (true) {\n\t\tconst value = data[currentDir];\n\t\tif (value === true || value === false) {\n\t\t\treturn { path: currentDir, decision: value };\n\t\t}\n\n\t\tconst parentDir = dirname(currentDir);\n\t\tif (parentDir === currentDir) {\n\t\t\treturn null;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport function getProjectTrustParentPath(cwd: string): string | undefined {\n\tconst trustPath = normalizeCwd(cwd);\n\tconst parentDir = dirname(trustPath);\n\treturn parentDir === trustPath ? undefined : parentDir;\n}\n\nexport function getProjectTrustOptions(cwd: string, options?: { includeSessionOnly?: boolean }): ProjectTrustOption[] {\n\tconst trustPath = normalizeCwd(cwd);\n\tconst trustOptions: ProjectTrustOption[] = [\n\t\t{ label: \"Trust\", trusted: true, updates: [{ path: trustPath, decision: true }], savedPath: trustPath },\n\t];\n\tconst parentPath = getProjectTrustParentPath(cwd);\n\tif (parentPath !== undefined) {\n\t\ttrustOptions.push({\n\t\t\tlabel: `Trust parent folder (${parentPath})`,\n\t\t\ttrusted: true,\n\t\t\tupdates: [\n\t\t\t\t{ path: parentPath, decision: true },\n\t\t\t\t{ path: trustPath, decision: null },\n\t\t\t],\n\t\t\tsavedPath: parentPath,\n\t\t});\n\t}\n\tif (options?.includeSessionOnly) {\n\t\ttrustOptions.push({ label: \"Trust (this session only)\", trusted: true, updates: [] });\n\t}\n\ttrustOptions.push({\n\t\tlabel: \"Do not trust\",\n\t\ttrusted: false,\n\t\tupdates: [{ path: trustPath, decision: false }],\n\t\tsavedPath: trustPath,\n\t});\n\tif (options?.includeSessionOnly) {\n\t\ttrustOptions.push({ label: \"Do not trust (this session only)\", trusted: false, updates: [] });\n\t}\n\treturn trustOptions;\n}\n\nfunction readTrustFile(path: string): TrustFile {\n\tif (!existsSync(path)) {\n\t\treturn {};\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(stripBom(readFileSync(path, \"utf-8\")));\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Failed to read trust store ${path}: ${message}`);\n\t}\n\n\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid trust store ${path}: expected an object`);\n\t}\n\n\tconst data: TrustFile = {};\n\tfor (const [key, value] of Object.entries(parsed)) {\n\t\tif (value !== true && value !== false && value !== null) {\n\t\t\tthrow new Error(`Invalid trust store ${path}: value for ${JSON.stringify(key)} must be true, false, or null`);\n\t\t}\n\t\tdata[key] = value;\n\t}\n\treturn data;\n}\n\nfunction writeTrustFile(path: string, data: TrustFile): void {\n\tconst sorted: TrustFile = {};\n\tfor (const key of Object.keys(data).sort()) {\n\t\tconst value = data[key];\n\t\tif (value === true || value === false || value === null) {\n\t\t\tsorted[key] = value;\n\t\t}\n\t}\n\tmkdirSync(dirname(path), { recursive: true });\n\twriteFileSync(path, `${JSON.stringify(sorted, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction acquireTrustLockSync(path: string): () => void {\n\tconst trustDir = dirname(path);\n\tmkdirSync(trustDir, { recursive: true });\n\tconst maxAttempts = 10;\n\tconst delayMs = 20;\n\tlet lastError: unknown;\n\n\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(trustDir, { realpath: false, lockfilePath: `${path}.lock` });\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t: undefined;\n\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tlastError = error;\n\t\t\tconst start = Date.now();\n\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t// Sleep synchronously to avoid changing trust store callers to async.\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lastError instanceof Error) {\n\t\tthrow lastError;\n\t}\n\tthrow new Error(\"Failed to acquire trust store lock\");\n}\n\nfunction withTrustFileLock<T>(path: string, fn: () => T): T {\n\tconst release = acquireTrustLockSync(path);\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\trelease();\n\t}\n}\n\n/**\n * Returns true when cwd has project-local resources that must be gated by\n * project trust: trust-requiring entries under cwd/.pi, or .agents/skills in\n * cwd or one of its ancestors. Returns false when no such project resources\n * exist. The user/global ~/.agents/skills directory is always treated as a\n * trusted user resource and is ignored here, even when cwd is $HOME.\n */\nexport function hasTrustRequiringProjectResources(cwd: string): boolean {\n\tconst homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir()));\n\tconst userAgentsSkillsDir = join(homeDir, \".agents\", \"skills\");\n\tlet currentDir = canonicalizePath(resolvePath(cwd));\n\n\tconst configDir = join(currentDir, CONFIG_DIR_NAME);\n\tif (TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync(join(configDir, entry)))) {\n\t\treturn true;\n\t}\n\n\twhile (true) {\n\t\tconst agentsSkillsDir = join(currentDir, \".agents\", \"skills\");\n\t\tif (agentsSkillsDir !== userAgentsSkillsDir && existsSync(agentsSkillsDir)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst parentDir = dirname(currentDir);\n\t\tif (parentDir === currentDir) {\n\t\t\treturn false;\n\t\t}\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nexport class ProjectTrustStore {\n\tprivate trustPath: string;\n\n\tconstructor(agentDir: string) {\n\t\tthis.trustPath = join(resolvePath(agentDir), \"trust.json\");\n\t}\n\n\tget(cwd: string): ProjectTrustDecision {\n\t\treturn this.getEntry(cwd)?.decision ?? null;\n\t}\n\n\tgetEntry(cwd: string): ProjectTrustStoreEntry | null {\n\t\treturn withTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\treturn findNearestTrustEntry(data, cwd);\n\t\t});\n\t}\n\n\tset(cwd: string, decision: ProjectTrustDecision): void {\n\t\tthis.setMany([{ path: cwd, decision }]);\n\t}\n\n\tsetMany(decisions: ProjectTrustUpdate[]): void {\n\t\twithTrustFileLock(this.trustPath, () => {\n\t\t\tconst data = readTrustFile(this.trustPath);\n\t\t\tfor (const { path, decision } of decisions) {\n\t\t\t\tconst key = normalizeCwd(path);\n\t\t\t\tif (decision === null) {\n\t\t\t\t\tdelete data[key];\n\t\t\t\t} else {\n\t\t\t\t\tdata[key] = decision;\n\t\t\t\t}\n\t\t\t}\n\t\t\twriteTrustFile(this.trustPath, data);\n\t\t});\n\t}\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable, non-secret per-request usage and latency samples. One sample per
|
|
3
|
+
* request attempt (win or rotated-away), sufficient for future measured routing
|
|
4
|
+
* (roadmap Phase 1's `model_perf` table) without inferring latency after the fact.
|
|
5
|
+
* Never holds a credential secret — only the opaque CredentialIdentity label.
|
|
6
|
+
*/
|
|
7
|
+
import { type CredentialFailureKind, type CredentialIdentity } from "./credential-pool.ts";
|
|
8
|
+
export interface UsagePerformanceSample {
|
|
9
|
+
timestamp: number;
|
|
10
|
+
provider: string;
|
|
11
|
+
model: string;
|
|
12
|
+
/** Stamped by the store at record time from its own construction, never by the caller. */
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
role?: string;
|
|
15
|
+
/** Opaque, non-secret credential label; absent when no credential pool was involved. */
|
|
16
|
+
credentialIdentity?: CredentialIdentity;
|
|
17
|
+
outcome: "success" | "error" | "aborted";
|
|
18
|
+
/** Only set when outcome is "error"; mirrors credential-failover's rotation classification. */
|
|
19
|
+
failureKind?: CredentialFailureKind;
|
|
20
|
+
ttftMs: number;
|
|
21
|
+
generationMs: number;
|
|
22
|
+
usage?: {
|
|
23
|
+
input: number;
|
|
24
|
+
output: number;
|
|
25
|
+
cacheRead: number;
|
|
26
|
+
cacheWrite: number;
|
|
27
|
+
};
|
|
28
|
+
cost?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface UsagePerformanceStore {
|
|
31
|
+
record(sample: UsagePerformanceSample): Promise<void>;
|
|
32
|
+
list(): Promise<readonly UsagePerformanceSample[]>;
|
|
33
|
+
close?(): void;
|
|
34
|
+
}
|
|
35
|
+
export declare class InMemoryUsagePerformanceStore implements UsagePerformanceStore {
|
|
36
|
+
private readonly samples;
|
|
37
|
+
record(sample: UsagePerformanceSample): Promise<void>;
|
|
38
|
+
list(): Promise<readonly UsagePerformanceSample[]>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Durable, cross-session store backed by the shared durable-state SQLite database
|
|
42
|
+
* (roadmap Phase 8). Constructed per session so every recorded sample is stamped
|
|
43
|
+
* with the session that produced it; `sessionId` is never taken from the sample
|
|
44
|
+
* itself, only from how the store was constructed (see the spec's "Session
|
|
45
|
+
* attribution" note — `ModelRuntime` is session-agnostic and cannot supply this).
|
|
46
|
+
*/
|
|
47
|
+
export declare class SqliteUsagePerformanceStore implements UsagePerformanceStore {
|
|
48
|
+
private readonly store;
|
|
49
|
+
private readonly sessionId;
|
|
50
|
+
private closed;
|
|
51
|
+
constructor(databasePath: string, sessionId?: string, retentionDays?: number);
|
|
52
|
+
record(sample: UsagePerformanceSample): Promise<void>;
|
|
53
|
+
list(): Promise<readonly UsagePerformanceSample[]>;
|
|
54
|
+
close(): void;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=usage-performance-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-performance-store.d.ts","sourceRoot":"","sources":["../../src/core/usage-performance-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAA4B,MAAM,sBAAsB,CAAC;AAGrH,MAAM,WAAW,sBAAsB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,OAAO,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IACzC,+FAA+F;IAC/F,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACrC,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,IAAI,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,IAAI,CAAC;CACf;AAED,qBAAa,6BAA8B,YAAW,qBAAqB;IAC1E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IAElD,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;IAEK,IAAI,IAAI,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAEvD;CACD;AAID;;;;;;GAMG;AACH,qBAAa,2BAA4B,YAAW,qBAAqB;IACxE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAS;IAEvB,YAAY,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,aAAa,GAAE,MAA+B,EAKnG;IAEK,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB1D;IAEK,IAAI,IAAI,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAuBvD;IAED,KAAK,IAAI,IAAI,CAIZ;CACD","sourcesContent":["/**\n * Durable, non-secret per-request usage and latency samples. One sample per\n * request attempt (win or rotated-away), sufficient for future measured routing\n * (roadmap Phase 1's `model_perf` table) without inferring latency after the fact.\n * Never holds a credential secret — only the opaque CredentialIdentity label.\n */\n\nimport { type CredentialFailureKind, type CredentialIdentity, createCredentialIdentity } from \"./credential-pool.ts\";\nimport { type DurableStateStore, openDurableStateStore } from \"./durable-state/sqlite.ts\";\n\nexport interface UsagePerformanceSample {\n\ttimestamp: number;\n\tprovider: string;\n\tmodel: string;\n\t/** Stamped by the store at record time from its own construction, never by the caller. */\n\tsessionId?: string;\n\trole?: string;\n\t/** Opaque, non-secret credential label; absent when no credential pool was involved. */\n\tcredentialIdentity?: CredentialIdentity;\n\toutcome: \"success\" | \"error\" | \"aborted\";\n\t/** Only set when outcome is \"error\"; mirrors credential-failover's rotation classification. */\n\tfailureKind?: CredentialFailureKind;\n\tttftMs: number;\n\tgenerationMs: number;\n\tusage?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcost?: number;\n}\n\nexport interface UsagePerformanceStore {\n\trecord(sample: UsagePerformanceSample): Promise<void>;\n\tlist(): Promise<readonly UsagePerformanceSample[]>;\n\tclose?(): void;\n}\n\nexport class InMemoryUsagePerformanceStore implements UsagePerformanceStore {\n\tprivate readonly samples: UsagePerformanceSample[] = [];\n\n\tasync record(sample: UsagePerformanceSample): Promise<void> {\n\t\tthis.samples.push(structuredClone(sample));\n\t}\n\n\tasync list(): Promise<readonly UsagePerformanceSample[]> {\n\t\treturn this.samples.map((sample) => structuredClone(sample));\n\t}\n}\n\nconst DEFAULT_RETENTION_DAYS = 90;\n\n/**\n * Durable, cross-session store backed by the shared durable-state SQLite database\n * (roadmap Phase 8). Constructed per session so every recorded sample is stamped\n * with the session that produced it; `sessionId` is never taken from the sample\n * itself, only from how the store was constructed (see the spec's \"Session\n * attribution\" note — `ModelRuntime` is session-agnostic and cannot supply this).\n */\nexport class SqliteUsagePerformanceStore implements UsagePerformanceStore {\n\tprivate readonly store: DurableStateStore;\n\tprivate readonly sessionId: string | undefined;\n\tprivate closed = false;\n\n\tconstructor(databasePath: string, sessionId?: string, retentionDays: number = DEFAULT_RETENTION_DAYS) {\n\t\tthis.store = openDurableStateStore(databasePath);\n\t\tthis.sessionId = sessionId;\n\t\tconst cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000).toISOString();\n\t\tthis.store.pruneUsagePerformance(cutoff);\n\t}\n\n\tasync record(sample: UsagePerformanceSample): Promise<void> {\n\t\tthis.store.recordUsagePerformance({\n\t\t\tprovider: sample.provider,\n\t\t\tmodelId: sample.model,\n\t\t\tttftMs: sample.ttftMs,\n\t\t\tgenerationMs: sample.generationMs,\n\t\t\tsampledAt: new Date(sample.timestamp).toISOString(),\n\t\t\tsessionId: this.sessionId ?? null,\n\t\t\trole: sample.role ?? null,\n\t\t\tcredentialIdentity: sample.credentialIdentity ?? null,\n\t\t\toutcome: sample.outcome,\n\t\t\tfailureKind: sample.failureKind ?? null,\n\t\t\tinputTokens: sample.usage?.input ?? null,\n\t\t\toutputTokens: sample.usage?.output ?? null,\n\t\t\tcacheReadTokens: sample.usage?.cacheRead ?? null,\n\t\t\tcacheWriteTokens: sample.usage?.cacheWrite ?? null,\n\t\t\tcost: sample.cost ?? null,\n\t\t});\n\t}\n\n\tasync list(): Promise<readonly UsagePerformanceSample[]> {\n\t\treturn this.store.listUsagePerformance().map((row) => ({\n\t\t\ttimestamp: Date.parse(row.sampledAt),\n\t\t\tprovider: row.provider,\n\t\t\tmodel: row.modelId,\n\t\t\tsessionId: row.sessionId ?? undefined,\n\t\t\trole: row.role ?? undefined,\n\t\t\tcredentialIdentity: row.credentialIdentity ? createCredentialIdentity(row.credentialIdentity) : undefined,\n\t\t\toutcome: row.outcome as UsagePerformanceSample[\"outcome\"],\n\t\t\tfailureKind: (row.failureKind ?? undefined) as CredentialFailureKind | undefined,\n\t\t\tttftMs: row.ttftMs ?? 0,\n\t\t\tgenerationMs: row.generationMs ?? 0,\n\t\t\tusage:\n\t\t\t\trow.inputTokens === null\n\t\t\t\t\t? undefined\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tinput: row.inputTokens,\n\t\t\t\t\t\t\toutput: row.outputTokens ?? 0,\n\t\t\t\t\t\t\tcacheRead: row.cacheReadTokens ?? 0,\n\t\t\t\t\t\t\tcacheWrite: row.cacheWriteTokens ?? 0,\n\t\t\t\t\t\t},\n\t\t\tcost: row.cost ?? undefined,\n\t\t}));\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.store.close();\n\t}\n}\n"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable, non-secret per-request usage and latency samples. One sample per
|
|
3
|
+
* request attempt (win or rotated-away), sufficient for future measured routing
|
|
4
|
+
* (roadmap Phase 1's `model_perf` table) without inferring latency after the fact.
|
|
5
|
+
* Never holds a credential secret — only the opaque CredentialIdentity label.
|
|
6
|
+
*/
|
|
7
|
+
import { createCredentialIdentity } from "./credential-pool.js";
|
|
8
|
+
import { openDurableStateStore } from "./durable-state/sqlite.js";
|
|
9
|
+
export class InMemoryUsagePerformanceStore {
|
|
10
|
+
samples = [];
|
|
11
|
+
async record(sample) {
|
|
12
|
+
this.samples.push(structuredClone(sample));
|
|
13
|
+
}
|
|
14
|
+
async list() {
|
|
15
|
+
return this.samples.map((sample) => structuredClone(sample));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const DEFAULT_RETENTION_DAYS = 90;
|
|
19
|
+
/**
|
|
20
|
+
* Durable, cross-session store backed by the shared durable-state SQLite database
|
|
21
|
+
* (roadmap Phase 8). Constructed per session so every recorded sample is stamped
|
|
22
|
+
* with the session that produced it; `sessionId` is never taken from the sample
|
|
23
|
+
* itself, only from how the store was constructed (see the spec's "Session
|
|
24
|
+
* attribution" note — `ModelRuntime` is session-agnostic and cannot supply this).
|
|
25
|
+
*/
|
|
26
|
+
export class SqliteUsagePerformanceStore {
|
|
27
|
+
store;
|
|
28
|
+
sessionId;
|
|
29
|
+
closed = false;
|
|
30
|
+
constructor(databasePath, sessionId, retentionDays = DEFAULT_RETENTION_DAYS) {
|
|
31
|
+
this.store = openDurableStateStore(databasePath);
|
|
32
|
+
this.sessionId = sessionId;
|
|
33
|
+
const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000).toISOString();
|
|
34
|
+
this.store.pruneUsagePerformance(cutoff);
|
|
35
|
+
}
|
|
36
|
+
async record(sample) {
|
|
37
|
+
this.store.recordUsagePerformance({
|
|
38
|
+
provider: sample.provider,
|
|
39
|
+
modelId: sample.model,
|
|
40
|
+
ttftMs: sample.ttftMs,
|
|
41
|
+
generationMs: sample.generationMs,
|
|
42
|
+
sampledAt: new Date(sample.timestamp).toISOString(),
|
|
43
|
+
sessionId: this.sessionId ?? null,
|
|
44
|
+
role: sample.role ?? null,
|
|
45
|
+
credentialIdentity: sample.credentialIdentity ?? null,
|
|
46
|
+
outcome: sample.outcome,
|
|
47
|
+
failureKind: sample.failureKind ?? null,
|
|
48
|
+
inputTokens: sample.usage?.input ?? null,
|
|
49
|
+
outputTokens: sample.usage?.output ?? null,
|
|
50
|
+
cacheReadTokens: sample.usage?.cacheRead ?? null,
|
|
51
|
+
cacheWriteTokens: sample.usage?.cacheWrite ?? null,
|
|
52
|
+
cost: sample.cost ?? null,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async list() {
|
|
56
|
+
return this.store.listUsagePerformance().map((row) => ({
|
|
57
|
+
timestamp: Date.parse(row.sampledAt),
|
|
58
|
+
provider: row.provider,
|
|
59
|
+
model: row.modelId,
|
|
60
|
+
sessionId: row.sessionId ?? undefined,
|
|
61
|
+
role: row.role ?? undefined,
|
|
62
|
+
credentialIdentity: row.credentialIdentity ? createCredentialIdentity(row.credentialIdentity) : undefined,
|
|
63
|
+
outcome: row.outcome,
|
|
64
|
+
failureKind: (row.failureKind ?? undefined),
|
|
65
|
+
ttftMs: row.ttftMs ?? 0,
|
|
66
|
+
generationMs: row.generationMs ?? 0,
|
|
67
|
+
usage: row.inputTokens === null
|
|
68
|
+
? undefined
|
|
69
|
+
: {
|
|
70
|
+
input: row.inputTokens,
|
|
71
|
+
output: row.outputTokens ?? 0,
|
|
72
|
+
cacheRead: row.cacheReadTokens ?? 0,
|
|
73
|
+
cacheWrite: row.cacheWriteTokens ?? 0,
|
|
74
|
+
},
|
|
75
|
+
cost: row.cost ?? undefined,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
close() {
|
|
79
|
+
if (this.closed)
|
|
80
|
+
return;
|
|
81
|
+
this.closed = true;
|
|
82
|
+
this.store.close();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=usage-performance-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-performance-store.js","sourceRoot":"","sources":["../../src/core/usage-performance-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Durable, non-secret per-request usage and latency samples. One sample per\n * request attempt (win or rotated-away), sufficient for future measured routing\n * (roadmap Phase 1's `model_perf` table) without inferring latency after the fact.\n * Never holds a credential secret — only the opaque CredentialIdentity label.\n */\n\nimport { type CredentialFailureKind, type CredentialIdentity, createCredentialIdentity } from \"./credential-pool.ts\";\nimport { type DurableStateStore, openDurableStateStore } from \"./durable-state/sqlite.ts\";\n\nexport interface UsagePerformanceSample {\n\ttimestamp: number;\n\tprovider: string;\n\tmodel: string;\n\t/** Stamped by the store at record time from its own construction, never by the caller. */\n\tsessionId?: string;\n\trole?: string;\n\t/** Opaque, non-secret credential label; absent when no credential pool was involved. */\n\tcredentialIdentity?: CredentialIdentity;\n\toutcome: \"success\" | \"error\" | \"aborted\";\n\t/** Only set when outcome is \"error\"; mirrors credential-failover's rotation classification. */\n\tfailureKind?: CredentialFailureKind;\n\tttftMs: number;\n\tgenerationMs: number;\n\tusage?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n\tcost?: number;\n}\n\nexport interface UsagePerformanceStore {\n\trecord(sample: UsagePerformanceSample): Promise<void>;\n\tlist(): Promise<readonly UsagePerformanceSample[]>;\n\tclose?(): void;\n}\n\nexport class InMemoryUsagePerformanceStore implements UsagePerformanceStore {\n\tprivate readonly samples: UsagePerformanceSample[] = [];\n\n\tasync record(sample: UsagePerformanceSample): Promise<void> {\n\t\tthis.samples.push(structuredClone(sample));\n\t}\n\n\tasync list(): Promise<readonly UsagePerformanceSample[]> {\n\t\treturn this.samples.map((sample) => structuredClone(sample));\n\t}\n}\n\nconst DEFAULT_RETENTION_DAYS = 90;\n\n/**\n * Durable, cross-session store backed by the shared durable-state SQLite database\n * (roadmap Phase 8). Constructed per session so every recorded sample is stamped\n * with the session that produced it; `sessionId` is never taken from the sample\n * itself, only from how the store was constructed (see the spec's \"Session\n * attribution\" note — `ModelRuntime` is session-agnostic and cannot supply this).\n */\nexport class SqliteUsagePerformanceStore implements UsagePerformanceStore {\n\tprivate readonly store: DurableStateStore;\n\tprivate readonly sessionId: string | undefined;\n\tprivate closed = false;\n\n\tconstructor(databasePath: string, sessionId?: string, retentionDays: number = DEFAULT_RETENTION_DAYS) {\n\t\tthis.store = openDurableStateStore(databasePath);\n\t\tthis.sessionId = sessionId;\n\t\tconst cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000).toISOString();\n\t\tthis.store.pruneUsagePerformance(cutoff);\n\t}\n\n\tasync record(sample: UsagePerformanceSample): Promise<void> {\n\t\tthis.store.recordUsagePerformance({\n\t\t\tprovider: sample.provider,\n\t\t\tmodelId: sample.model,\n\t\t\tttftMs: sample.ttftMs,\n\t\t\tgenerationMs: sample.generationMs,\n\t\t\tsampledAt: new Date(sample.timestamp).toISOString(),\n\t\t\tsessionId: this.sessionId ?? null,\n\t\t\trole: sample.role ?? null,\n\t\t\tcredentialIdentity: sample.credentialIdentity ?? null,\n\t\t\toutcome: sample.outcome,\n\t\t\tfailureKind: sample.failureKind ?? null,\n\t\t\tinputTokens: sample.usage?.input ?? null,\n\t\t\toutputTokens: sample.usage?.output ?? null,\n\t\t\tcacheReadTokens: sample.usage?.cacheRead ?? null,\n\t\t\tcacheWriteTokens: sample.usage?.cacheWrite ?? null,\n\t\t\tcost: sample.cost ?? null,\n\t\t});\n\t}\n\n\tasync list(): Promise<readonly UsagePerformanceSample[]> {\n\t\treturn this.store.listUsagePerformance().map((row) => ({\n\t\t\ttimestamp: Date.parse(row.sampledAt),\n\t\t\tprovider: row.provider,\n\t\t\tmodel: row.modelId,\n\t\t\tsessionId: row.sessionId ?? undefined,\n\t\t\trole: row.role ?? undefined,\n\t\t\tcredentialIdentity: row.credentialIdentity ? createCredentialIdentity(row.credentialIdentity) : undefined,\n\t\t\toutcome: row.outcome as UsagePerformanceSample[\"outcome\"],\n\t\t\tfailureKind: (row.failureKind ?? undefined) as CredentialFailureKind | undefined,\n\t\t\tttftMs: row.ttftMs ?? 0,\n\t\t\tgenerationMs: row.generationMs ?? 0,\n\t\t\tusage:\n\t\t\t\trow.inputTokens === null\n\t\t\t\t\t? undefined\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tinput: row.inputTokens,\n\t\t\t\t\t\t\toutput: row.outputTokens ?? 0,\n\t\t\t\t\t\t\tcacheRead: row.cacheReadTokens ?? 0,\n\t\t\t\t\t\t\tcacheWrite: row.cacheWriteTokens ?? 0,\n\t\t\t\t\t\t},\n\t\t\tcost: row.cost ?? undefined,\n\t\t}));\n\t}\n\n\tclose(): void {\n\t\tif (this.closed) return;\n\t\tthis.closed = true;\n\t\tthis.store.close();\n\t}\n}\n"]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { WebSearchSettings } from "./settings-manager.ts";
|
|
2
|
+
import type { WebSearchOperations } from "./tools/web-search.ts";
|
|
3
|
+
export type WebSearchProviderId = "exa";
|
|
4
|
+
/**
|
|
5
|
+
* Backend used when settings name none. `web_search` still reports itself
|
|
6
|
+
* unconfigured unless this backend's key resolves, so the default selects which
|
|
7
|
+
* credential is looked for, not whether the tool reaches the network.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_WEB_SEARCH_PROVIDER: WebSearchProviderId;
|
|
10
|
+
/**
|
|
11
|
+
* Reject a literal secret configured in settings.
|
|
12
|
+
*
|
|
13
|
+
* `webSearch.apiKey` is read from project settings as well as global ones, and this
|
|
14
|
+
* repository deliberately does not gitignore `<project>/.apex-code/` -- that directory
|
|
15
|
+
* is meant to be versioned and shared with a team. A literal key written there would be
|
|
16
|
+
* committed and handed to everyone who clones the repository.
|
|
17
|
+
*
|
|
18
|
+
* A reference (`$VAR`, `${VAR}`, `!command`) names where the secret lives without
|
|
19
|
+
* containing it, so it is safe to commit. AGENTS.md already states that no credential
|
|
20
|
+
* belongs in a file the settings loader writes; this makes that rule enforced rather
|
|
21
|
+
* than documented. `auth.json` still accepts literals, because holding secrets outside
|
|
22
|
+
* the repository is what the credential store is for.
|
|
23
|
+
*/
|
|
24
|
+
export declare function webSearchSettingsError(settings?: WebSearchSettings): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The host `web_search` needs on the sandbox allowlist, or undefined when no
|
|
27
|
+
* credential is configured for the selected backend.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately checks whether the key *reference* resolves rather than resolving it:
|
|
30
|
+
* the supervisor calls this on every launch, and a `!command` reference would
|
|
31
|
+
* otherwise spawn a shell before the child even starts. That check is an environment
|
|
32
|
+
* lookup for a `$VAR` reference and free for a command reference.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveWebSearchHost(settings: WebSearchSettings | undefined, env?: Record<string, string>, authPath?: string): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Build the configured `web_search` backend, or undefined when no credential
|
|
37
|
+
* resolves.
|
|
38
|
+
*
|
|
39
|
+
* Undefined leaves the tool on its unconfigured operations, which throw a
|
|
40
|
+
* model-readable "not configured" error. That is deliberately not the same thing as
|
|
41
|
+
* hiding the tool: a session that silently lacks `web_search` cannot tell the model
|
|
42
|
+
* why, and the throw names the missing piece.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* What to tell the model, and through it the user, when nothing is configured.
|
|
46
|
+
*
|
|
47
|
+
* Named here rather than in `web-search.ts` because only this module knows which
|
|
48
|
+
* backend was selected and therefore which credential to name. The audience is a
|
|
49
|
+
* person who asked the agent to search something, so it names the two things they
|
|
50
|
+
* can actually do, not the SDK option an embedder would pass.
|
|
51
|
+
*/
|
|
52
|
+
export declare function unconfiguredWebSearchMessage(settings?: WebSearchSettings): string;
|
|
53
|
+
/**
|
|
54
|
+
* A `web_search` backend that resolves its credential on each call.
|
|
55
|
+
*
|
|
56
|
+
* The session builds its tool registry once, at construction, so operations captured
|
|
57
|
+
* there would pin whatever was configured at startup. A key saved from the settings
|
|
58
|
+
* panel would then appear to save and do nothing until restart, which is worse than
|
|
59
|
+
* having no settings row at all. Resolving per call costs one small file read and
|
|
60
|
+
* keeps `resolveConfigValue`'s cache for command references.
|
|
61
|
+
*/
|
|
62
|
+
export declare function createDeferredWebSearchOperations(readSettings: () => WebSearchSettings | undefined, authPath?: string): WebSearchOperations;
|
|
63
|
+
export declare function resolveWebSearchOperations(settings: WebSearchSettings | undefined, env?: Record<string, string>, authPath?: string): WebSearchOperations | undefined;
|
|
64
|
+
//# sourceMappingURL=web-search-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search-provider.d.ts","sourceRoot":"","sources":["../../src/core/web-search-provider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE,MAAM,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAsCxC;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAA2B,CAAC;AAwBtE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAQvF;AAiBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,QAAQ,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,SAAS,CAGpB;AAED;;;;;;;;GAQG;AACH;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAIjF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAChD,YAAY,EAAE,MAAM,iBAAiB,GAAG,SAAS,EACjD,QAAQ,CAAC,EAAE,MAAM,GACf,mBAAmB,CAarB;AAED,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,QAAQ,CAAC,EAAE,MAAM,GACf,mBAAmB,GAAG,SAAS,CASjC","sourcesContent":["import { readStoredCredential } from \"./auth-storage.ts\";\nimport {\n\tgetConfigValueEnvVarNames,\n\tisCommandConfigValue,\n\tisConfigValueConfigured,\n\tresolveConfigValue,\n} from \"./resolve-config-value.ts\";\nimport type { WebSearchSettings } from \"./settings-manager.ts\";\nimport type { WebSearchOperations } from \"./tools/web-search.ts\";\nimport { createExaWebSearchOperations, EXA_SEARCH_HOST } from \"./tools/web-search-exa.ts\";\n\nexport type WebSearchProviderId = \"exa\";\n\n/**\n * One entry per backend `web_search` can speak to.\n *\n * A table rather than a branch because the swap is the point: the `web_search` tool\n * owns the contract and the permission grammar, the backend owns nothing but an HTTP\n * call, and adding the second backend should be a row here rather than a new code\n * path through the resolver.\n */\ninterface WebSearchProviderDefinition {\n\t/**\n\t * Config-value reference used when settings name no key. Held as a reference,\n\t * never a literal: a resolved key must never reach a file the settings loader\n\t * writes back.\n\t */\n\treadonly defaultApiKeyReference: string;\n\t/** Host the sandbox must allow before this backend can reach anything. */\n\treadonly host: string;\n\t/** `auth.json` key holding a credential saved from the settings panel. */\n\treadonly credentialId: string;\n\tcreate(options: {\n\t\tapiKey: string;\n\t\tendpoint?: string;\n\t\tnumResults?: number;\n\t\tsnippetMaxCharacters?: number;\n\t}): WebSearchOperations;\n}\n\nconst WEB_SEARCH_PROVIDERS: Record<WebSearchProviderId, WebSearchProviderDefinition> = {\n\texa: {\n\t\tdefaultApiKeyReference: \"$EXA_API_KEY\",\n\t\thost: EXA_SEARCH_HOST,\n\t\tcredentialId: \"exa\",\n\t\tcreate: createExaWebSearchOperations,\n\t},\n};\n\n/**\n * Backend used when settings name none. `web_search` still reports itself\n * unconfigured unless this backend's key resolves, so the default selects which\n * credential is looked for, not whether the tool reaches the network.\n */\nexport const DEFAULT_WEB_SEARCH_PROVIDER: WebSearchProviderId = \"exa\";\n\nfunction definitionFor(settings: WebSearchSettings | undefined): WebSearchProviderDefinition {\n\treturn WEB_SEARCH_PROVIDERS[settings?.provider ?? DEFAULT_WEB_SEARCH_PROVIDER];\n}\n\n/** `auth.json` key holding a stored credential for the selected backend. */\nfunction webSearchCredentialId(settings?: WebSearchSettings): string {\n\treturn definitionFor(settings).credentialId;\n}\n\n/**\n * The reference stored by the settings panel, or undefined when nothing is saved.\n *\n * Whatever was saved stays a reference rather than being resolved here, so the one\n * resolution below covers a literal key, a `$VAR`, and a `!command` alike. An OAuth\n * credential under the same key is not an API key and is ignored rather than coerced.\n */\nfunction storedApiKeyReference(settings: WebSearchSettings | undefined, authPath?: string): string | undefined {\n\tconst credential = readStoredCredential(webSearchCredentialId(settings), authPath);\n\tif (credential?.type !== \"api_key\") return undefined;\n\treturn credential.key?.trim() || undefined;\n}\n\n/**\n * Reject a literal secret configured in settings.\n *\n * `webSearch.apiKey` is read from project settings as well as global ones, and this\n * repository deliberately does not gitignore `<project>/.apex-code/` -- that directory\n * is meant to be versioned and shared with a team. A literal key written there would be\n * committed and handed to everyone who clones the repository.\n *\n * A reference (`$VAR`, `${VAR}`, `!command`) names where the secret lives without\n * containing it, so it is safe to commit. AGENTS.md already states that no credential\n * belongs in a file the settings loader writes; this makes that rule enforced rather\n * than documented. `auth.json` still accepts literals, because holding secrets outside\n * the repository is what the credential store is for.\n */\nexport function webSearchSettingsError(settings?: WebSearchSettings): string | undefined {\n\tconst configured = settings?.apiKey?.trim();\n\tif (!configured) return undefined;\n\tif (isCommandConfigValue(configured)) return undefined;\n\tif (getConfigValueEnvVarNames(configured).length > 0) return undefined;\n\t// The value itself is never echoed: this message reaches the model, and from there a\n\t// transcript. Naming the setting is enough to act on.\n\treturn `webSearch.apiKey must be a reference, not a literal key, because project settings are versioned and shared. Use \"$EXA_API_KEY\", \"\\${YOUR_VAR}\", or \"!your-command\", and keep the secret in your environment or credential store.`;\n}\n\n/**\n * Pick one reference, then resolve it once.\n *\n * Order is explicit configuration, then saved credential, then ambient environment.\n * A user who just typed a key into the settings dialog expects it to beat a stale\n * export they have forgotten about, and an explicit `webSearch.apiKey` in settings is\n * a direct instruction that should beat both.\n */\nfunction apiKeyReferenceFor(settings: WebSearchSettings | undefined, authPath?: string): string {\n\t// A refused literal falls through rather than being honoured, so a committed key is\n\t// inert instead of quietly working for whoever cloned the repository.\n\tconst configured = webSearchSettingsError(settings) ? undefined : settings?.apiKey?.trim();\n\treturn configured || storedApiKeyReference(settings, authPath) || definitionFor(settings).defaultApiKeyReference;\n}\n\n/**\n * The host `web_search` needs on the sandbox allowlist, or undefined when no\n * credential is configured for the selected backend.\n *\n * Deliberately checks whether the key *reference* resolves rather than resolving it:\n * the supervisor calls this on every launch, and a `!command` reference would\n * otherwise spawn a shell before the child even starts. That check is an environment\n * lookup for a `$VAR` reference and free for a command reference.\n */\nexport function resolveWebSearchHost(\n\tsettings: WebSearchSettings | undefined,\n\tenv?: Record<string, string>,\n\tauthPath?: string,\n): string | undefined {\n\tconst definition = definitionFor(settings);\n\treturn isConfigValueConfigured(apiKeyReferenceFor(settings, authPath), env) ? definition.host : undefined;\n}\n\n/**\n * Build the configured `web_search` backend, or undefined when no credential\n * resolves.\n *\n * Undefined leaves the tool on its unconfigured operations, which throw a\n * model-readable \"not configured\" error. That is deliberately not the same thing as\n * hiding the tool: a session that silently lacks `web_search` cannot tell the model\n * why, and the throw names the missing piece.\n */\n/**\n * What to tell the model, and through it the user, when nothing is configured.\n *\n * Named here rather than in `web-search.ts` because only this module knows which\n * backend was selected and therefore which credential to name. The audience is a\n * person who asked the agent to search something, so it names the two things they\n * can actually do, not the SDK option an embedder would pass.\n */\nexport function unconfiguredWebSearchMessage(settings?: WebSearchSettings): string {\n\tconst definition = definitionFor(settings);\n\tconst variable = definition.defaultApiKeyReference.replace(/^\\$/, \"\");\n\treturn `web_search has no API key configured. Set ${variable} in the environment, or run /settings and add a ${definition.credentialId} key.`;\n}\n\n/**\n * A `web_search` backend that resolves its credential on each call.\n *\n * The session builds its tool registry once, at construction, so operations captured\n * there would pin whatever was configured at startup. A key saved from the settings\n * panel would then appear to save and do nothing until restart, which is worse than\n * having no settings row at all. Resolving per call costs one small file read and\n * keeps `resolveConfigValue`'s cache for command references.\n */\nexport function createDeferredWebSearchOperations(\n\treadSettings: () => WebSearchSettings | undefined,\n\tauthPath?: string,\n): WebSearchOperations {\n\treturn {\n\t\tasync search(query, signal) {\n\t\t\tconst settings = readSettings();\n\t\t\t// Reported ahead of the unconfigured message: \"no key\" and \"your key is in the\n\t\t\t// wrong place\" need different fixes.\n\t\t\tconst settingsError = webSearchSettingsError(settings);\n\t\t\tif (settingsError) throw new Error(settingsError);\n\t\t\tconst operations = resolveWebSearchOperations(settings, undefined, authPath);\n\t\t\tif (!operations) throw new Error(unconfiguredWebSearchMessage(settings));\n\t\t\treturn operations.search(query, signal);\n\t\t},\n\t};\n}\n\nexport function resolveWebSearchOperations(\n\tsettings: WebSearchSettings | undefined,\n\tenv?: Record<string, string>,\n\tauthPath?: string,\n): WebSearchOperations | undefined {\n\tconst apiKey = resolveConfigValue(apiKeyReferenceFor(settings, authPath), env)?.trim();\n\tif (!apiKey) return undefined;\n\treturn definitionFor(settings).create({\n\t\tapiKey,\n\t\t...(settings?.endpoint === undefined ? {} : { endpoint: settings.endpoint }),\n\t\t...(settings?.numResults === undefined ? {} : { numResults: settings.numResults }),\n\t\t...(settings?.snippetMaxCharacters === undefined ? {} : { snippetMaxCharacters: settings.snippetMaxCharacters }),\n\t});\n}\n"]}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { readStoredCredential } from "./auth-storage.js";
|
|
2
|
+
import { getConfigValueEnvVarNames, isCommandConfigValue, isConfigValueConfigured, resolveConfigValue, } from "./resolve-config-value.js";
|
|
3
|
+
import { createExaWebSearchOperations, EXA_SEARCH_HOST } from "./tools/web-search-exa.js";
|
|
4
|
+
const WEB_SEARCH_PROVIDERS = {
|
|
5
|
+
exa: {
|
|
6
|
+
defaultApiKeyReference: "$EXA_API_KEY",
|
|
7
|
+
host: EXA_SEARCH_HOST,
|
|
8
|
+
credentialId: "exa",
|
|
9
|
+
create: createExaWebSearchOperations,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Backend used when settings name none. `web_search` still reports itself
|
|
14
|
+
* unconfigured unless this backend's key resolves, so the default selects which
|
|
15
|
+
* credential is looked for, not whether the tool reaches the network.
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_WEB_SEARCH_PROVIDER = "exa";
|
|
18
|
+
function definitionFor(settings) {
|
|
19
|
+
return WEB_SEARCH_PROVIDERS[settings?.provider ?? DEFAULT_WEB_SEARCH_PROVIDER];
|
|
20
|
+
}
|
|
21
|
+
/** `auth.json` key holding a stored credential for the selected backend. */
|
|
22
|
+
function webSearchCredentialId(settings) {
|
|
23
|
+
return definitionFor(settings).credentialId;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The reference stored by the settings panel, or undefined when nothing is saved.
|
|
27
|
+
*
|
|
28
|
+
* Whatever was saved stays a reference rather than being resolved here, so the one
|
|
29
|
+
* resolution below covers a literal key, a `$VAR`, and a `!command` alike. An OAuth
|
|
30
|
+
* credential under the same key is not an API key and is ignored rather than coerced.
|
|
31
|
+
*/
|
|
32
|
+
function storedApiKeyReference(settings, authPath) {
|
|
33
|
+
const credential = readStoredCredential(webSearchCredentialId(settings), authPath);
|
|
34
|
+
if (credential?.type !== "api_key")
|
|
35
|
+
return undefined;
|
|
36
|
+
return credential.key?.trim() || undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reject a literal secret configured in settings.
|
|
40
|
+
*
|
|
41
|
+
* `webSearch.apiKey` is read from project settings as well as global ones, and this
|
|
42
|
+
* repository deliberately does not gitignore `<project>/.apex-code/` -- that directory
|
|
43
|
+
* is meant to be versioned and shared with a team. A literal key written there would be
|
|
44
|
+
* committed and handed to everyone who clones the repository.
|
|
45
|
+
*
|
|
46
|
+
* A reference (`$VAR`, `${VAR}`, `!command`) names where the secret lives without
|
|
47
|
+
* containing it, so it is safe to commit. AGENTS.md already states that no credential
|
|
48
|
+
* belongs in a file the settings loader writes; this makes that rule enforced rather
|
|
49
|
+
* than documented. `auth.json` still accepts literals, because holding secrets outside
|
|
50
|
+
* the repository is what the credential store is for.
|
|
51
|
+
*/
|
|
52
|
+
export function webSearchSettingsError(settings) {
|
|
53
|
+
const configured = settings?.apiKey?.trim();
|
|
54
|
+
if (!configured)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (isCommandConfigValue(configured))
|
|
57
|
+
return undefined;
|
|
58
|
+
if (getConfigValueEnvVarNames(configured).length > 0)
|
|
59
|
+
return undefined;
|
|
60
|
+
// The value itself is never echoed: this message reaches the model, and from there a
|
|
61
|
+
// transcript. Naming the setting is enough to act on.
|
|
62
|
+
return `webSearch.apiKey must be a reference, not a literal key, because project settings are versioned and shared. Use "$EXA_API_KEY", "\${YOUR_VAR}", or "!your-command", and keep the secret in your environment or credential store.`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Pick one reference, then resolve it once.
|
|
66
|
+
*
|
|
67
|
+
* Order is explicit configuration, then saved credential, then ambient environment.
|
|
68
|
+
* A user who just typed a key into the settings dialog expects it to beat a stale
|
|
69
|
+
* export they have forgotten about, and an explicit `webSearch.apiKey` in settings is
|
|
70
|
+
* a direct instruction that should beat both.
|
|
71
|
+
*/
|
|
72
|
+
function apiKeyReferenceFor(settings, authPath) {
|
|
73
|
+
// A refused literal falls through rather than being honoured, so a committed key is
|
|
74
|
+
// inert instead of quietly working for whoever cloned the repository.
|
|
75
|
+
const configured = webSearchSettingsError(settings) ? undefined : settings?.apiKey?.trim();
|
|
76
|
+
return configured || storedApiKeyReference(settings, authPath) || definitionFor(settings).defaultApiKeyReference;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The host `web_search` needs on the sandbox allowlist, or undefined when no
|
|
80
|
+
* credential is configured for the selected backend.
|
|
81
|
+
*
|
|
82
|
+
* Deliberately checks whether the key *reference* resolves rather than resolving it:
|
|
83
|
+
* the supervisor calls this on every launch, and a `!command` reference would
|
|
84
|
+
* otherwise spawn a shell before the child even starts. That check is an environment
|
|
85
|
+
* lookup for a `$VAR` reference and free for a command reference.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveWebSearchHost(settings, env, authPath) {
|
|
88
|
+
const definition = definitionFor(settings);
|
|
89
|
+
return isConfigValueConfigured(apiKeyReferenceFor(settings, authPath), env) ? definition.host : undefined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Build the configured `web_search` backend, or undefined when no credential
|
|
93
|
+
* resolves.
|
|
94
|
+
*
|
|
95
|
+
* Undefined leaves the tool on its unconfigured operations, which throw a
|
|
96
|
+
* model-readable "not configured" error. That is deliberately not the same thing as
|
|
97
|
+
* hiding the tool: a session that silently lacks `web_search` cannot tell the model
|
|
98
|
+
* why, and the throw names the missing piece.
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* What to tell the model, and through it the user, when nothing is configured.
|
|
102
|
+
*
|
|
103
|
+
* Named here rather than in `web-search.ts` because only this module knows which
|
|
104
|
+
* backend was selected and therefore which credential to name. The audience is a
|
|
105
|
+
* person who asked the agent to search something, so it names the two things they
|
|
106
|
+
* can actually do, not the SDK option an embedder would pass.
|
|
107
|
+
*/
|
|
108
|
+
export function unconfiguredWebSearchMessage(settings) {
|
|
109
|
+
const definition = definitionFor(settings);
|
|
110
|
+
const variable = definition.defaultApiKeyReference.replace(/^\$/, "");
|
|
111
|
+
return `web_search has no API key configured. Set ${variable} in the environment, or run /settings and add a ${definition.credentialId} key.`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A `web_search` backend that resolves its credential on each call.
|
|
115
|
+
*
|
|
116
|
+
* The session builds its tool registry once, at construction, so operations captured
|
|
117
|
+
* there would pin whatever was configured at startup. A key saved from the settings
|
|
118
|
+
* panel would then appear to save and do nothing until restart, which is worse than
|
|
119
|
+
* having no settings row at all. Resolving per call costs one small file read and
|
|
120
|
+
* keeps `resolveConfigValue`'s cache for command references.
|
|
121
|
+
*/
|
|
122
|
+
export function createDeferredWebSearchOperations(readSettings, authPath) {
|
|
123
|
+
return {
|
|
124
|
+
async search(query, signal) {
|
|
125
|
+
const settings = readSettings();
|
|
126
|
+
// Reported ahead of the unconfigured message: "no key" and "your key is in the
|
|
127
|
+
// wrong place" need different fixes.
|
|
128
|
+
const settingsError = webSearchSettingsError(settings);
|
|
129
|
+
if (settingsError)
|
|
130
|
+
throw new Error(settingsError);
|
|
131
|
+
const operations = resolveWebSearchOperations(settings, undefined, authPath);
|
|
132
|
+
if (!operations)
|
|
133
|
+
throw new Error(unconfiguredWebSearchMessage(settings));
|
|
134
|
+
return operations.search(query, signal);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
export function resolveWebSearchOperations(settings, env, authPath) {
|
|
139
|
+
const apiKey = resolveConfigValue(apiKeyReferenceFor(settings, authPath), env)?.trim();
|
|
140
|
+
if (!apiKey)
|
|
141
|
+
return undefined;
|
|
142
|
+
return definitionFor(settings).create({
|
|
143
|
+
apiKey,
|
|
144
|
+
...(settings?.endpoint === undefined ? {} : { endpoint: settings.endpoint }),
|
|
145
|
+
...(settings?.numResults === undefined ? {} : { numResults: settings.numResults }),
|
|
146
|
+
...(settings?.snippetMaxCharacters === undefined ? {} : { snippetMaxCharacters: settings.snippetMaxCharacters }),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=web-search-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-search-provider.js","sourceRoot":"","sources":["../../src/core/web-search-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { readStoredCredential } from \"./auth-storage.ts\";\nimport {\n\tgetConfigValueEnvVarNames,\n\tisCommandConfigValue,\n\tisConfigValueConfigured,\n\tresolveConfigValue,\n} from \"./resolve-config-value.ts\";\nimport type { WebSearchSettings } from \"./settings-manager.ts\";\nimport type { WebSearchOperations } from \"./tools/web-search.ts\";\nimport { createExaWebSearchOperations, EXA_SEARCH_HOST } from \"./tools/web-search-exa.ts\";\n\nexport type WebSearchProviderId = \"exa\";\n\n/**\n * One entry per backend `web_search` can speak to.\n *\n * A table rather than a branch because the swap is the point: the `web_search` tool\n * owns the contract and the permission grammar, the backend owns nothing but an HTTP\n * call, and adding the second backend should be a row here rather than a new code\n * path through the resolver.\n */\ninterface WebSearchProviderDefinition {\n\t/**\n\t * Config-value reference used when settings name no key. Held as a reference,\n\t * never a literal: a resolved key must never reach a file the settings loader\n\t * writes back.\n\t */\n\treadonly defaultApiKeyReference: string;\n\t/** Host the sandbox must allow before this backend can reach anything. */\n\treadonly host: string;\n\t/** `auth.json` key holding a credential saved from the settings panel. */\n\treadonly credentialId: string;\n\tcreate(options: {\n\t\tapiKey: string;\n\t\tendpoint?: string;\n\t\tnumResults?: number;\n\t\tsnippetMaxCharacters?: number;\n\t}): WebSearchOperations;\n}\n\nconst WEB_SEARCH_PROVIDERS: Record<WebSearchProviderId, WebSearchProviderDefinition> = {\n\texa: {\n\t\tdefaultApiKeyReference: \"$EXA_API_KEY\",\n\t\thost: EXA_SEARCH_HOST,\n\t\tcredentialId: \"exa\",\n\t\tcreate: createExaWebSearchOperations,\n\t},\n};\n\n/**\n * Backend used when settings name none. `web_search` still reports itself\n * unconfigured unless this backend's key resolves, so the default selects which\n * credential is looked for, not whether the tool reaches the network.\n */\nexport const DEFAULT_WEB_SEARCH_PROVIDER: WebSearchProviderId = \"exa\";\n\nfunction definitionFor(settings: WebSearchSettings | undefined): WebSearchProviderDefinition {\n\treturn WEB_SEARCH_PROVIDERS[settings?.provider ?? DEFAULT_WEB_SEARCH_PROVIDER];\n}\n\n/** `auth.json` key holding a stored credential for the selected backend. */\nfunction webSearchCredentialId(settings?: WebSearchSettings): string {\n\treturn definitionFor(settings).credentialId;\n}\n\n/**\n * The reference stored by the settings panel, or undefined when nothing is saved.\n *\n * Whatever was saved stays a reference rather than being resolved here, so the one\n * resolution below covers a literal key, a `$VAR`, and a `!command` alike. An OAuth\n * credential under the same key is not an API key and is ignored rather than coerced.\n */\nfunction storedApiKeyReference(settings: WebSearchSettings | undefined, authPath?: string): string | undefined {\n\tconst credential = readStoredCredential(webSearchCredentialId(settings), authPath);\n\tif (credential?.type !== \"api_key\") return undefined;\n\treturn credential.key?.trim() || undefined;\n}\n\n/**\n * Reject a literal secret configured in settings.\n *\n * `webSearch.apiKey` is read from project settings as well as global ones, and this\n * repository deliberately does not gitignore `<project>/.apex-code/` -- that directory\n * is meant to be versioned and shared with a team. A literal key written there would be\n * committed and handed to everyone who clones the repository.\n *\n * A reference (`$VAR`, `${VAR}`, `!command`) names where the secret lives without\n * containing it, so it is safe to commit. AGENTS.md already states that no credential\n * belongs in a file the settings loader writes; this makes that rule enforced rather\n * than documented. `auth.json` still accepts literals, because holding secrets outside\n * the repository is what the credential store is for.\n */\nexport function webSearchSettingsError(settings?: WebSearchSettings): string | undefined {\n\tconst configured = settings?.apiKey?.trim();\n\tif (!configured) return undefined;\n\tif (isCommandConfigValue(configured)) return undefined;\n\tif (getConfigValueEnvVarNames(configured).length > 0) return undefined;\n\t// The value itself is never echoed: this message reaches the model, and from there a\n\t// transcript. Naming the setting is enough to act on.\n\treturn `webSearch.apiKey must be a reference, not a literal key, because project settings are versioned and shared. Use \"$EXA_API_KEY\", \"\\${YOUR_VAR}\", or \"!your-command\", and keep the secret in your environment or credential store.`;\n}\n\n/**\n * Pick one reference, then resolve it once.\n *\n * Order is explicit configuration, then saved credential, then ambient environment.\n * A user who just typed a key into the settings dialog expects it to beat a stale\n * export they have forgotten about, and an explicit `webSearch.apiKey` in settings is\n * a direct instruction that should beat both.\n */\nfunction apiKeyReferenceFor(settings: WebSearchSettings | undefined, authPath?: string): string {\n\t// A refused literal falls through rather than being honoured, so a committed key is\n\t// inert instead of quietly working for whoever cloned the repository.\n\tconst configured = webSearchSettingsError(settings) ? undefined : settings?.apiKey?.trim();\n\treturn configured || storedApiKeyReference(settings, authPath) || definitionFor(settings).defaultApiKeyReference;\n}\n\n/**\n * The host `web_search` needs on the sandbox allowlist, or undefined when no\n * credential is configured for the selected backend.\n *\n * Deliberately checks whether the key *reference* resolves rather than resolving it:\n * the supervisor calls this on every launch, and a `!command` reference would\n * otherwise spawn a shell before the child even starts. That check is an environment\n * lookup for a `$VAR` reference and free for a command reference.\n */\nexport function resolveWebSearchHost(\n\tsettings: WebSearchSettings | undefined,\n\tenv?: Record<string, string>,\n\tauthPath?: string,\n): string | undefined {\n\tconst definition = definitionFor(settings);\n\treturn isConfigValueConfigured(apiKeyReferenceFor(settings, authPath), env) ? definition.host : undefined;\n}\n\n/**\n * Build the configured `web_search` backend, or undefined when no credential\n * resolves.\n *\n * Undefined leaves the tool on its unconfigured operations, which throw a\n * model-readable \"not configured\" error. That is deliberately not the same thing as\n * hiding the tool: a session that silently lacks `web_search` cannot tell the model\n * why, and the throw names the missing piece.\n */\n/**\n * What to tell the model, and through it the user, when nothing is configured.\n *\n * Named here rather than in `web-search.ts` because only this module knows which\n * backend was selected and therefore which credential to name. The audience is a\n * person who asked the agent to search something, so it names the two things they\n * can actually do, not the SDK option an embedder would pass.\n */\nexport function unconfiguredWebSearchMessage(settings?: WebSearchSettings): string {\n\tconst definition = definitionFor(settings);\n\tconst variable = definition.defaultApiKeyReference.replace(/^\\$/, \"\");\n\treturn `web_search has no API key configured. Set ${variable} in the environment, or run /settings and add a ${definition.credentialId} key.`;\n}\n\n/**\n * A `web_search` backend that resolves its credential on each call.\n *\n * The session builds its tool registry once, at construction, so operations captured\n * there would pin whatever was configured at startup. A key saved from the settings\n * panel would then appear to save and do nothing until restart, which is worse than\n * having no settings row at all. Resolving per call costs one small file read and\n * keeps `resolveConfigValue`'s cache for command references.\n */\nexport function createDeferredWebSearchOperations(\n\treadSettings: () => WebSearchSettings | undefined,\n\tauthPath?: string,\n): WebSearchOperations {\n\treturn {\n\t\tasync search(query, signal) {\n\t\t\tconst settings = readSettings();\n\t\t\t// Reported ahead of the unconfigured message: \"no key\" and \"your key is in the\n\t\t\t// wrong place\" need different fixes.\n\t\t\tconst settingsError = webSearchSettingsError(settings);\n\t\t\tif (settingsError) throw new Error(settingsError);\n\t\t\tconst operations = resolveWebSearchOperations(settings, undefined, authPath);\n\t\t\tif (!operations) throw new Error(unconfiguredWebSearchMessage(settings));\n\t\t\treturn operations.search(query, signal);\n\t\t},\n\t};\n}\n\nexport function resolveWebSearchOperations(\n\tsettings: WebSearchSettings | undefined,\n\tenv?: Record<string, string>,\n\tauthPath?: string,\n): WebSearchOperations | undefined {\n\tconst apiKey = resolveConfigValue(apiKeyReferenceFor(settings, authPath), env)?.trim();\n\tif (!apiKey) return undefined;\n\treturn definitionFor(settings).create({\n\t\tapiKey,\n\t\t...(settings?.endpoint === undefined ? {} : { endpoint: settings.endpoint }),\n\t\t...(settings?.numResults === undefined ? {} : { numResults: settings.numResults }),\n\t\t...(settings?.snippetMaxCharacters === undefined ? {} : { snippetMaxCharacters: settings.snippetMaxCharacters }),\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/llama/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gCAAgC,CAAC;AAyC5F,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/llama/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gCAAgC,CAAC;AAyC5F,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA4L7D","sourcesContent":["import type { ExtensionAPI, ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport { formatBytes, LlamaClient, type LlamaModelInfo, normalizeLlamaServerUrl } from \"./client.ts\";\nimport { findHuggingFaceToken, HuggingFaceClient } from \"./huggingface.ts\";\nimport { createLlamaProvider, LLAMA_PROVIDER_ID } from \"./provider.ts\";\nimport { type LlamaUi, runWithProgress, showLlamaUi } from \"./ui.ts\";\n\nfunction modelIsLoaded(model: LlamaModelInfo): boolean {\n\treturn model.status.value === \"loaded\" || model.status.value === \"sleeping\";\n}\n\nfunction isConnectionError(error: unknown): boolean {\n\tif (!(error instanceof Error)) return false;\n\tconst message = `${error.name} ${error.message}`.toLowerCase();\n\treturn message.includes(\"fetch failed\") || message.includes(\"timeout\") || message.includes(\"network\");\n}\n\nfunction connectionErrorMessage(error: unknown): string {\n\tif (isConnectionError(error)) return \"Could not connect to the server.\";\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction parseHuggingFaceModel(value: string): { repository: string; quantization?: string } {\n\tconst colon = value.indexOf(\":\", value.indexOf(\"/\") + 1);\n\treturn colon < 0\n\t\t? { repository: value }\n\t\t: { repository: value.slice(0, colon), quantization: value.slice(colon + 1) };\n}\n\nasync function configuredClient(ctx: ExtensionCommandContext): Promise<LlamaClient | undefined> {\n\tconst result = await ctx.modelRegistry.getProviderAuth(LLAMA_PROVIDER_ID);\n\tif (!result) {\n\t\tctx.ui.notify(`Configure llama.cpp with /login ${LLAMA_PROVIDER_ID}`, \"warning\");\n\t\treturn undefined;\n\t}\n\tconst configuredUrl = result.env?.LLAMA_BASE_URL;\n\tconst serverUrl = normalizeLlamaServerUrl(\n\t\ttypeof configuredUrl === \"string\" && configuredUrl ? configuredUrl : (result.auth.baseUrl ?? \"\"),\n\t);\n\treturn new LlamaClient(serverUrl, result.auth.apiKey);\n}\n\nexport default function llamaExtension(pi: ExtensionAPI): void {\n\tconst provider = createLlamaProvider();\n\tpi.registerProvider(provider.provider);\n\n\tconst syncCatalog = async (\n\t\tctx: ExtensionCommandContext,\n\t\tclient: LlamaClient,\n\t\tcatalog?: LlamaModelInfo[],\n\t): Promise<LlamaModelInfo[]> => {\n\t\tconst signal = AbortSignal.timeout(15_000);\n\t\tconst current = catalog ?? (await client.list({ signal }));\n\t\tprovider.setCatalog(current, client.serverUrl);\n\t\tconst result = await ctx.modelRegistry.refresh({\n\t\t\tproviders: [LLAMA_PROVIDER_ID],\n\t\t\t// /llama already contacted the configured llama.cpp server, so keep this refresh live even in APEX_CODE_OFFLINE.\n\t\t\tallowNetwork: true,\n\t\t\tsignal,\n\t\t});\n\t\tif (result.aborted) throw new Error(\"Model catalog refresh timed out.\");\n\t\tconst refreshError = result.errors.get(LLAMA_PROVIDER_ID);\n\t\tif (refreshError) throw refreshError;\n\t\treturn current;\n\t};\n\n\tconst loadModel = async (\n\t\tctx: ExtensionCommandContext,\n\t\tui: LlamaUi,\n\t\tclient: LlamaClient,\n\t\tcatalog: LlamaModelInfo[],\n\t\ttarget: LlamaModelInfo,\n\t): Promise<void> => {\n\t\tconst loaded = catalog.filter((model) => model.id !== target.id && modelIsLoaded(model));\n\t\tlet replace = false;\n\t\tif (loaded.length > 0) {\n\t\t\tconst choice = await ui.select(`${loaded.length} model${loaded.length === 1 ? \" is\" : \"s are\"} loaded`, [\n\t\t\t\t\"Unload all and load\",\n\t\t\t\t\"Keep loaded and load\",\n\t\t\t\t\"Cancel\",\n\t\t\t]);\n\t\t\tif (!choice || choice === \"Cancel\") return;\n\t\t\treplace = choice === \"Unload all and load\";\n\t\t}\n\n\t\tconst restoreLoaded = async (): Promise<void> => {\n\t\t\tctx.ui.notify(\"Restoring previously loaded models\");\n\t\t\tfor (const model of loaded) await client.loadAndWait(model.id, () => {});\n\t\t\tawait syncCatalog(ctx, client);\n\t\t};\n\t\tif (replace) {\n\t\t\tfor (const model of loaded) await client.unloadAndWait(model.id);\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = await runWithProgress(ui, {\n\t\t\t\ttitle: \"Loading model\",\n\t\t\t\tmodel: target.id,\n\t\t\t\tinitialMessage: \"Starting…\",\n\t\t\t\tcancelTitle: \"Stop loading?\",\n\t\t\t\tcancelMessage: target.id,\n\t\t\t\trun: (signal, update) => client.loadAndWait(target.id, update, signal),\n\t\t\t\tcancel: () => client.unload(target.id),\n\t\t\t});\n\t\t\tif (result.cancelled) {\n\t\t\t\tif (replace) await restoreLoaded();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst refreshed = await syncCatalog(ctx, client);\n\t\t\tconst loadedModel = refreshed.find((model) => model.id === target.id);\n\t\t\tctx.ui.notify(\n\t\t\t\tloadedModel?.status.value === \"loaded\" ? `Loaded ${target.id}` : `Load started for ${target.id}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (replace) {\n\t\t\t\ttry {\n\t\t\t\t\tawait restoreLoaded();\n\t\t\t\t} catch {\n\t\t\t\t\t// Preserve the original load error.\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tconst unloadModel = async (\n\t\tctx: ExtensionCommandContext,\n\t\tui: LlamaUi,\n\t\tclient: LlamaClient,\n\t\tmodel: LlamaModelInfo,\n\t): Promise<void> => {\n\t\tif (!(await ui.confirm(\"Unload model?\", model.id))) return;\n\t\tawait client.unloadAndWait(model.id);\n\t\tawait syncCatalog(ctx, client);\n\t\tctx.ui.notify(`Unloaded ${model.id}`);\n\t};\n\n\tconst downloadModel = async (ctx: ExtensionCommandContext, ui: LlamaUi, client: LlamaClient): Promise<void> => {\n\t\tconst huggingFace = new HuggingFaceClient(await findHuggingFaceToken());\n\t\tconst selected = await ui.searchModels((query, signal) => huggingFace.search(query, signal));\n\t\tif (!selected) return;\n\t\tconst parsed = parseHuggingFaceModel(selected);\n\t\tui.showStatus(\"Loading model details\", parsed.repository);\n\t\tconst details = await huggingFace.details(parsed.repository);\n\t\tif (details.gated) {\n\t\t\tconst approval = details.gated === \"manual\" ? \"Manual approval is required\" : \"Accept the access terms\";\n\t\t\tconst choice = await ui.select(\n\t\t\t\t`Hugging Face access required\\n${details.id}\\n\\n${approval} at:\\nhttps://huggingface.co/${details.id}\\n\\nThe llama.cpp server needs HF_TOKEN with access.`,\n\t\t\t\t[\"Continue\", \"Back\"],\n\t\t\t);\n\t\t\tif (choice !== \"Continue\") return;\n\t\t}\n\t\tlet quantization = parsed.quantization;\n\t\tif (!quantization && details.quantizations.length > 0) {\n\t\t\tconst options = details.quantizations.map((entry) => {\n\t\t\t\tconst detail = [\n\t\t\t\t\tentry.size === undefined ? undefined : formatBytes(entry.size),\n\t\t\t\t\tentry.name === \"Q4_K_M\" ? \"recommended\" : undefined,\n\t\t\t\t]\n\t\t\t\t\t.filter((value): value is string => Boolean(value))\n\t\t\t\t\t.join(\" · \");\n\t\t\t\treturn detail ? `${entry.name} · ${detail}` : entry.name;\n\t\t\t});\n\t\t\tconst choice = await ui.select(`Select quantization\\n${details.id}`, options);\n\t\t\tif (!choice) return;\n\t\t\tquantization = details.quantizations[options.indexOf(choice)]?.name;\n\t\t\tif (!quantization) return;\n\t\t}\n\t\tconst model = quantization ? `${details.id}:${quantization}` : details.id;\n\t\tconst result = await runWithProgress(ui, {\n\t\t\ttitle: \"Downloading model\",\n\t\t\tmodel,\n\t\t\tinitialMessage: \"Starting…\",\n\t\t\tcancelTitle: \"Stop download?\",\n\t\t\tcancelMessage: model,\n\t\t\trun: (signal, update) => client.downloadAndWait(model, update, signal),\n\t\t\tcancel: () => client.unload(model),\n\t\t});\n\t\tif (result.cancelled) return;\n\t\tawait syncCatalog(ctx, client, result.value);\n\t\tctx.ui.notify(`Downloaded ${model}`);\n\t};\n\n\tpi.registerCommand(\"llama\", {\n\t\tdescription: \"Manage llama.cpp router models\",\n\t\thandler: async (_args, ctx) => {\n\t\t\tif (ctx.mode !== \"tui\") {\n\t\t\t\tctx.ui.notify(\"/llama is available in interactive mode\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst client = await configuredClient(ctx);\n\t\t\tif (!client) return;\n\t\t\tawait showLlamaUi(ctx, async (ui) => {\n\t\t\t\tconst readCatalog = async (): Promise<LlamaModelInfo[] | undefined> => {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn await syncCatalog(ctx, client);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif ((await ui.connectionError(client.serverUrl, connectionErrorMessage(error))) === \"close\") {\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tlet catalog = await readCatalog();\n\t\t\t\tif (!catalog) return;\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst action = await ui.showModels(client.serverUrl, catalog);\n\t\t\t\t\tif (action.type === \"close\") return;\n\t\t\t\t\tlet actionError: unknown;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (action.type === \"download\") await downloadModel(ctx, ui, client);\n\t\t\t\t\t\telse if (modelIsLoaded(action.model)) await unloadModel(ctx, ui, client, action.model);\n\t\t\t\t\t\telse if (action.model.status.value === \"unloaded\")\n\t\t\t\t\t\t\tawait loadModel(ctx, ui, client, catalog, action.model);\n\t\t\t\t\t\telse ctx.ui.notify(`${action.model.id} is ${action.model.status.value}`, \"warning\");\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tactionError = error;\n\t\t\t\t\t}\n\t\t\t\t\tconst refreshed = await readCatalog();\n\t\t\t\t\tif (!refreshed) return;\n\t\t\t\t\tcatalog = refreshed;\n\t\t\t\t\tif (actionError && !isConnectionError(actionError)) {\n\t\t\t\t\t\tctx.ui.notify(actionError instanceof Error ? actionError.message : String(actionError), \"error\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t});\n}\n"]}
|
|
@@ -41,6 +41,8 @@ export default function llamaExtension(pi) {
|
|
|
41
41
|
provider.setCatalog(current, client.serverUrl);
|
|
42
42
|
const result = await ctx.modelRegistry.refresh({
|
|
43
43
|
providers: [LLAMA_PROVIDER_ID],
|
|
44
|
+
// /llama already contacted the configured llama.cpp server, so keep this refresh live even in APEX_CODE_OFFLINE.
|
|
45
|
+
allowNetwork: true,
|
|
44
46
|
signal,
|
|
45
47
|
});
|
|
46
48
|
if (result.aborted)
|