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
|
@@ -14,17 +14,22 @@ import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebu
|
|
|
14
14
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
15
15
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
16
16
|
import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
|
|
17
|
+
import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defaults.js";
|
|
18
|
+
import { getApexEnvironment } from "../../core/environment.js";
|
|
17
19
|
import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
18
20
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
19
21
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
20
22
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
21
23
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScopeFromModels, } from "../../core/model-resolver.js";
|
|
22
24
|
import { CredentialSynchronizationError } from "../../core/model-runtime.js";
|
|
25
|
+
import { aggregateUsagePerformance } from "../../core/observability/aggregate.js";
|
|
23
26
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
27
|
+
import { observeTerminalHandoff, TERMINAL_HANDOFF_PATH_VARIABLE } from "../../core/sandbox/terminal-handoff.js";
|
|
24
28
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
25
29
|
import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
|
|
30
|
+
import { formatShareUnavailableMessage, publishSessionShare } from "../../core/session-share.js";
|
|
31
|
+
import { slugifySkillCommandName } from "../../core/skills.js";
|
|
26
32
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
27
|
-
import { isInstallTelemetryEnabled } from "../../core/telemetry.js";
|
|
28
33
|
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
29
34
|
import { getUsageCostBreakdown } from "../../core/usage-totals.js";
|
|
30
35
|
import { getChangelogPath, getNewEntries, normalizeChangelogLinks, parseChangelog } from "../../utils/changelog.js";
|
|
@@ -33,10 +38,10 @@ import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipb
|
|
|
33
38
|
import { parseGitUrl } from "../../utils/git.js";
|
|
34
39
|
import { openBrowser } from "../../utils/open-browser.js";
|
|
35
40
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
36
|
-
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
37
41
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
42
|
+
import { loadAllHighlightLanguages } from "../../utils/syntax-highlight.js";
|
|
38
43
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
39
|
-
import {
|
|
44
|
+
import { checkForNewApexCodeVersion } from "../../utils/version-check.js";
|
|
40
45
|
import { ArminComponent } from "./components/armin.js";
|
|
41
46
|
import { AssistantMessageComponent } from "./components/assistant-message.js";
|
|
42
47
|
import { BashExecutionComponent } from "./components/bash-execution.js";
|
|
@@ -52,6 +57,7 @@ import { EarendilAnnouncementComponent } from "./components/earendil-announcemen
|
|
|
52
57
|
import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
53
58
|
import { ExtensionInputComponent } from "./components/extension-input.js";
|
|
54
59
|
import { ExtensionSelectorComponent } from "./components/extension-selector.js";
|
|
60
|
+
import { FirstUseHints } from "./components/first-use-hints.js";
|
|
55
61
|
import { FooterComponent, formatTokens } from "./components/footer.js";
|
|
56
62
|
import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
57
63
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
@@ -60,15 +66,18 @@ import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
|
60
66
|
import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
61
67
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
62
68
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
63
|
-
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
69
|
+
import { PERMISSION_MODE_OVERRIDE_HINTS, SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
64
70
|
import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
|
|
71
|
+
import { ApexSplashHeader } from "./components/splash-header.js";
|
|
65
72
|
import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
|
|
73
|
+
import { ThinkingSelectorComponent } from "./components/thinking-selector.js";
|
|
66
74
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
67
75
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
68
76
|
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
69
77
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
70
78
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
71
79
|
import { editInExternalEditor } from "./external-editor.js";
|
|
80
|
+
import { refreshModelCatalogs } from "./model-catalog-refresh.js";
|
|
72
81
|
import { getModelSearchText } from "./model-search.js";
|
|
73
82
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
74
83
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
@@ -90,6 +99,9 @@ class ExpandableText extends Text {
|
|
|
90
99
|
function isCustomSessionEntry(item) {
|
|
91
100
|
return "type" in item && item.type === "custom";
|
|
92
101
|
}
|
|
102
|
+
function isCompactionCostNotice(item) {
|
|
103
|
+
return "type" in item && item.type === "compaction_cost";
|
|
104
|
+
}
|
|
93
105
|
const DEAD_TERMINAL_ERROR_CODES = new Set(["EIO", "EPIPE", "ENOTCONN"]);
|
|
94
106
|
function isDeadTerminalError(error) {
|
|
95
107
|
if (!error || typeof error !== "object" || !("code" in error)) {
|
|
@@ -129,6 +141,11 @@ export function formatResumeCommand(sessionManager) {
|
|
|
129
141
|
function hasDefaultModelProvider(providerId) {
|
|
130
142
|
return providerId in defaultModelPerProvider;
|
|
131
143
|
}
|
|
144
|
+
function llamaCppPostLoginGuidance(actionLabel, loadedModelCount) {
|
|
145
|
+
return loadedModelCount === 0
|
|
146
|
+
? `${actionLabel}. No llama.cpp models are loaded. Use /llama to load a model, then /model to select it.`
|
|
147
|
+
: `${actionLabel}. Use /model to select a loaded llama.cpp model, or /llama to manage models.`;
|
|
148
|
+
}
|
|
132
149
|
const AUTH_TYPE_ORDER = { oauth: 0, api_key: 1 };
|
|
133
150
|
function createFuzzyAutocompleteItems(items, prefix, getSearchText, toAutocompleteItem) {
|
|
134
151
|
const filtered = fuzzyFilter(items, prefix, getSearchText);
|
|
@@ -169,9 +186,21 @@ function formatLoginProviderCompletionDescription(provider) {
|
|
|
169
186
|
export function createInteractiveTui(options) {
|
|
170
187
|
const terminal = options.terminal ?? new ProcessTerminal();
|
|
171
188
|
if (options.tuiMode === "fullscreen") {
|
|
189
|
+
const styleSearchMatch = (text) => theme.bg("searchMatchBg", theme.fg("searchMatchText", text));
|
|
172
190
|
return new TuiAltScreen(terminal, options.showHardwareCursor, options.logDirectory, {
|
|
191
|
+
searchMatchStyle: (text) => theme.underline(styleSearchMatch(text)),
|
|
192
|
+
searchCurrentMatchStyle: (text) => theme.bold(theme.inverse(styleSearchMatch(text))),
|
|
173
193
|
openUrl: openBrowser,
|
|
174
194
|
onRightClickPaste: options.onRightClickPaste,
|
|
195
|
+
copySelection: async (text) => {
|
|
196
|
+
try {
|
|
197
|
+
await copyToClipboard(text);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
175
204
|
});
|
|
176
205
|
}
|
|
177
206
|
return new TuiMainScreen(terminal, options.showHardwareCursor, options.logDirectory);
|
|
@@ -209,6 +238,8 @@ export function createInteractiveTuiReference(getTui) {
|
|
|
209
238
|
}
|
|
210
239
|
export class InteractiveMode {
|
|
211
240
|
runtimeHost;
|
|
241
|
+
/** Settled once the most recent /settings permission-mode write has hit disk. */
|
|
242
|
+
pendingPermissionModeWrite;
|
|
212
243
|
renderer;
|
|
213
244
|
ui;
|
|
214
245
|
mainScreenRenderState;
|
|
@@ -231,6 +262,14 @@ export class InteractiveMode {
|
|
|
231
262
|
footer;
|
|
232
263
|
footerContainer;
|
|
233
264
|
footerDataProvider;
|
|
265
|
+
/**
|
|
266
|
+
* Whether the startup screen is showing its counted inventory line.
|
|
267
|
+
*
|
|
268
|
+
* Warnings are only allowed to collapse into that count when the count is
|
|
269
|
+
* actually on screen. Under a quiet startup there is no splash header, so
|
|
270
|
+
* collapsing them would hide conflicts entirely rather than summarise them.
|
|
271
|
+
*/
|
|
272
|
+
startupInventoryVisible = false;
|
|
234
273
|
// Stored so the same manager can be injected into custom editors, selectors, and extension UI.
|
|
235
274
|
keybindings;
|
|
236
275
|
version;
|
|
@@ -253,6 +292,7 @@ export class InteractiveMode {
|
|
|
253
292
|
// Status line tracking (for mutating immediately-sequential status updates)
|
|
254
293
|
lastStatusSpacer = undefined;
|
|
255
294
|
lastStatusText = undefined;
|
|
295
|
+
managedToolStatusStarted = false;
|
|
256
296
|
// Streaming message tracking
|
|
257
297
|
streamingComponent = undefined;
|
|
258
298
|
streamingMessage = undefined;
|
|
@@ -274,6 +314,7 @@ export class InteractiveMode {
|
|
|
274
314
|
signalCleanupHandlers = [];
|
|
275
315
|
// Track if editor is in bash mode (text starts with !)
|
|
276
316
|
isBashMode = false;
|
|
317
|
+
firstUseHints;
|
|
277
318
|
// Track current bash execution component
|
|
278
319
|
bashComponent = undefined;
|
|
279
320
|
// Track pending bash components (shown in pending area, moved to chat on submit)
|
|
@@ -323,6 +364,14 @@ export class InteractiveMode {
|
|
|
323
364
|
get settingsManager() {
|
|
324
365
|
return this.session.settingsManager;
|
|
325
366
|
}
|
|
367
|
+
offerFirstUseHint(id) {
|
|
368
|
+
this.firstUseHints ??= new FirstUseHints(this.settingsManager.getFirstUseHints());
|
|
369
|
+
const hint = this.firstUseHints.offer(id);
|
|
370
|
+
if (!hint)
|
|
371
|
+
return;
|
|
372
|
+
this.settingsManager.setFirstUseHints(this.firstUseHints.getSeen());
|
|
373
|
+
this.chatContainer.addChild(new Text(theme.fg("dim", hint), this.outputPad, 0));
|
|
374
|
+
}
|
|
326
375
|
constructor(runtimeHost, options = {}) {
|
|
327
376
|
this.runtimeHost = runtimeHost;
|
|
328
377
|
const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
|
|
@@ -333,6 +382,7 @@ export class InteractiveMode {
|
|
|
333
382
|
});
|
|
334
383
|
this.runtimeHost.setRebindSession(async () => {
|
|
335
384
|
await this.rebindCurrentSession({ renderBeforeBind: true });
|
|
385
|
+
await this.themeController.applyFromSettings();
|
|
336
386
|
});
|
|
337
387
|
this.version = VERSION;
|
|
338
388
|
this.renderer = createInteractiveTui({
|
|
@@ -361,12 +411,20 @@ export class InteractiveMode {
|
|
|
361
411
|
this.defaultEditor = new CustomEditor(this.ui, getEditorTheme(), this.keybindings, {
|
|
362
412
|
paddingX: editorPaddingX,
|
|
363
413
|
autocompleteMaxVisible,
|
|
414
|
+
promptPrefix: "› ",
|
|
415
|
+
promptColor: (text) => theme.fg("accent", text),
|
|
416
|
+
placeholder: "Ask anything",
|
|
417
|
+
placeholderColor: (text) => theme.fg("dim", text),
|
|
418
|
+
commandColor: (text) => theme.fg("accent", text),
|
|
419
|
+
surfaceColor: (text) => theme.bg("userMessageBg", text),
|
|
420
|
+
autocompleteRule: (width) => theme.fg("borderMuted", (this.settingsManager.getSymbolPreset() === "ascii" ? "-" : "┄").repeat(Math.max(1, width))),
|
|
421
|
+
autocompleteFooter: () => this.buildAutocompleteFooter(),
|
|
364
422
|
});
|
|
365
423
|
this.editor = this.defaultEditor;
|
|
366
424
|
this.editorContainer = new Container();
|
|
367
425
|
this.editorContainer.addChild(this.editor);
|
|
368
426
|
this.footerDataProvider = new FooterDataProvider(this.sessionManager.getCwd());
|
|
369
|
-
this.footer = new FooterComponent(this.session, this.footerDataProvider);
|
|
427
|
+
this.footer = new FooterComponent(this.session, this.footerDataProvider, this.settingsManager);
|
|
370
428
|
this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
|
|
371
429
|
this.footerContainer = new Container();
|
|
372
430
|
this.footerContainer.addChild(this.footer);
|
|
@@ -375,7 +433,12 @@ export class InteractiveMode {
|
|
|
375
433
|
this.outputPad = this.settingsManager.getOutputPad();
|
|
376
434
|
// Register themes from resource loader and initialize
|
|
377
435
|
setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
|
|
378
|
-
this.themeController = new InteractiveThemeController(this.ui,
|
|
436
|
+
this.themeController = new InteractiveThemeController(this.ui, {
|
|
437
|
+
getSettingsManager: () => this.settingsManager,
|
|
438
|
+
showError: (message) => this.showError(message),
|
|
439
|
+
onChanged: () => this.updateEditorBorderColor(),
|
|
440
|
+
initialThemeSetting: options.initialThemeSetting,
|
|
441
|
+
});
|
|
379
442
|
}
|
|
380
443
|
getAutocompleteSourceTag(sourceInfo) {
|
|
381
444
|
if (!sourceInfo) {
|
|
@@ -445,6 +508,15 @@ export class InteractiveMode {
|
|
|
445
508
|
}));
|
|
446
509
|
};
|
|
447
510
|
}
|
|
511
|
+
const thinkingCommand = slashCommands.find((command) => command.name === "thinking");
|
|
512
|
+
if (thinkingCommand) {
|
|
513
|
+
thinkingCommand.getArgumentCompletions = (prefix) => {
|
|
514
|
+
return createFuzzyAutocompleteItems(this.session.getAvailableThinkingLevels(), prefix, (level) => level, (level) => ({
|
|
515
|
+
value: level,
|
|
516
|
+
label: level,
|
|
517
|
+
}));
|
|
518
|
+
};
|
|
519
|
+
}
|
|
448
520
|
const loginCommand = slashCommands.find((command) => command.name === "login");
|
|
449
521
|
if (loginCommand) {
|
|
450
522
|
loginCommand.getArgumentCompletions = (prefix) => {
|
|
@@ -477,7 +549,7 @@ export class InteractiveMode {
|
|
|
477
549
|
const skillCommandList = [];
|
|
478
550
|
if (this.settingsManager.getEnableSkillCommands()) {
|
|
479
551
|
for (const skill of this.session.resourceLoader.getSkills().skills) {
|
|
480
|
-
const commandName = `skill:${skill.name}`;
|
|
552
|
+
const commandName = `skill:${slugifySkillCommandName(skill.name)}`;
|
|
481
553
|
this.skillCommands.set(commandName, skill.filePath);
|
|
482
554
|
skillCommandList.push({
|
|
483
555
|
name: commandName,
|
|
@@ -516,7 +588,7 @@ export class InteractiveMode {
|
|
|
516
588
|
}
|
|
517
589
|
this.chatContainer.addChild(new DynamicBorder());
|
|
518
590
|
if (this.settingsManager.getCollapseChangelog()) {
|
|
519
|
-
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
591
|
+
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+(?:-[0-9A-Za-z][0-9A-Za-z.-]*)?)\]?/);
|
|
520
592
|
const latestVersion = versionMatch ? versionMatch[1] : this.version;
|
|
521
593
|
const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
|
|
522
594
|
this.chatContainer.addChild(new Text(condensedText, 1, 0));
|
|
@@ -538,14 +610,14 @@ export class InteractiveMode {
|
|
|
538
610
|
tui.setLayoutRoot(this.fullscreenLayoutRoot);
|
|
539
611
|
}
|
|
540
612
|
}
|
|
541
|
-
stopInteractiveTui() {
|
|
542
|
-
if (this.renderer.mode === "fullscreen") {
|
|
613
|
+
stopInteractiveTui(fullscreenExitOutput) {
|
|
614
|
+
if (this.renderer.mode === "fullscreen" && fullscreenExitOutput === "transcript") {
|
|
543
615
|
while (this.renderer.hasOverlayEntries)
|
|
544
616
|
this.renderer.hideOverlay();
|
|
545
617
|
this.switchTuiMode("regular", false, false);
|
|
546
618
|
this.renderer.renderNow();
|
|
547
619
|
}
|
|
548
|
-
this.ui.stop();
|
|
620
|
+
this.ui.stop({ preserveScreen: this.renderer.mode === "fullscreen" });
|
|
549
621
|
}
|
|
550
622
|
switchTuiMode(mode, restoreProgress = true, startRenderer = true) {
|
|
551
623
|
const previousUi = this.renderer;
|
|
@@ -602,10 +674,9 @@ export class InteractiveMode {
|
|
|
602
674
|
this.registerSignalHandlers();
|
|
603
675
|
// Load changelog (only show new entries, skip for resumed sessions)
|
|
604
676
|
this.changelogMarkdown = this.getChangelogForDisplay();
|
|
605
|
-
//
|
|
606
|
-
//
|
|
607
|
-
|
|
608
|
-
this.fdPath = fdPath;
|
|
677
|
+
// Resolve the effective mode before mounting or focusing components. Both
|
|
678
|
+
// operations can schedule a frame even before the renderer is started.
|
|
679
|
+
await this.refreshFooterPermissionMode();
|
|
609
680
|
if (this.session.scopedModels.length > 0 && (this.options.verbose || !this.settingsManager.getQuietStartup())) {
|
|
610
681
|
const modelList = this.session.scopedModels
|
|
611
682
|
.map((sm) => {
|
|
@@ -649,18 +720,23 @@ export class InteractiveMode {
|
|
|
649
720
|
this.widgetContainerBelow,
|
|
650
721
|
this.footerContainer,
|
|
651
722
|
]);
|
|
723
|
+
// Accept text while startup completes, but only enable interrupt, exit, and submission feedback.
|
|
724
|
+
this.defaultEditor.onAction("app.clear", () => this.handleCtrlC());
|
|
725
|
+
this.defaultEditor.onCtrlD = () => this.handleCtrlD();
|
|
726
|
+
this.defaultEditor.onSubmit = (text) => this.handleStartupSubmit(text);
|
|
652
727
|
this.ui.setFocus(this.editor);
|
|
653
|
-
this.setupKeyHandlers();
|
|
654
|
-
this.setupEditorSubmitHandler();
|
|
655
728
|
// Start the UI before initializing extensions so session_start handlers can use interactive dialogs
|
|
656
729
|
this.ui.start();
|
|
657
730
|
this.isInitialized = true;
|
|
658
731
|
await this.themeController.applyFromSettings();
|
|
659
|
-
//
|
|
732
|
+
// Brand splash: mark on the left, runtime metadata on the right. The model
|
|
733
|
+
// and cwd are read through live getters, so they fill in once the session
|
|
734
|
+
// binds in rebindCurrentSession below.
|
|
660
735
|
if (this.options.verbose || !this.settingsManager.getQuietStartup()) {
|
|
661
|
-
const logo = theme.bold(theme.fg("accent", APP_NAME)) + theme.fg("dim", ` v${this.version}`);
|
|
662
736
|
// Build startup instructions using keybinding hint helpers
|
|
663
737
|
const hint = (keybinding, description) => keyHint(keybinding, description);
|
|
738
|
+
// The full cheatsheet is verbose-only. The default screen leads with the
|
|
739
|
+
// mark and the runtime facts that actually differ between launches.
|
|
664
740
|
const expandedInstructions = [
|
|
665
741
|
hint("app.interrupt", "to interrupt"),
|
|
666
742
|
hint("app.clear", "to clear"),
|
|
@@ -682,27 +758,45 @@ export class InteractiveMode {
|
|
|
682
758
|
hint("app.clipboard.pasteImage", "to paste image (with text fallback)"),
|
|
683
759
|
rawKeyHint("drop files", "to attach"),
|
|
684
760
|
].join("\n");
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
761
|
+
this.builtInHeader = new ApexSplashHeader(this.version, () => this.session.state.model?.id, () => this.session.sessionManager.getCwd(), this.options.verbose ? expandedInstructions : undefined, {
|
|
762
|
+
topPadding: true,
|
|
763
|
+
getSymbolPreset: () => this.settingsManager.getSymbolPreset(),
|
|
764
|
+
getExtraMetadata: () => {
|
|
765
|
+
// Which branch the session is rooted on differs between launches
|
|
766
|
+
// and is not derivable from the prompt, so it belongs here. The
|
|
767
|
+
// tray carries it too, but drops it first when space is tight.
|
|
768
|
+
const branch = this.footerDataProvider.getGitBranch();
|
|
769
|
+
return branch ? [{ label: "branch", value: branch }] : [];
|
|
770
|
+
},
|
|
771
|
+
getInventory: () => this.buildStartupInventory(),
|
|
772
|
+
inventoryHint: "/resources",
|
|
773
|
+
getShortcuts: () => this.buildStartupShortcuts(),
|
|
774
|
+
getHint: () => "Apex Code can explain its own features and look up its docs.",
|
|
775
|
+
});
|
|
695
776
|
// Setup UI layout
|
|
696
|
-
this.
|
|
777
|
+
this.startupInventoryVisible = true;
|
|
697
778
|
this.headerContainer.addChild(this.builtInHeader);
|
|
698
779
|
this.headerContainer.addChild(new Spacer(1));
|
|
699
780
|
}
|
|
700
781
|
else {
|
|
701
782
|
// Minimal header when silenced
|
|
783
|
+
this.startupInventoryVisible = false;
|
|
702
784
|
this.builtInHeader = new Text("", 0, 0);
|
|
703
785
|
this.headerContainer.addChild(this.builtInHeader);
|
|
704
786
|
}
|
|
705
787
|
this.ui.requestRender();
|
|
788
|
+
// Ensure fd and rg are available after mounting the TUI (downloads if missing, adds to PATH via getBinDir)
|
|
789
|
+
// so slow downloads do not make startup appear frozen.
|
|
790
|
+
// Both are needed: fd for autocomplete, rg for grep tool and bash commands.
|
|
791
|
+
const [fdPath] = await Promise.all([
|
|
792
|
+
ensureTool("fd", (status) => this.showManagedToolStatus(status)),
|
|
793
|
+
ensureTool("rg", (status) => this.showManagedToolStatus(status)),
|
|
794
|
+
]);
|
|
795
|
+
this.fdPath = fdPath;
|
|
796
|
+
// Enable the remaining input handlers only after managed-tool setup completes.
|
|
797
|
+
this.setupKeyHandlers();
|
|
798
|
+
this.setupEditorSubmitHandler();
|
|
799
|
+
this.ui.requestRender();
|
|
706
800
|
// Initialize extensions first so resources are shown before messages
|
|
707
801
|
await this.rebindCurrentSession();
|
|
708
802
|
// Render initial messages AFTER showing loaded resources
|
|
@@ -719,6 +813,14 @@ export class InteractiveMode {
|
|
|
719
813
|
});
|
|
720
814
|
// Initialize available provider count for footer display
|
|
721
815
|
await this.updateAvailableProviderCount();
|
|
816
|
+
// Flush the completed startup state before loading the remaining syntax grammars.
|
|
817
|
+
this.ui.renderNow();
|
|
818
|
+
void loadAllHighlightLanguages().then(() => {
|
|
819
|
+
if (!this.isInitialized)
|
|
820
|
+
return;
|
|
821
|
+
this.ui.invalidate();
|
|
822
|
+
this.ui.requestRender();
|
|
823
|
+
});
|
|
722
824
|
}
|
|
723
825
|
/**
|
|
724
826
|
* Update terminal title with session name and cwd.
|
|
@@ -739,17 +841,16 @@ export class InteractiveMode {
|
|
|
739
841
|
*/
|
|
740
842
|
async run() {
|
|
741
843
|
await this.init();
|
|
742
|
-
if (!
|
|
844
|
+
if (!getApexEnvironment("APEX_CODE_OFFLINE")) {
|
|
743
845
|
const controller = new AbortController();
|
|
744
846
|
const timeout = setTimeout(() => controller.abort(), 15_000);
|
|
745
|
-
void this.session.modelRuntime
|
|
746
|
-
.refresh({ signal: controller.signal })
|
|
847
|
+
void refreshModelCatalogs(this.session.modelRuntime, controller.signal)
|
|
747
848
|
.then(() => this.updateAvailableProviderCount())
|
|
748
849
|
.catch(() => { })
|
|
749
850
|
.finally(() => clearTimeout(timeout));
|
|
750
851
|
}
|
|
751
852
|
// Start version check asynchronously
|
|
752
|
-
|
|
853
|
+
checkForNewApexCodeVersion(this.version).then((newRelease) => {
|
|
753
854
|
if (newRelease) {
|
|
754
855
|
this.showNewVersionNotification(newRelease);
|
|
755
856
|
}
|
|
@@ -775,7 +876,18 @@ export class InteractiveMode {
|
|
|
775
876
|
}
|
|
776
877
|
});
|
|
777
878
|
// Show startup warnings
|
|
778
|
-
const { migratedProviders, modelFallbackMessage, initialMessage, initialImages, initialMessages } = this.options;
|
|
879
|
+
const { migratedProviders, startupDiagnostics, modelFallbackMessage, initialMessage, initialImages, initialMessages, } = this.options;
|
|
880
|
+
for (const diagnostic of startupDiagnostics ?? []) {
|
|
881
|
+
if (diagnostic.type === "error") {
|
|
882
|
+
this.showError(diagnostic.message);
|
|
883
|
+
}
|
|
884
|
+
else if (diagnostic.type === "warning") {
|
|
885
|
+
this.showWarning(diagnostic.message);
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
this.showStatus(diagnostic.message);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
779
891
|
if (migratedProviders && migratedProviders.length > 0) {
|
|
780
892
|
this.showWarning(`Migrated credentials to auth.json: ${migratedProviders.join(", ")}`);
|
|
781
893
|
}
|
|
@@ -821,7 +933,7 @@ export class InteractiveMode {
|
|
|
821
933
|
}
|
|
822
934
|
}
|
|
823
935
|
async checkForPackageUpdates() {
|
|
824
|
-
if (
|
|
936
|
+
if (getApexEnvironment("APEX_CODE_OFFLINE")) {
|
|
825
937
|
return [];
|
|
826
938
|
}
|
|
827
939
|
try {
|
|
@@ -874,7 +986,7 @@ export class InteractiveMode {
|
|
|
874
986
|
return "tmux extended-keys is off. Modified Enter keys may not work. Add `set -g extended-keys on` to ~/.tmux.conf and restart tmux.";
|
|
875
987
|
}
|
|
876
988
|
if (extendedKeysFormat === "xterm") {
|
|
877
|
-
return "tmux extended-keys-format is xterm.
|
|
989
|
+
return "tmux extended-keys-format is xterm. Apex Code works best with csi-u. Add `set -g extended-keys-format csi-u` to ~/.tmux.conf and restart tmux.";
|
|
878
990
|
}
|
|
879
991
|
return undefined;
|
|
880
992
|
}
|
|
@@ -891,35 +1003,17 @@ export class InteractiveMode {
|
|
|
891
1003
|
const changelogPath = getChangelogPath();
|
|
892
1004
|
const entries = parseChangelog(changelogPath);
|
|
893
1005
|
if (!lastVersion) {
|
|
894
|
-
// Fresh install - record the version,
|
|
1006
|
+
// Fresh install - record the version, don't show changelog
|
|
895
1007
|
this.settingsManager.setLastChangelogVersion(VERSION);
|
|
896
|
-
this.reportInstallTelemetry(VERSION);
|
|
897
1008
|
return undefined;
|
|
898
1009
|
}
|
|
899
1010
|
const newEntries = getNewEntries(entries, lastVersion);
|
|
900
1011
|
if (newEntries.length > 0) {
|
|
901
1012
|
this.settingsManager.setLastChangelogVersion(VERSION);
|
|
902
|
-
this.reportInstallTelemetry(VERSION);
|
|
903
1013
|
return newEntries.map((e) => normalizeChangelogLinks(e.content, e)).join("\n\n");
|
|
904
1014
|
}
|
|
905
1015
|
return undefined;
|
|
906
1016
|
}
|
|
907
|
-
reportInstallTelemetry(version) {
|
|
908
|
-
if (process.env.PI_OFFLINE) {
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
if (!isInstallTelemetryEnabled(this.settingsManager)) {
|
|
912
|
-
return;
|
|
913
|
-
}
|
|
914
|
-
void fetch(`https://pi.dev/api/report-install?version=${encodeURIComponent(version)}`, {
|
|
915
|
-
headers: {
|
|
916
|
-
"User-Agent": getPiUserAgent(version),
|
|
917
|
-
},
|
|
918
|
-
signal: AbortSignal.timeout(5000),
|
|
919
|
-
})
|
|
920
|
-
.then(() => undefined)
|
|
921
|
-
.catch(() => undefined);
|
|
922
|
-
}
|
|
923
1017
|
getMarkdownThemeWithSettings() {
|
|
924
1018
|
return {
|
|
925
1019
|
...getMarkdownTheme(),
|
|
@@ -1216,7 +1310,7 @@ export class InteractiveMode {
|
|
|
1216
1310
|
showLoadedResources(options) {
|
|
1217
1311
|
// Resource rendering is idempotent; chat clears no longer clear this separate container.
|
|
1218
1312
|
this.loadedResourcesContainer.clear();
|
|
1219
|
-
const showListing = options?.force || this.options.verbose
|
|
1313
|
+
const showListing = options?.force || this.options.verbose;
|
|
1220
1314
|
const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
|
|
1221
1315
|
if (!showListing && !showDiagnostics) {
|
|
1222
1316
|
return;
|
|
@@ -1333,43 +1427,105 @@ export class InteractiveMode {
|
|
|
1333
1427
|
addLoadedSection("Themes", themeCompactList, themeList);
|
|
1334
1428
|
}
|
|
1335
1429
|
}
|
|
1430
|
+
// Warnings collapse into the counted line when that line is on screen; the
|
|
1431
|
+
// full trace lives behind /resources. Errors always surface inline,
|
|
1432
|
+
// because an error means a resource did not load at all.
|
|
1336
1433
|
if (showDiagnostics) {
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
const
|
|
1346
|
-
this.loadedResourcesContainer.addChild(new Text(`${theme.fg(
|
|
1347
|
-
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1348
|
-
}
|
|
1349
|
-
const extensionDiagnostics = [];
|
|
1350
|
-
const extensionErrors = this.session.resourceLoader.getExtensions().errors;
|
|
1351
|
-
if (extensionErrors.length > 0) {
|
|
1352
|
-
for (const error of extensionErrors) {
|
|
1353
|
-
extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
const commandDiagnostics = this.session.extensionRunner.getCommandDiagnostics();
|
|
1357
|
-
extensionDiagnostics.push(...commandDiagnostics);
|
|
1358
|
-
extensionDiagnostics.push(...this.getBuiltInCommandConflictDiagnostics(this.session.extensionRunner));
|
|
1359
|
-
const shortcutDiagnostics = this.session.extensionRunner.getShortcutDiagnostics();
|
|
1360
|
-
extensionDiagnostics.push(...shortcutDiagnostics);
|
|
1361
|
-
if (extensionDiagnostics.length > 0) {
|
|
1362
|
-
const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);
|
|
1363
|
-
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
|
|
1364
|
-
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1365
|
-
}
|
|
1366
|
-
const themeDiagnostics = themesResult.diagnostics;
|
|
1367
|
-
if (themeDiagnostics.length > 0) {
|
|
1368
|
-
const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
|
|
1369
|
-
this.loadedResourcesContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
|
|
1434
|
+
const collapseWarnings = !showListing && this.startupInventoryVisible;
|
|
1435
|
+
for (const group of this.collectDiagnosticGroups()) {
|
|
1436
|
+
const visible = collapseWarnings
|
|
1437
|
+
? group.diagnostics.filter((diagnostic) => diagnostic.type === "error")
|
|
1438
|
+
: group.diagnostics;
|
|
1439
|
+
if (visible.length === 0)
|
|
1440
|
+
continue;
|
|
1441
|
+
const severity = visible.some((diagnostic) => diagnostic.type === "error") ? "error" : "warning";
|
|
1442
|
+
const body = this.formatDiagnostics(visible, sourceInfos);
|
|
1443
|
+
this.loadedResourcesContainer.addChild(new Text(`${theme.fg(severity, `[${group.label}]`)}\n${body}`, 0, 0));
|
|
1370
1444
|
this.loadedResourcesContainer.addChild(new Spacer(1));
|
|
1371
1445
|
}
|
|
1372
1446
|
}
|
|
1447
|
+
// Counts on the startup screen are read at render time, so they fill in
|
|
1448
|
+
// once resources finish loading without an explicit refresh here.
|
|
1449
|
+
this.builtInHeader?.invalidate?.();
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Every startup diagnostic, grouped by the resource kind that produced it.
|
|
1453
|
+
*
|
|
1454
|
+
* One list feeds both the counted line in the header and the detailed
|
|
1455
|
+
* listing, so the two can never disagree about how many issues exist.
|
|
1456
|
+
*/
|
|
1457
|
+
collectDiagnosticGroups() {
|
|
1458
|
+
const extensionDiagnostics = [
|
|
1459
|
+
...this.session.resourceLoader
|
|
1460
|
+
.getExtensions()
|
|
1461
|
+
.errors.map((error) => ({ type: "error", message: error.error, path: error.path })),
|
|
1462
|
+
...this.session.extensionRunner.getCommandDiagnostics(),
|
|
1463
|
+
...this.getBuiltInCommandConflictDiagnostics(this.session.extensionRunner),
|
|
1464
|
+
...this.session.extensionRunner.getShortcutDiagnostics(),
|
|
1465
|
+
];
|
|
1466
|
+
return [
|
|
1467
|
+
{ label: "Skill conflicts", diagnostics: this.session.resourceLoader.getSkills().diagnostics },
|
|
1468
|
+
{ label: "Prompt conflicts", diagnostics: this.session.resourceLoader.getPrompts().diagnostics },
|
|
1469
|
+
{ label: "Extension issues", diagnostics: extensionDiagnostics },
|
|
1470
|
+
{ label: "Theme conflicts", diagnostics: this.session.resourceLoader.getThemes().diagnostics },
|
|
1471
|
+
].filter((group) => group.diagnostics.length > 0);
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* The counted line in the ruled band under the mark.
|
|
1475
|
+
*
|
|
1476
|
+
* The startup screen used to print all 152 skill names across fifteen rows.
|
|
1477
|
+
* A count answers the only question that screen can usefully answer, which
|
|
1478
|
+
* is what got loaded; the names live behind /resources now.
|
|
1479
|
+
*/
|
|
1480
|
+
/**
|
|
1481
|
+
* The sigil row under the hint: how to reach commands, bash, and files.
|
|
1482
|
+
*
|
|
1483
|
+
* These are the only three characters that change what the composer does, so
|
|
1484
|
+
* they take the accent and everything around them stays quiet.
|
|
1485
|
+
*/
|
|
1486
|
+
/** Live keybindings under the autocomplete dropdown. */
|
|
1487
|
+
buildAutocompleteFooter() {
|
|
1488
|
+
const separator = theme.fg("borderMuted", this.settingsManager.getSymbolPreset() === "ascii" ? " - " : " · ");
|
|
1489
|
+
return [
|
|
1490
|
+
rawKeyHint(`${keyText("tui.select.up")}/${keyText("tui.select.down")}`, "move"),
|
|
1491
|
+
keyHint("tui.select.confirm", "select"),
|
|
1492
|
+
keyHint("tui.input.tab", "complete"),
|
|
1493
|
+
keyHint("tui.select.cancel", "dismiss"),
|
|
1494
|
+
].join(separator);
|
|
1495
|
+
}
|
|
1496
|
+
buildStartupShortcuts() {
|
|
1497
|
+
const entry = (sigil, label) => `${theme.fg("accent", sigil)} ${theme.fg("muted", label)}`;
|
|
1498
|
+
return [
|
|
1499
|
+
entry("/", "commands"),
|
|
1500
|
+
entry("!", "bash"),
|
|
1501
|
+
entry("@", "files"),
|
|
1502
|
+
`${theme.fg("dim", keyText("app.interrupt"))} ${theme.fg("muted", "interrupt")}`,
|
|
1503
|
+
].join(" ");
|
|
1504
|
+
}
|
|
1505
|
+
buildStartupInventory() {
|
|
1506
|
+
const counted = (total, singular) => `${total} ${singular}${total === 1 ? "" : "s"}`;
|
|
1507
|
+
const parts = [];
|
|
1508
|
+
const skills = this.session.resourceLoader.getSkills().skills.length;
|
|
1509
|
+
const extensions = this.session.resourceLoader.getExtensions().extensions.filter((e) => !e.hidden).length;
|
|
1510
|
+
const prompts = this.session.resourceLoader.getPrompts().prompts.length;
|
|
1511
|
+
if (skills > 0)
|
|
1512
|
+
parts.push(theme.fg("muted", counted(skills, "skill")));
|
|
1513
|
+
if (extensions > 0)
|
|
1514
|
+
parts.push(theme.fg("muted", counted(extensions, "extension")));
|
|
1515
|
+
if (prompts > 0)
|
|
1516
|
+
parts.push(theme.fg("muted", counted(prompts, "prompt")));
|
|
1517
|
+
const diagnostics = this.collectDiagnosticGroups().flatMap((group) => group.diagnostics);
|
|
1518
|
+
const errors = diagnostics.filter((diagnostic) => diagnostic.type === "error").length;
|
|
1519
|
+
const conflicts = diagnostics.length - errors;
|
|
1520
|
+
if (errors > 0)
|
|
1521
|
+
parts.push(theme.fg("error", counted(errors, "error")));
|
|
1522
|
+
if (conflicts > 0)
|
|
1523
|
+
parts.push(theme.fg("warning", counted(conflicts, "conflict")));
|
|
1524
|
+
if (parts.length === 0)
|
|
1525
|
+
return undefined;
|
|
1526
|
+
const ascii = this.settingsManager.getSymbolPreset() === "ascii";
|
|
1527
|
+
const separator = theme.fg("borderMuted", ascii ? " - " : " · ");
|
|
1528
|
+
return parts.join(separator);
|
|
1373
1529
|
}
|
|
1374
1530
|
/**
|
|
1375
1531
|
* Initialize the extension system with TUI-based UI context.
|
|
@@ -1457,6 +1613,7 @@ export class InteractiveMode {
|
|
|
1457
1613
|
this.applyFullscreenScrollbarSetting();
|
|
1458
1614
|
this.footer.setSession(this.session);
|
|
1459
1615
|
this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
|
|
1616
|
+
void this.refreshFooterPermissionMode();
|
|
1460
1617
|
this.footerDataProvider.setCwd(this.sessionManager.getCwd());
|
|
1461
1618
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
1462
1619
|
this.outputPad = this.settingsManager.getOutputPad();
|
|
@@ -1499,7 +1656,7 @@ export class InteractiveMode {
|
|
|
1499
1656
|
const message = error instanceof Error ? error.message : String(error);
|
|
1500
1657
|
this.showError(`${prefix}: ${message}`);
|
|
1501
1658
|
stopThemeWatcher();
|
|
1502
|
-
this.stop();
|
|
1659
|
+
this.stop("transcript");
|
|
1503
1660
|
process.exit(1);
|
|
1504
1661
|
}
|
|
1505
1662
|
renderCurrentSessionState() {
|
|
@@ -1509,9 +1666,14 @@ export class InteractiveMode {
|
|
|
1509
1666
|
this.compactionQueuedMessages = [];
|
|
1510
1667
|
this.streamingComponent = undefined;
|
|
1511
1668
|
this.streamingMessage = undefined;
|
|
1512
|
-
this.
|
|
1669
|
+
this.clearPendingTools();
|
|
1513
1670
|
this.renderInitialMessages();
|
|
1514
1671
|
}
|
|
1672
|
+
clearPendingTools() {
|
|
1673
|
+
for (const component of this.pendingTools.values())
|
|
1674
|
+
component.dispose();
|
|
1675
|
+
this.pendingTools.clear();
|
|
1676
|
+
}
|
|
1515
1677
|
/**
|
|
1516
1678
|
* Get a registered tool definition by name (for custom rendering).
|
|
1517
1679
|
*/
|
|
@@ -1894,7 +2056,7 @@ export class InteractiveMode {
|
|
|
1894
2056
|
/**
|
|
1895
2057
|
* Show a selector for extensions.
|
|
1896
2058
|
*/
|
|
1897
|
-
showExtensionSelector(title, options, opts) {
|
|
2059
|
+
showExtensionSelector(title, options, opts, enableSearch = false) {
|
|
1898
2060
|
return new Promise((resolve) => {
|
|
1899
2061
|
if (opts?.signal?.aborted) {
|
|
1900
2062
|
resolve(undefined);
|
|
@@ -1913,7 +2075,12 @@ export class InteractiveMode {
|
|
|
1913
2075
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
1914
2076
|
this.hideExtensionSelector();
|
|
1915
2077
|
resolve(undefined);
|
|
1916
|
-
}, {
|
|
2078
|
+
}, {
|
|
2079
|
+
tui: this.ui,
|
|
2080
|
+
timeout: opts?.timeout,
|
|
2081
|
+
onToggleToolsExpanded: () => this.toggleToolOutputExpansion(),
|
|
2082
|
+
enableSearch,
|
|
2083
|
+
});
|
|
1917
2084
|
this.disposeActiveSelector();
|
|
1918
2085
|
this.editorContainer.clear();
|
|
1919
2086
|
this.editorContainer.addChild(this.extensionSelector);
|
|
@@ -1932,6 +2099,40 @@ export class InteractiveMode {
|
|
|
1932
2099
|
this.ui.setFocus(this.editor);
|
|
1933
2100
|
this.ui.requestRender();
|
|
1934
2101
|
}
|
|
2102
|
+
async showConfigurationIndex() {
|
|
2103
|
+
const choice = await this.showExtensionSelector("Configuration", [
|
|
2104
|
+
"Settings",
|
|
2105
|
+
"Model",
|
|
2106
|
+
"Model cycling",
|
|
2107
|
+
"Provider login",
|
|
2108
|
+
"Provider logout",
|
|
2109
|
+
"Project trust",
|
|
2110
|
+
"Resources, extensions, and MCP adapters",
|
|
2111
|
+
], undefined, true);
|
|
2112
|
+
switch (choice) {
|
|
2113
|
+
case "Settings":
|
|
2114
|
+
await this.showSettingsSelector();
|
|
2115
|
+
break;
|
|
2116
|
+
case "Model":
|
|
2117
|
+
this.showModelSelector();
|
|
2118
|
+
break;
|
|
2119
|
+
case "Model cycling":
|
|
2120
|
+
await this.showModelsSelector();
|
|
2121
|
+
break;
|
|
2122
|
+
case "Provider login":
|
|
2123
|
+
await this.handleLoginCommand();
|
|
2124
|
+
break;
|
|
2125
|
+
case "Provider logout":
|
|
2126
|
+
this.showOAuthSelector("logout");
|
|
2127
|
+
break;
|
|
2128
|
+
case "Project trust":
|
|
2129
|
+
this.showTrustSelector();
|
|
2130
|
+
break;
|
|
2131
|
+
case "Resources, extensions, and MCP adapters":
|
|
2132
|
+
this.showStatus("Run apex-code config to manage resources, extensions, and MCP adapters.");
|
|
2133
|
+
break;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
1935
2136
|
/**
|
|
1936
2137
|
* Show a confirmation dialog for extensions.
|
|
1937
2138
|
*/
|
|
@@ -2243,6 +2444,8 @@ export class InteractiveMode {
|
|
|
2243
2444
|
const wasBashMode = this.isBashMode;
|
|
2244
2445
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
2245
2446
|
if (wasBashMode !== this.isBashMode) {
|
|
2447
|
+
if (this.isBashMode)
|
|
2448
|
+
this.offerFirstUseHint("bash");
|
|
2246
2449
|
this.updateEditorBorderColor();
|
|
2247
2450
|
}
|
|
2248
2451
|
};
|
|
@@ -2274,7 +2477,7 @@ export class InteractiveMode {
|
|
|
2274
2477
|
if (image) {
|
|
2275
2478
|
const tmpDir = os.tmpdir();
|
|
2276
2479
|
const ext = extensionForImageMimeType(image.mimeType) ?? "png";
|
|
2277
|
-
const fileName = `
|
|
2480
|
+
const fileName = `apex-code-clipboard-${crypto.randomUUID()}.${ext}`;
|
|
2278
2481
|
const filePath = path.join(tmpDir, fileName);
|
|
2279
2482
|
fs.writeFileSync(filePath, Buffer.from(image.bytes));
|
|
2280
2483
|
this.editor.insertTextAtCursor?.(filePath);
|
|
@@ -2291,15 +2494,31 @@ export class InteractiveMode {
|
|
|
2291
2494
|
// Silently ignore clipboard errors (may not have permission, etc.)
|
|
2292
2495
|
}
|
|
2293
2496
|
}
|
|
2497
|
+
handleStartupSubmit(text) {
|
|
2498
|
+
this.editor.setText(text);
|
|
2499
|
+
this.showStatus("Startup is still in progress");
|
|
2500
|
+
}
|
|
2294
2501
|
setupEditorSubmitHandler() {
|
|
2295
2502
|
this.defaultEditor.onSubmit = async (text) => {
|
|
2296
2503
|
text = text.trim();
|
|
2297
2504
|
if (!text)
|
|
2298
2505
|
return;
|
|
2506
|
+
// A mode chosen in /settings is written asynchronously. Awaiting it here
|
|
2507
|
+
// keeps the store authoritative before any tool call can read it, so a
|
|
2508
|
+
// switch *out* of bypassPermissions can never be raced by the next turn.
|
|
2509
|
+
if (this.pendingPermissionModeWrite) {
|
|
2510
|
+
await this.pendingPermissionModeWrite;
|
|
2511
|
+
this.pendingPermissionModeWrite = undefined;
|
|
2512
|
+
}
|
|
2299
2513
|
// Handle commands
|
|
2514
|
+
if (text === "/config") {
|
|
2515
|
+
this.editor.setText("");
|
|
2516
|
+
await this.showConfigurationIndex();
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2300
2519
|
if (text === "/settings") {
|
|
2301
|
-
this.showSettingsSelector();
|
|
2302
2520
|
this.editor.setText("");
|
|
2521
|
+
await this.showSettingsSelector();
|
|
2303
2522
|
return;
|
|
2304
2523
|
}
|
|
2305
2524
|
if (text === "/scoped-models") {
|
|
@@ -2313,6 +2532,12 @@ export class InteractiveMode {
|
|
|
2313
2532
|
await this.handleModelCommand(searchTerm);
|
|
2314
2533
|
return;
|
|
2315
2534
|
}
|
|
2535
|
+
if (text === "/thinking" || text.startsWith("/thinking ")) {
|
|
2536
|
+
const searchTerm = text.startsWith("/thinking ") ? text.slice(10).trim() : undefined;
|
|
2537
|
+
this.editor.setText("");
|
|
2538
|
+
this.handleThinkingCommand(searchTerm);
|
|
2539
|
+
return;
|
|
2540
|
+
}
|
|
2316
2541
|
if (text === "/export" || text.startsWith("/export ")) {
|
|
2317
2542
|
await this.handleExportCommand(text);
|
|
2318
2543
|
this.editor.setText("");
|
|
@@ -2339,7 +2564,7 @@ export class InteractiveMode {
|
|
|
2339
2564
|
return;
|
|
2340
2565
|
}
|
|
2341
2566
|
if (text === "/session") {
|
|
2342
|
-
this.handleSessionCommand();
|
|
2567
|
+
await this.handleSessionCommand();
|
|
2343
2568
|
this.editor.setText("");
|
|
2344
2569
|
return;
|
|
2345
2570
|
}
|
|
@@ -2348,6 +2573,11 @@ export class InteractiveMode {
|
|
|
2348
2573
|
this.editor.setText("");
|
|
2349
2574
|
return;
|
|
2350
2575
|
}
|
|
2576
|
+
if (text === "/resources") {
|
|
2577
|
+
this.showLoadedResources({ force: true });
|
|
2578
|
+
this.editor.setText("");
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2351
2581
|
if (text === "/hotkeys") {
|
|
2352
2582
|
this.handleHotkeysCommand();
|
|
2353
2583
|
this.editor.setText("");
|
|
@@ -2488,7 +2718,7 @@ export class InteractiveMode {
|
|
|
2488
2718
|
this.footer.invalidate();
|
|
2489
2719
|
switch (event.type) {
|
|
2490
2720
|
case "agent_start":
|
|
2491
|
-
this.
|
|
2721
|
+
this.clearPendingTools();
|
|
2492
2722
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
2493
2723
|
this.ui.terminal.setProgress(true);
|
|
2494
2724
|
}
|
|
@@ -2540,6 +2770,7 @@ export class InteractiveMode {
|
|
|
2540
2770
|
this.streamingMessage = event.message;
|
|
2541
2771
|
this.chatContainer.addChild(this.streamingComponent);
|
|
2542
2772
|
this.streamingComponent.updateContent(this.streamingMessage, true);
|
|
2773
|
+
this.updateEditorBorderColor();
|
|
2543
2774
|
this.ui.requestRender();
|
|
2544
2775
|
}
|
|
2545
2776
|
break;
|
|
@@ -2557,6 +2788,7 @@ export class InteractiveMode {
|
|
|
2557
2788
|
component.setExpanded(this.toolOutputExpanded);
|
|
2558
2789
|
this.chatContainer.addChild(component);
|
|
2559
2790
|
this.pendingTools.set(content.id, component);
|
|
2791
|
+
this.offerFirstUseHint("tool-expand");
|
|
2560
2792
|
}
|
|
2561
2793
|
else {
|
|
2562
2794
|
const component = this.pendingTools.get(content.id);
|
|
@@ -2594,7 +2826,7 @@ export class InteractiveMode {
|
|
|
2594
2826
|
isError: true,
|
|
2595
2827
|
});
|
|
2596
2828
|
}
|
|
2597
|
-
this.
|
|
2829
|
+
this.clearPendingTools();
|
|
2598
2830
|
}
|
|
2599
2831
|
else {
|
|
2600
2832
|
// Args are now complete - trigger diff computation for edit tools
|
|
@@ -2606,6 +2838,7 @@ export class InteractiveMode {
|
|
|
2606
2838
|
this.streamingComponent = undefined;
|
|
2607
2839
|
this.streamingMessage = undefined;
|
|
2608
2840
|
this.footer.invalidate();
|
|
2841
|
+
this.updateEditorBorderColor();
|
|
2609
2842
|
}
|
|
2610
2843
|
this.ui.requestRender();
|
|
2611
2844
|
break;
|
|
@@ -2654,7 +2887,7 @@ export class InteractiveMode {
|
|
|
2654
2887
|
this.streamingComponent = undefined;
|
|
2655
2888
|
this.streamingMessage = undefined;
|
|
2656
2889
|
}
|
|
2657
|
-
this.
|
|
2890
|
+
this.clearPendingTools();
|
|
2658
2891
|
this.ui.requestRender();
|
|
2659
2892
|
break;
|
|
2660
2893
|
case "agent_settled":
|
|
@@ -2691,9 +2924,21 @@ export class InteractiveMode {
|
|
|
2691
2924
|
}
|
|
2692
2925
|
}
|
|
2693
2926
|
else if (event.result) {
|
|
2927
|
+
const entries = this.sessionManager.buildContextEntries();
|
|
2928
|
+
if (entries[0]?.type !== "compaction") {
|
|
2929
|
+
throw new Error("Completed compaction is missing from the session context");
|
|
2930
|
+
}
|
|
2694
2931
|
this.chatContainer.clear();
|
|
2695
|
-
|
|
2932
|
+
// The latest compaction is prepended for model context; append it below at its chronological position.
|
|
2933
|
+
this.renderSessionEntries(entries.slice(1));
|
|
2696
2934
|
this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, new Date().toISOString()));
|
|
2935
|
+
if (event.result.usage) {
|
|
2936
|
+
this.addCompactionCostNotice({
|
|
2937
|
+
type: "compaction_cost",
|
|
2938
|
+
kind: "compaction",
|
|
2939
|
+
usage: event.result.usage,
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2697
2942
|
this.footer.invalidate();
|
|
2698
2943
|
}
|
|
2699
2944
|
else if (event.errorMessage) {
|
|
@@ -2766,6 +3011,19 @@ export class InteractiveMode {
|
|
|
2766
3011
|
: message.content.filter((c) => c.type === "text");
|
|
2767
3012
|
return textBlocks.map((c) => c.text).join("");
|
|
2768
3013
|
}
|
|
3014
|
+
/** Show a managed-tool status update in the chat. */
|
|
3015
|
+
showManagedToolStatus(status) {
|
|
3016
|
+
if (!this.managedToolStatusStarted) {
|
|
3017
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3018
|
+
this.managedToolStatusStarted = true;
|
|
3019
|
+
}
|
|
3020
|
+
const message = status.type === "warning" ? `Warning: ${status.message}` : status.message;
|
|
3021
|
+
const color = status.type === "warning" ? "warning" : "dim";
|
|
3022
|
+
this.chatContainer.addChild(new Text(theme.fg(color, message), 1, 0));
|
|
3023
|
+
this.lastStatusSpacer = undefined;
|
|
3024
|
+
this.lastStatusText = undefined;
|
|
3025
|
+
this.ui.requestRender();
|
|
3026
|
+
}
|
|
2769
3027
|
/**
|
|
2770
3028
|
* Show a status message in the chat.
|
|
2771
3029
|
*
|
|
@@ -2886,7 +3144,7 @@ export class InteractiveMode {
|
|
|
2886
3144
|
}
|
|
2887
3145
|
}
|
|
2888
3146
|
renderSessionItems(items, options = {}) {
|
|
2889
|
-
this.
|
|
3147
|
+
this.clearPendingTools();
|
|
2890
3148
|
const renderedPendingTools = new Map();
|
|
2891
3149
|
// Cache-miss notices are not persisted; re-derive them from the full entry
|
|
2892
3150
|
// list and re-inject them after the assistant messages that paid for them.
|
|
@@ -2902,6 +3160,10 @@ export class InteractiveMode {
|
|
|
2902
3160
|
this.addCustomEntryToChat(item);
|
|
2903
3161
|
continue;
|
|
2904
3162
|
}
|
|
3163
|
+
if (isCompactionCostNotice(item)) {
|
|
3164
|
+
this.addCompactionCostNotice(item);
|
|
3165
|
+
continue;
|
|
3166
|
+
}
|
|
2905
3167
|
const message = item;
|
|
2906
3168
|
// Assistant messages need special handling for tool calls
|
|
2907
3169
|
if (message.role === "assistant") {
|
|
@@ -2969,10 +3231,28 @@ export class InteractiveMode {
|
|
|
2969
3231
|
if (entry.type === "custom") {
|
|
2970
3232
|
return [entry];
|
|
2971
3233
|
}
|
|
2972
|
-
|
|
3234
|
+
const messages = sessionEntryToContextMessages(entry);
|
|
3235
|
+
if ((entry.type === "compaction" || entry.type === "branch_summary") && entry.usage && messages.length > 0) {
|
|
3236
|
+
return [...messages, { type: "compaction_cost", kind: entry.type, usage: entry.usage }];
|
|
3237
|
+
}
|
|
3238
|
+
return messages;
|
|
2973
3239
|
});
|
|
2974
3240
|
this.renderSessionItems(items, options);
|
|
2975
3241
|
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Render billing usage for a compaction or branch summary. The notice is derived
|
|
3244
|
+
* from persisted summary usage and is not stored as a separate session entry.
|
|
3245
|
+
*/
|
|
3246
|
+
addCompactionCostNotice(notice) {
|
|
3247
|
+
if (!this.settingsManager.getShowCacheMissNotices())
|
|
3248
|
+
return;
|
|
3249
|
+
const { usage } = notice;
|
|
3250
|
+
const tokens = usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
3251
|
+
const cost = usage.cost.total >= 0.01 ? ` (~$${usage.cost.total.toFixed(2)})` : "";
|
|
3252
|
+
const label = notice.kind === "compaction" ? "Compaction" : "Branch summary";
|
|
3253
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3254
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `${label}: ${formatTokens(tokens)} tokens billed${cost}`), 1, 0));
|
|
3255
|
+
}
|
|
2976
3256
|
/**
|
|
2977
3257
|
* Show a transcript notice when a completed assistant message paid for a
|
|
2978
3258
|
* significant cache miss. Only states observable facts: the miss itself,
|
|
@@ -3024,7 +3304,7 @@ export class InteractiveMode {
|
|
|
3024
3304
|
if (this.chatContainer.children.length > 0) {
|
|
3025
3305
|
this.chatContainer.addChild(new Spacer(1));
|
|
3026
3306
|
}
|
|
3027
|
-
this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart
|
|
3307
|
+
this.chatContainer.addChild(new Text(theme.fg("warning", `This project is not trusted. Project ${CONFIG_DIR_NAME} resources and packages are ignored. Use /trust to save a trust decision, then restart apex-code.`), 1, 0));
|
|
3028
3308
|
}
|
|
3029
3309
|
async getUserInput() {
|
|
3030
3310
|
const queuedInput = this.pendingUserInputs.shift();
|
|
@@ -3137,7 +3417,7 @@ export class InteractiveMode {
|
|
|
3137
3417
|
this.ui.stop();
|
|
3138
3418
|
}
|
|
3139
3419
|
catch { }
|
|
3140
|
-
console.error("
|
|
3420
|
+
console.error("apex-code exiting due to uncaughtException:");
|
|
3141
3421
|
console.error(error);
|
|
3142
3422
|
process.exit(1);
|
|
3143
3423
|
}
|
|
@@ -3183,6 +3463,34 @@ export class InteractiveMode {
|
|
|
3183
3463
|
const uncaughtExceptionHandler = (error) => this.uncaughtCrash(error);
|
|
3184
3464
|
process.prependListener("uncaughtException", uncaughtExceptionHandler);
|
|
3185
3465
|
this.signalCleanupHandlers.push(() => process.off("uncaughtException", uncaughtExceptionHandler));
|
|
3466
|
+
// Lend the terminal back to the supervisor when it needs to draw a sandbox
|
|
3467
|
+
// escalation prompt. The supervisor owns that decision (ADR 0023) and this
|
|
3468
|
+
// process cannot read the answer anyway -- bwrap --new-session leaves it with no
|
|
3469
|
+
// controlling terminal. `ui.stop()` is the same restore Ctrl+Z already performs,
|
|
3470
|
+
// so the terminal is in cooked mode with a visible cursor while the human answers.
|
|
3471
|
+
const handoffDirectory = process.env[TERMINAL_HANDOFF_PATH_VARIABLE];
|
|
3472
|
+
if (handoffDirectory) {
|
|
3473
|
+
const observer = observeTerminalHandoff(handoffDirectory, {
|
|
3474
|
+
suspend: () => {
|
|
3475
|
+
try {
|
|
3476
|
+
this.ui.stop();
|
|
3477
|
+
}
|
|
3478
|
+
catch {
|
|
3479
|
+
// A terminal we cannot restore still leaves the prompt readable.
|
|
3480
|
+
}
|
|
3481
|
+
},
|
|
3482
|
+
resume: () => {
|
|
3483
|
+
try {
|
|
3484
|
+
this.ui.start();
|
|
3485
|
+
this.ui.requestRender(true);
|
|
3486
|
+
}
|
|
3487
|
+
catch {
|
|
3488
|
+
// Nothing further to try; the next render request recovers.
|
|
3489
|
+
}
|
|
3490
|
+
},
|
|
3491
|
+
});
|
|
3492
|
+
this.signalCleanupHandlers.push(() => observer.stop());
|
|
3493
|
+
}
|
|
3186
3494
|
}
|
|
3187
3495
|
unregisterSignalHandlers() {
|
|
3188
3496
|
for (const cleanup of this.signalCleanupHandlers) {
|
|
@@ -3244,6 +3552,7 @@ export class InteractiveMode {
|
|
|
3244
3552
|
this.editor.addToHistory?.(text);
|
|
3245
3553
|
this.editor.setText("");
|
|
3246
3554
|
await this.session.prompt(text, { streamingBehavior: "followUp" });
|
|
3555
|
+
this.offerFirstUseHint("queue");
|
|
3247
3556
|
this.updatePendingMessagesDisplay();
|
|
3248
3557
|
this.ui.requestRender();
|
|
3249
3558
|
}
|
|
@@ -3263,6 +3572,7 @@ export class InteractiveMode {
|
|
|
3263
3572
|
}
|
|
3264
3573
|
}
|
|
3265
3574
|
updateEditorBorderColor() {
|
|
3575
|
+
this.defaultEditor.setModeLabel(this.isBashMode ? "bash" : this.session.isStreaming ? "busy" : undefined);
|
|
3266
3576
|
if (this.isBashMode) {
|
|
3267
3577
|
this.editor.borderColor = theme.getBashModeBorderColor();
|
|
3268
3578
|
}
|
|
@@ -3323,6 +3633,7 @@ export class InteractiveMode {
|
|
|
3323
3633
|
this.showStatus(`Tool output: ${expanded ? "expanded" : "collapsed"}`);
|
|
3324
3634
|
}
|
|
3325
3635
|
toggleThinkingBlockVisibility() {
|
|
3636
|
+
this.offerFirstUseHint("thinking");
|
|
3326
3637
|
this.hideThinkingBlock = !this.hideThinkingBlock;
|
|
3327
3638
|
this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
|
|
3328
3639
|
// Rebuild chat from session messages
|
|
@@ -3374,7 +3685,7 @@ export class InteractiveMode {
|
|
|
3374
3685
|
showNewVersionNotification(release) {
|
|
3375
3686
|
const action = theme.fg("accent", `${APP_NAME} update`);
|
|
3376
3687
|
const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
|
|
3377
|
-
const changelogUrl = "https://
|
|
3688
|
+
const changelogUrl = "https://github.com/Fchery87/apex-code/blob/main/packages/coding-agent/CHANGELOG.md";
|
|
3378
3689
|
const changelogLink = getCapabilities().hyperlinks
|
|
3379
3690
|
? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
|
|
3380
3691
|
: theme.fg("accent", changelogUrl);
|
|
@@ -3606,11 +3917,63 @@ export class InteractiveMode {
|
|
|
3606
3917
|
this.ui.setFocus(created.focus);
|
|
3607
3918
|
this.ui.requestRender();
|
|
3608
3919
|
}
|
|
3609
|
-
|
|
3920
|
+
/**
|
|
3921
|
+
* Resyncs the footer from the store. Called on every session swap, not just at
|
|
3922
|
+
* startup: `applyRuntimeSettings` also repoints the cwd, and cwd selects which
|
|
3923
|
+
* project-scope permission file applies, so the mode genuinely can differ
|
|
3924
|
+
* between two sessions in one process. A footer left showing the old value
|
|
3925
|
+
* would under-report bypassPermissions, which is the one direction that matters.
|
|
3926
|
+
*/
|
|
3927
|
+
async refreshFooterPermissionMode() {
|
|
3928
|
+
const resolution = await this.session.getPermissionMode();
|
|
3929
|
+
this.footer.setPermissionMode(resolution?.mode ?? "default");
|
|
3930
|
+
if (this.isInitialized) {
|
|
3931
|
+
this.ui.requestRender();
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
/**
|
|
3935
|
+
* Writes the mode to user scope, then reports what is actually in force. The
|
|
3936
|
+
* write can be outranked by `--permission-mode` or a project file, and a
|
|
3937
|
+
* settings row that silently does nothing is worse than no row at all.
|
|
3938
|
+
*/
|
|
3939
|
+
async applyPermissionMode(mode) {
|
|
3940
|
+
let resolution;
|
|
3941
|
+
try {
|
|
3942
|
+
const write = this.session.setPermissionMode(mode);
|
|
3943
|
+
this.pendingPermissionModeWrite = write.then(() => { }, () => { });
|
|
3944
|
+
resolution = await write;
|
|
3945
|
+
}
|
|
3946
|
+
catch (error) {
|
|
3947
|
+
// Never swallow this. A permission mode the user believes they set, and
|
|
3948
|
+
// did not, is the one outcome worse than the prompt they were escaping.
|
|
3949
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
3950
|
+
this.chatContainer.addChild(new Text(theme.fg("error", `Permission mode could not be saved: ${detail}`), 1, 0));
|
|
3951
|
+
this.ui.requestRender();
|
|
3952
|
+
return;
|
|
3953
|
+
}
|
|
3954
|
+
if (!resolution)
|
|
3955
|
+
return;
|
|
3956
|
+
const outranked = resolution.mode !== mode;
|
|
3957
|
+
const source = PERMISSION_MODE_OVERRIDE_HINTS[resolution.origin] ?? resolution.origin;
|
|
3958
|
+
const line = outranked
|
|
3959
|
+
? `Permission mode saved as ${mode}, but ${source} sets ${resolution.mode} for this session.`
|
|
3960
|
+
: `Permission mode set to ${mode}.`;
|
|
3961
|
+
this.chatContainer.addChild(new Text(theme.fg(outranked ? "warning" : "muted", line), 1, 0));
|
|
3962
|
+
this.footer.setPermissionMode(resolution.mode);
|
|
3963
|
+
this.ui.requestRender();
|
|
3964
|
+
}
|
|
3965
|
+
async showSettingsSelector() {
|
|
3966
|
+
const permissionMode = await this.session.getPermissionMode();
|
|
3610
3967
|
this.showSelector((done) => {
|
|
3611
3968
|
let selector;
|
|
3969
|
+
const defaultProvider = this.settingsManager.getDefaultProvider();
|
|
3970
|
+
const defaultModelId = this.settingsManager.getDefaultModel();
|
|
3971
|
+
const defaultModel = defaultProvider && defaultModelId ? `${defaultProvider}/${defaultModelId}` : "not set";
|
|
3612
3972
|
selector = new SettingsSelectorComponent({
|
|
3613
3973
|
autoCompact: this.session.autoCompactionEnabled,
|
|
3974
|
+
defaultModel,
|
|
3975
|
+
currentModel: this.session.model,
|
|
3976
|
+
availableDefaultModels: this.session.modelRuntime.getAvailableSnapshot(),
|
|
3614
3977
|
showImages: this.settingsManager.getShowImages(),
|
|
3615
3978
|
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
3616
3979
|
autoResizeImages: this.settingsManager.getImageAutoResize(),
|
|
@@ -3620,20 +3983,22 @@ export class InteractiveMode {
|
|
|
3620
3983
|
followUpMode: this.session.followUpMode,
|
|
3621
3984
|
transport: this.settingsManager.getTransport(),
|
|
3622
3985
|
httpIdleTimeoutMs: this.settingsManager.getHttpIdleTimeoutMs(),
|
|
3623
|
-
thinkingLevel: this.
|
|
3624
|
-
availableThinkingLevels:
|
|
3625
|
-
|
|
3986
|
+
thinkingLevel: this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL,
|
|
3987
|
+
availableThinkingLevels: [...THINKING_LEVEL_OPTIONS],
|
|
3988
|
+
modelThinkingLevels: this.settingsManager.getAllModelThinkingLevels(),
|
|
3989
|
+
currentTheme: this.themeController.getThemeSelection() || "dark",
|
|
3626
3990
|
terminalTheme: this.themeController.getTerminalTheme(),
|
|
3627
3991
|
availableThemes: getAvailableThemes(),
|
|
3628
3992
|
hideThinkingBlock: this.hideThinkingBlock,
|
|
3629
3993
|
mermaidRenderingMode: this.settingsManager.getMermaidRenderingMode(),
|
|
3630
3994
|
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
|
3631
|
-
|
|
3995
|
+
sendProviderAttribution: this.settingsManager.getSendProviderAttribution(),
|
|
3632
3996
|
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
|
3633
3997
|
treeFilterMode: this.settingsManager.getTreeFilterMode(),
|
|
3634
3998
|
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
|
3635
3999
|
showCacheMissNotices: this.settingsManager.getShowCacheMissNotices(),
|
|
3636
4000
|
defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),
|
|
4001
|
+
permissionMode,
|
|
3637
4002
|
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
|
3638
4003
|
outputPad: this.settingsManager.getOutputPad(),
|
|
3639
4004
|
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
|
@@ -3641,6 +4006,7 @@ export class InteractiveMode {
|
|
|
3641
4006
|
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
|
3642
4007
|
showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
|
|
3643
4008
|
tuiMode: this.ui.mode,
|
|
4009
|
+
fullscreenExitOutput: this.settingsManager.getFullscreenExitOutput(),
|
|
3644
4010
|
fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
|
|
3645
4011
|
warnings: this.settingsManager.getWarnings(),
|
|
3646
4012
|
}, {
|
|
@@ -3689,14 +4055,30 @@ export class InteractiveMode {
|
|
|
3689
4055
|
configureHttpDispatcher(timeoutMs);
|
|
3690
4056
|
this.showStatus(`HTTP idle timeout: ${formatHttpIdleTimeoutMs(timeoutMs)}`);
|
|
3691
4057
|
},
|
|
3692
|
-
|
|
3693
|
-
this.
|
|
3694
|
-
|
|
3695
|
-
this.
|
|
4058
|
+
onModelThinkingLevelChange: (provider, modelId, level) => {
|
|
4059
|
+
this.settingsManager.setModelThinkingLevel(provider, modelId, level);
|
|
4060
|
+
// If the override is for the current model, apply it to the session too
|
|
4061
|
+
const current = this.session.model;
|
|
4062
|
+
if (current && current.provider === provider && current.id === modelId) {
|
|
4063
|
+
this.session.setThinkingLevel(level);
|
|
4064
|
+
this.footer.invalidate();
|
|
4065
|
+
this.updateEditorBorderColor();
|
|
4066
|
+
}
|
|
4067
|
+
},
|
|
4068
|
+
onModelThinkingLevelRemove: (provider, modelId) => {
|
|
4069
|
+
this.settingsManager.removeModelThinkingLevel(provider, modelId);
|
|
4070
|
+
// If the override was for the current model, revert to global default
|
|
4071
|
+
const current = this.session.model;
|
|
4072
|
+
if (current && current.provider === provider && current.id === modelId) {
|
|
4073
|
+
const globalDefault = this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
4074
|
+
this.session.setThinkingLevel(globalDefault);
|
|
4075
|
+
this.footer.invalidate();
|
|
4076
|
+
this.updateEditorBorderColor();
|
|
4077
|
+
}
|
|
3696
4078
|
},
|
|
3697
4079
|
onThemeChange: (themeSetting) => {
|
|
3698
4080
|
this.settingsManager.setTheme(themeSetting);
|
|
3699
|
-
void this.themeController.
|
|
4081
|
+
void this.themeController.setThemeSetting(themeSetting);
|
|
3700
4082
|
},
|
|
3701
4083
|
onThemePreview: (themeName) => this.themeController.preview(themeName),
|
|
3702
4084
|
onHideThinkingBlockChange: (hidden) => {
|
|
@@ -3722,8 +4104,8 @@ export class InteractiveMode {
|
|
|
3722
4104
|
onCollapseChangelogChange: (collapsed) => {
|
|
3723
4105
|
this.settingsManager.setCollapseChangelog(collapsed);
|
|
3724
4106
|
},
|
|
3725
|
-
|
|
3726
|
-
this.settingsManager.
|
|
4107
|
+
onSendProviderAttributionChange: (enabled) => {
|
|
4108
|
+
this.settingsManager.setSendProviderAttribution(enabled);
|
|
3727
4109
|
},
|
|
3728
4110
|
onQuietStartupChange: (enabled) => {
|
|
3729
4111
|
this.settingsManager.setQuietStartup(enabled);
|
|
@@ -3731,6 +4113,9 @@ export class InteractiveMode {
|
|
|
3731
4113
|
onDefaultProjectTrustChange: (defaultProjectTrust) => {
|
|
3732
4114
|
this.settingsManager.setDefaultProjectTrust(defaultProjectTrust);
|
|
3733
4115
|
},
|
|
4116
|
+
onPermissionModeChange: (mode) => {
|
|
4117
|
+
void this.applyPermissionMode(mode);
|
|
4118
|
+
},
|
|
3734
4119
|
onDoubleEscapeActionChange: (action) => {
|
|
3735
4120
|
this.settingsManager.setDoubleEscapeAction(action);
|
|
3736
4121
|
},
|
|
@@ -3795,6 +4180,9 @@ export class InteractiveMode {
|
|
|
3795
4180
|
this.statusContainer.clear();
|
|
3796
4181
|
this.showStatus(`TUI mode: ${mode}`);
|
|
3797
4182
|
},
|
|
4183
|
+
onFullscreenExitOutputChange: (output) => {
|
|
4184
|
+
this.settingsManager.setFullscreenExitOutput(output);
|
|
4185
|
+
},
|
|
3798
4186
|
onFullscreenScrollbarChange: (mode) => {
|
|
3799
4187
|
this.settingsManager.setFullscreenScrollbar(mode);
|
|
3800
4188
|
this.applyFullscreenScrollbarSetting();
|
|
@@ -3810,6 +4198,44 @@ export class InteractiveMode {
|
|
|
3810
4198
|
return { component: selector, focus: selector.getSettingsList() };
|
|
3811
4199
|
});
|
|
3812
4200
|
}
|
|
4201
|
+
handleThinkingCommand(searchTerm) {
|
|
4202
|
+
const availableLevels = this.session.getAvailableThinkingLevels();
|
|
4203
|
+
if (!searchTerm) {
|
|
4204
|
+
this.showThinkingSelector();
|
|
4205
|
+
return;
|
|
4206
|
+
}
|
|
4207
|
+
const normalized = searchTerm.trim().toLowerCase();
|
|
4208
|
+
const level = availableLevels.find((candidate) => candidate.toLowerCase() === normalized);
|
|
4209
|
+
if (!level) {
|
|
4210
|
+
this.showError(`Unknown thinking level "${searchTerm}". Available levels: ${availableLevels.join(", ")}.`);
|
|
4211
|
+
return;
|
|
4212
|
+
}
|
|
4213
|
+
this.selectThinkingLevel(level, false);
|
|
4214
|
+
}
|
|
4215
|
+
selectThinkingLevel(level, persist) {
|
|
4216
|
+
try {
|
|
4217
|
+
this.session.setThinkingLevel(level, { persist });
|
|
4218
|
+
this.footer.invalidate();
|
|
4219
|
+
this.updateEditorBorderColor();
|
|
4220
|
+
this.showStatus(persist ? `Default thinking level: ${level}` : `Thinking level: ${level}`);
|
|
4221
|
+
}
|
|
4222
|
+
catch (error) {
|
|
4223
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
showThinkingSelector() {
|
|
4227
|
+
this.showSelector((done) => {
|
|
4228
|
+
const selectLevel = (level, persist) => {
|
|
4229
|
+
this.selectThinkingLevel(level, persist);
|
|
4230
|
+
done();
|
|
4231
|
+
};
|
|
4232
|
+
const selector = new ThinkingSelectorComponent(this.session.thinkingLevel ?? DEFAULT_THINKING_LEVEL, this.session.getAvailableThinkingLevels(), (level) => selectLevel(level, false), () => {
|
|
4233
|
+
done();
|
|
4234
|
+
this.ui.requestRender();
|
|
4235
|
+
}, (level) => selectLevel(level, true), this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);
|
|
4236
|
+
return { component: selector, focus: selector };
|
|
4237
|
+
});
|
|
4238
|
+
}
|
|
3813
4239
|
async handleModelCommand(searchTerm) {
|
|
3814
4240
|
if (!searchTerm) {
|
|
3815
4241
|
this.showModelSelector();
|
|
@@ -3818,7 +4244,7 @@ export class InteractiveMode {
|
|
|
3818
4244
|
const model = await this.findExactModelMatch(searchTerm);
|
|
3819
4245
|
if (model) {
|
|
3820
4246
|
try {
|
|
3821
|
-
await this.session.setModel(model);
|
|
4247
|
+
await this.session.setModel(model, { persist: false });
|
|
3822
4248
|
this.footer.invalidate();
|
|
3823
4249
|
this.updateEditorBorderColor();
|
|
3824
4250
|
this.showStatus(`Model: ${model.id}`);
|
|
@@ -3847,7 +4273,7 @@ export class InteractiveMode {
|
|
|
3847
4273
|
controller.abort();
|
|
3848
4274
|
}, 15_000);
|
|
3849
4275
|
try {
|
|
3850
|
-
const result = await this.session.modelRuntime
|
|
4276
|
+
const result = await refreshModelCatalogs(this.session.modelRuntime, controller.signal);
|
|
3851
4277
|
if (result.aborted && timedOut) {
|
|
3852
4278
|
this.showWarning("Model refresh timed out; searching cached models.");
|
|
3853
4279
|
}
|
|
@@ -3935,7 +4361,7 @@ export class InteractiveMode {
|
|
|
3935
4361
|
onSelect: (selection) => {
|
|
3936
4362
|
trustStore.setMany(selection.updates);
|
|
3937
4363
|
done();
|
|
3938
|
-
this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart
|
|
4364
|
+
this.showStatus(`Saved trust decision: ${selection.trusted ? "trusted" : "untrusted"}. Restart ${APP_NAME} for this to take effect.`);
|
|
3939
4365
|
},
|
|
3940
4366
|
onCancel: () => {
|
|
3941
4367
|
done();
|
|
@@ -3947,13 +4373,13 @@ export class InteractiveMode {
|
|
|
3947
4373
|
}
|
|
3948
4374
|
showModelSelector(initialSearchInput) {
|
|
3949
4375
|
this.showSelector((done) => {
|
|
3950
|
-
const
|
|
4376
|
+
const selectModel = async (model, persist) => {
|
|
3951
4377
|
try {
|
|
3952
|
-
await this.session.setModel(model);
|
|
4378
|
+
await this.session.setModel(model, { persist });
|
|
3953
4379
|
this.footer.invalidate();
|
|
3954
4380
|
this.updateEditorBorderColor();
|
|
3955
4381
|
done();
|
|
3956
|
-
this.showStatus(`Model: ${model.id}`);
|
|
4382
|
+
this.showStatus(persist ? `Default model: ${model.provider}/${model.id}` : `Model: ${model.id}`);
|
|
3957
4383
|
void this.maybeWarnAboutAnthropicSubscriptionAuth(model);
|
|
3958
4384
|
this.checkDaxnutsEasterEgg(model);
|
|
3959
4385
|
}
|
|
@@ -3961,10 +4387,13 @@ export class InteractiveMode {
|
|
|
3961
4387
|
done();
|
|
3962
4388
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
3963
4389
|
}
|
|
3964
|
-
}
|
|
4390
|
+
};
|
|
4391
|
+
const defaultProvider = this.settingsManager.getDefaultProvider();
|
|
4392
|
+
const defaultModel = this.settingsManager.getDefaultModel();
|
|
4393
|
+
const selector = new ModelSelectorComponent(this.ui, this.session.model, this.session.modelRuntime, this.session.scopedModels, (model) => selectModel(model, false), () => {
|
|
3965
4394
|
done();
|
|
3966
4395
|
this.ui.requestRender();
|
|
3967
|
-
}, initialSearchInput);
|
|
4396
|
+
}, initialSearchInput, (model) => selectModel(model, true), defaultProvider && defaultModel ? { provider: defaultProvider, id: defaultModel } : undefined);
|
|
3968
4397
|
return { component: selector, focus: selector, dispose: () => selector.dispose() };
|
|
3969
4398
|
});
|
|
3970
4399
|
}
|
|
@@ -4035,8 +4464,7 @@ export class InteractiveMode {
|
|
|
4035
4464
|
this.ui.requestRender();
|
|
4036
4465
|
},
|
|
4037
4466
|
});
|
|
4038
|
-
void this.session.modelRuntime
|
|
4039
|
-
.refresh({ signal: controller.signal })
|
|
4467
|
+
void refreshModelCatalogs(this.session.modelRuntime, controller.signal)
|
|
4040
4468
|
.then((result) => {
|
|
4041
4469
|
if (disposed)
|
|
4042
4470
|
return;
|
|
@@ -4521,7 +4949,11 @@ export class InteractiveMode {
|
|
|
4521
4949
|
if (isUnknownModel(previousModel)) {
|
|
4522
4950
|
const availableModels = this.session.modelRuntime.getAvailableSnapshot();
|
|
4523
4951
|
const providerModels = availableModels.filter((model) => model.provider === providerId);
|
|
4524
|
-
|
|
4952
|
+
// Matches LLAMA_PROVIDER_ID from extensions/llama/provider.ts; kept inline to avoid coupling interactive mode to the built-in extension.
|
|
4953
|
+
if (providerId === "llama.cpp") {
|
|
4954
|
+
selectionError = llamaCppPostLoginGuidance(actionLabel, providerModels.length);
|
|
4955
|
+
}
|
|
4956
|
+
else if (!hasDefaultModelProvider(providerId)) {
|
|
4525
4957
|
selectionError = `${actionLabel}, but no default model is configured for provider "${providerId}". Use /model to select a model.`;
|
|
4526
4958
|
}
|
|
4527
4959
|
else if (providerModels.length === 0) {
|
|
@@ -4535,7 +4967,7 @@ export class InteractiveMode {
|
|
|
4535
4967
|
}
|
|
4536
4968
|
else {
|
|
4537
4969
|
try {
|
|
4538
|
-
await this.session.setModel(selectedModel);
|
|
4970
|
+
await this.session.setModel(selectedModel, { persist: true });
|
|
4539
4971
|
}
|
|
4540
4972
|
catch (error) {
|
|
4541
4973
|
selectedModel = undefined;
|
|
@@ -4590,7 +5022,7 @@ export class InteractiveMode {
|
|
|
4590
5022
|
this.ui.requestRender();
|
|
4591
5023
|
};
|
|
4592
5024
|
const dialog = new LoginDialogComponent(this.ui, providerOption.id, () => restoreEditor(), providerOption.name, `${providerOption.name} setup`);
|
|
4593
|
-
dialog.showInfo(`${providerOption.method?.name ?? "Authentication"} is configured outside
|
|
5025
|
+
dialog.showInfo(`${providerOption.method?.name ?? "Authentication"} is configured outside Apex Code.`, [], true);
|
|
4594
5026
|
this.editorContainer.clear();
|
|
4595
5027
|
this.editorContainer.addChild(dialog);
|
|
4596
5028
|
this.ui.setFocus(dialog);
|
|
@@ -4827,7 +5259,9 @@ export class InteractiveMode {
|
|
|
4827
5259
|
this.showStatus(`Session exported to: ${filePath}`);
|
|
4828
5260
|
}
|
|
4829
5261
|
else {
|
|
4830
|
-
const filePath = await this.session.exportToHtml(outputPath
|
|
5262
|
+
const filePath = await this.session.exportToHtml(outputPath, {
|
|
5263
|
+
themeName: theme.name,
|
|
5264
|
+
});
|
|
4831
5265
|
this.showStatus(`Session exported to: ${filePath}`);
|
|
4832
5266
|
}
|
|
4833
5267
|
}
|
|
@@ -4903,89 +5337,74 @@ export class InteractiveMode {
|
|
|
4903
5337
|
}
|
|
4904
5338
|
}
|
|
4905
5339
|
async handleShareCommand() {
|
|
4906
|
-
// Check
|
|
5340
|
+
// Check before confirmation so a user without a working GitHub CLI gets an actionable error.
|
|
4907
5341
|
try {
|
|
4908
5342
|
const authResult = spawnSync("gh", ["auth", "status"], { encoding: "utf-8" });
|
|
4909
5343
|
if (authResult.status !== 0) {
|
|
4910
|
-
this.showError("
|
|
5344
|
+
this.showError(formatShareUnavailableMessage("unauthenticated"));
|
|
4911
5345
|
return;
|
|
4912
5346
|
}
|
|
4913
5347
|
}
|
|
4914
5348
|
catch {
|
|
4915
|
-
this.showError(
|
|
4916
|
-
return;
|
|
4917
|
-
}
|
|
4918
|
-
// Export to a temp file
|
|
4919
|
-
const tmpFile = path.join(os.tmpdir(), "session.html");
|
|
4920
|
-
try {
|
|
4921
|
-
await this.session.exportToHtml(tmpFile);
|
|
4922
|
-
}
|
|
4923
|
-
catch (error) {
|
|
4924
|
-
this.showError(`Failed to export session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
5349
|
+
this.showError(formatShareUnavailableMessage("missing"));
|
|
4925
5350
|
return;
|
|
4926
5351
|
}
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
this.editorContainer.clear();
|
|
4930
|
-
this.editorContainer.addChild(loader);
|
|
4931
|
-
this.ui.setFocus(loader);
|
|
4932
|
-
this.ui.requestRender();
|
|
4933
|
-
const restoreEditor = () => {
|
|
4934
|
-
loader.dispose();
|
|
4935
|
-
this.editorContainer.clear();
|
|
4936
|
-
this.editorContainer.addChild(this.editor);
|
|
4937
|
-
this.ui.setFocus(this.editor);
|
|
4938
|
-
try {
|
|
4939
|
-
fs.unlinkSync(tmpFile);
|
|
4940
|
-
}
|
|
4941
|
-
catch {
|
|
4942
|
-
// Ignore cleanup errors
|
|
4943
|
-
}
|
|
4944
|
-
};
|
|
4945
|
-
// Create a secret gist asynchronously
|
|
4946
|
-
let proc = null;
|
|
4947
|
-
loader.onAbort = () => {
|
|
4948
|
-
proc?.kill();
|
|
4949
|
-
restoreEditor();
|
|
4950
|
-
this.showStatus("Share cancelled");
|
|
4951
|
-
};
|
|
5352
|
+
let loader;
|
|
5353
|
+
let proc;
|
|
4952
5354
|
try {
|
|
4953
|
-
const result = await
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
5355
|
+
const result = await publishSessionShare({
|
|
5356
|
+
confirm: () => this.showExtensionConfirm("Publish session to GitHub?", "This uploads a complete HTML export to a secret GitHub Gist. Secret Gists are unlisted, not private or access-controlled; anyone with the URL can read the transcript, prompts, tool activity, and included file content. Review a local /export first if needed."),
|
|
5357
|
+
exportToHtml: async (exportPath) => {
|
|
5358
|
+
await this.session.exportToHtml(exportPath);
|
|
5359
|
+
},
|
|
5360
|
+
publishGist: (exportPath) => new Promise((resolve, reject) => {
|
|
5361
|
+
loader = new BorderedLoader(this.ui, theme, "Creating secret GitHub Gist...");
|
|
5362
|
+
this.editorContainer.clear();
|
|
5363
|
+
this.editorContainer.addChild(loader);
|
|
5364
|
+
this.ui.setFocus(loader);
|
|
5365
|
+
this.ui.requestRender();
|
|
5366
|
+
loader.onAbort = () => proc?.kill();
|
|
5367
|
+
proc = spawn("gh", ["gist", "create", "--public=false", exportPath]);
|
|
5368
|
+
let stdout = "";
|
|
5369
|
+
let stderr = "";
|
|
5370
|
+
proc.stdout?.on("data", (data) => {
|
|
5371
|
+
stdout += data.toString();
|
|
5372
|
+
});
|
|
5373
|
+
proc.stderr?.on("data", (data) => {
|
|
5374
|
+
stderr += data.toString();
|
|
5375
|
+
});
|
|
5376
|
+
proc.on("error", reject);
|
|
5377
|
+
proc.on("close", (code) => {
|
|
5378
|
+
if (loader?.signal.aborted)
|
|
5379
|
+
reject(new Error("Share cancelled"));
|
|
5380
|
+
else if (code !== 0)
|
|
5381
|
+
reject(new Error(stderr.trim() || "Unknown GitHub CLI error"));
|
|
5382
|
+
else
|
|
5383
|
+
resolve(stdout);
|
|
5384
|
+
});
|
|
5385
|
+
}),
|
|
4964
5386
|
});
|
|
4965
|
-
if (
|
|
4966
|
-
|
|
4967
|
-
restoreEditor();
|
|
4968
|
-
if (result.code !== 0) {
|
|
4969
|
-
const errorMsg = result.stderr?.trim() || "Unknown error";
|
|
4970
|
-
this.showError(`Failed to create gist: ${errorMsg}`);
|
|
4971
|
-
return;
|
|
4972
|
-
}
|
|
4973
|
-
// Extract gist ID from the URL returned by gh
|
|
4974
|
-
// gh returns something like: https://gist.github.com/username/GIST_ID
|
|
4975
|
-
const gistUrl = result.stdout?.trim();
|
|
4976
|
-
const gistId = gistUrl?.split("/").pop();
|
|
4977
|
-
if (!gistId) {
|
|
4978
|
-
this.showError("Failed to parse gist ID from gh output");
|
|
5387
|
+
if (result.kind === "cancelled") {
|
|
5388
|
+
this.showStatus("Share cancelled");
|
|
4979
5389
|
return;
|
|
4980
5390
|
}
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
5391
|
+
const previewUrl = getShareViewerUrl(result.gistId);
|
|
5392
|
+
this.showStatus(previewUrl
|
|
5393
|
+
? `Secret GitHub Gist: ${result.gistUrl}\nConfigured preview: ${previewUrl}`
|
|
5394
|
+
: `Secret GitHub Gist: ${result.gistUrl}`);
|
|
4984
5395
|
}
|
|
4985
5396
|
catch (error) {
|
|
4986
|
-
if (
|
|
4987
|
-
|
|
4988
|
-
|
|
5397
|
+
if (error instanceof Error && error.message === "Share cancelled")
|
|
5398
|
+
this.showStatus("Share cancelled");
|
|
5399
|
+
else
|
|
5400
|
+
this.showError(`Failed to create secret GitHub Gist: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
5401
|
+
}
|
|
5402
|
+
finally {
|
|
5403
|
+
if (loader) {
|
|
5404
|
+
loader.dispose();
|
|
5405
|
+
this.editorContainer.clear();
|
|
5406
|
+
this.editorContainer.addChild(this.editor);
|
|
5407
|
+
this.ui.setFocus(this.editor);
|
|
4989
5408
|
}
|
|
4990
5409
|
}
|
|
4991
5410
|
}
|
|
@@ -5031,7 +5450,7 @@ export class InteractiveMode {
|
|
|
5031
5450
|
this.chatContainer.addChild(new Text(theme.fg("dim", `Session name set: ${sessionName ?? name}`), 1, 0));
|
|
5032
5451
|
this.ui.requestRender();
|
|
5033
5452
|
}
|
|
5034
|
-
handleSessionCommand() {
|
|
5453
|
+
async handleSessionCommand() {
|
|
5035
5454
|
const stats = this.session.getSessionStats();
|
|
5036
5455
|
const sessionName = this.sessionManager.getSessionName();
|
|
5037
5456
|
const entries = this.sessionManager.getEntries();
|
|
@@ -5084,6 +5503,26 @@ export class InteractiveMode {
|
|
|
5084
5503
|
: `\n${theme.fg("dim", "Cache Re-billed:")} ${detail}`;
|
|
5085
5504
|
}
|
|
5086
5505
|
}
|
|
5506
|
+
// Role and latency: the two dimensions the durable ledger (roadmap Phase 8)
|
|
5507
|
+
// carries that session entries never did. Scoped to this session's rows only
|
|
5508
|
+
// -- a ledger that also served other sessions must never leak their cost in.
|
|
5509
|
+
const usagePerformanceSamples = (await this.session.modelRuntime.listUsagePerformanceSamples()).filter((sample) => sample.sessionId === stats.sessionId);
|
|
5510
|
+
if (usagePerformanceSamples.length > 0) {
|
|
5511
|
+
const avgTtftMs = usagePerformanceSamples.reduce((sum, sample) => sum + sample.ttftMs, 0) / usagePerformanceSamples.length;
|
|
5512
|
+
const avgGenerationMs = usagePerformanceSamples.reduce((sum, sample) => sum + sample.generationMs, 0) /
|
|
5513
|
+
usagePerformanceSamples.length;
|
|
5514
|
+
info += `\n\n${theme.bold("Latency")}\n`;
|
|
5515
|
+
info += `${theme.fg("dim", "Avg TTFT:")} ${Math.round(avgTtftMs)}ms\n`;
|
|
5516
|
+
info += `${theme.fg("dim", "Avg Generation:")} ${Math.round(avgGenerationMs)}ms`;
|
|
5517
|
+
const roleRows = aggregateUsagePerformance(usagePerformanceSamples, "role");
|
|
5518
|
+
if (roleRows.length > 0) {
|
|
5519
|
+
info += `\n\n${theme.bold("Roles")}`;
|
|
5520
|
+
for (const row of roleRows) {
|
|
5521
|
+
const requestLabel = row.sampleCount === 1 ? "1 request" : `${row.sampleCount} requests`;
|
|
5522
|
+
info += `\n ${theme.fg("dim", `${row.key}:`)} $${row.cost.toFixed(3)} ${theme.fg("dim", `(${requestLabel})`)}`;
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5087
5526
|
this.chatContainer.addChild(new Spacer(1));
|
|
5088
5527
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
5089
5528
|
this.ui.requestRender();
|
|
@@ -5364,7 +5803,7 @@ export class InteractiveMode {
|
|
|
5364
5803
|
// Ignore, will be emitted as an event
|
|
5365
5804
|
}
|
|
5366
5805
|
}
|
|
5367
|
-
stop() {
|
|
5806
|
+
stop(fullscreenExitOutput = this.settingsManager.getFullscreenExitOutput()) {
|
|
5368
5807
|
this.disposeActiveSelector();
|
|
5369
5808
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
5370
5809
|
this.ui.terminal.setProgress(false);
|
|
@@ -5378,7 +5817,7 @@ export class InteractiveMode {
|
|
|
5378
5817
|
this.unsubscribe();
|
|
5379
5818
|
}
|
|
5380
5819
|
if (this.isInitialized) {
|
|
5381
|
-
this.stopInteractiveTui();
|
|
5820
|
+
this.stopInteractiveTui(fullscreenExitOutput);
|
|
5382
5821
|
this.isInitialized = false;
|
|
5383
5822
|
}
|
|
5384
5823
|
this.unregisterSignalHandlers();
|