@greppleai/grip 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +1 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/embedded-assets.d.ts.map +1 -1
- package/dist/bun/embedded-assets.js.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.js.map +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/initial-message.js.map +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +38 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +289 -154
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-guidance.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -10
- 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 +19 -23
- 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.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +9 -2
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/compression-detection-ledger.d.ts.map +1 -1
- package/dist/core/compaction/compression-detection-ledger.js.map +1 -1
- package/dist/core/compaction/compression-detector.d.ts +1 -0
- package/dist/core/compaction/compression-detector.d.ts.map +1 -1
- package/dist/core/compaction/compression-detector.js +10 -21
- package/dist/core/compaction/compression-detector.js.map +1 -1
- package/dist/core/compaction/compression-economics.d.ts.map +1 -1
- package/dist/core/compaction/compression-economics.js.map +1 -1
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +40 -30
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +21 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +15 -16
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/grip-agent.d.ts.map +1 -1
- package/dist/core/grip-agent.js +7 -21
- package/dist/core/grip-agent.js.map +1 -1
- package/dist/core/grip-manifest.d.ts.map +1 -1
- package/dist/core/grip-manifest.js.map +1 -1
- package/dist/core/hooks/aggregate.d.ts.map +1 -1
- package/dist/core/hooks/aggregate.js.map +1 -1
- package/dist/core/hooks/config.d.ts.map +1 -1
- package/dist/core/hooks/config.js.map +1 -1
- package/dist/core/hooks/executor.d.ts.map +1 -1
- package/dist/core/hooks/executor.js.map +1 -1
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js.map +1 -1
- package/dist/core/hooks/matcher.d.ts.map +1 -1
- package/dist/core/hooks/matcher.js.map +1 -1
- package/dist/core/hooks/trust-store.d.ts.map +1 -1
- package/dist/core/hooks/trust-store.js +0 -3
- package/dist/core/hooks/trust-store.js.map +1 -1
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/instruction-resource-loader.d.ts +1 -0
- package/dist/core/instruction-resource-loader.d.ts.map +1 -1
- package/dist/core/instruction-resource-loader.js +2 -4
- package/dist/core/instruction-resource-loader.js.map +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +0 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/lsp/abort.d.ts.map +1 -1
- package/dist/core/lsp/abort.js.map +1 -1
- package/dist/core/lsp/client.d.ts.map +1 -1
- package/dist/core/lsp/client.js +8 -22
- package/dist/core/lsp/client.js.map +1 -1
- package/dist/core/lsp/config-loader.d.ts.map +1 -1
- package/dist/core/lsp/config-loader.js.map +1 -1
- package/dist/core/lsp/config.d.ts.map +1 -1
- package/dist/core/lsp/config.js.map +1 -1
- package/dist/core/lsp/diagnostics.d.ts.map +1 -1
- package/dist/core/lsp/diagnostics.js.map +1 -1
- package/dist/core/lsp/file-sync.d.ts.map +1 -1
- package/dist/core/lsp/file-sync.js +7 -9
- package/dist/core/lsp/file-sync.js.map +1 -1
- package/dist/core/lsp/integration.d.ts.map +1 -1
- package/dist/core/lsp/integration.js.map +1 -1
- package/dist/core/lsp/language-map.d.ts.map +1 -1
- package/dist/core/lsp/language-map.js +2 -7
- package/dist/core/lsp/language-map.js.map +1 -1
- package/dist/core/lsp/manager.d.ts.map +1 -1
- package/dist/core/lsp/manager.js +18 -29
- package/dist/core/lsp/manager.js.map +1 -1
- package/dist/core/lsp/navigation.d.ts.map +1 -1
- package/dist/core/lsp/navigation.js.map +1 -1
- package/dist/core/lsp/portable-path.d.ts.map +1 -1
- package/dist/core/lsp/portable-path.js.map +1 -1
- package/dist/core/lsp/refactor.d.ts.map +1 -1
- package/dist/core/lsp/refactor.js.map +1 -1
- package/dist/core/lsp/transport.d.ts.map +1 -1
- package/dist/core/lsp/transport.js.map +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +30 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +5 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +0 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/contract.js +4 -2
- package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-client.js +1 -5
- package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +5 -10
- package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +2 -9
- package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -1
- package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/session.js +27 -65
- package/dist/core/remote-workspace-protocol/session.js.map +1 -1
- package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -1
- package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +0 -48
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js.map +1 -1
- package/dist/core/sandbox/command.d.ts.map +1 -1
- package/dist/core/sandbox/command.js.map +1 -1
- package/dist/core/sandbox/config.d.ts.map +1 -1
- package/dist/core/sandbox/config.js.map +1 -1
- package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -1
- package/dist/core/sandbox/lima-guest-binary.js.map +1 -1
- package/dist/core/sandbox/lima.d.ts +2 -0
- package/dist/core/sandbox/lima.d.ts.map +1 -1
- package/dist/core/sandbox/lima.js +3 -9
- package/dist/core/sandbox/lima.js.map +1 -1
- package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -1
- package/dist/core/sandbox/shared-lima-roots.js.map +1 -1
- package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -1
- package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -1
- package/dist/core/session/constants.d.ts.map +1 -1
- package/dist/core/session/context-metadata.d.ts.map +1 -1
- package/dist/core/session/context-metadata.js.map +1 -1
- package/dist/core/session/context.d.ts.map +1 -1
- package/dist/core/session/context.js.map +1 -1
- package/dist/core/session/ids.d.ts.map +1 -1
- package/dist/core/session/ids.js.map +1 -1
- package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
- package/dist/core/session/in-memory-session-manager.js +0 -1
- package/dist/core/session/in-memory-session-manager.js.map +1 -1
- package/dist/core/session/in-memory-session.d.ts.map +1 -1
- package/dist/core/session/in-memory-session.js.map +1 -1
- package/dist/core/session/jsonl-errors.d.ts.map +1 -1
- package/dist/core/session/jsonl-errors.js +0 -11
- package/dist/core/session/jsonl-errors.js.map +1 -1
- package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
- package/dist/core/session/jsonl-helpers.js.map +1 -1
- package/dist/core/session/local-session-manager.d.ts.map +1 -1
- package/dist/core/session/local-session-manager.js +4 -6
- package/dist/core/session/local-session-manager.js.map +1 -1
- package/dist/core/session/local-session.d.ts.map +1 -1
- package/dist/core/session/local-session.js.map +1 -1
- package/dist/core/session/migrations.d.ts.map +1 -1
- package/dist/core/session/migrations.js.map +1 -1
- package/dist/core/session/remote-session-client.d.ts.map +1 -1
- package/dist/core/session/remote-session-client.js +0 -6
- package/dist/core/session/remote-session-client.js.map +1 -1
- package/dist/core/session/remote-session-manager.d.ts.map +1 -1
- package/dist/core/session/remote-session-manager.js +0 -3
- package/dist/core/session/remote-session-manager.js.map +1 -1
- package/dist/core/session/remote-session.d.ts.map +1 -1
- package/dist/core/session/remote-session.js +0 -1
- package/dist/core/session/remote-session.js.map +1 -1
- package/dist/core/session/session-manager.d.ts.map +1 -1
- package/dist/core/session/session.d.ts.map +1 -1
- package/dist/core/session/session.js +1 -5
- package/dist/core/session/session.js.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/in-memory-session-store.js +7 -6
- package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/jsonl-session-store.js +6 -14
- package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
- package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
- package/dist/core/session/stores/remote-session-store.js +3 -8
- package/dist/core/session/stores/remote-session-store.js.map +1 -1
- package/dist/core/session/stores/session-store.d.ts.map +1 -1
- package/dist/core/session/types.d.ts.map +1 -1
- package/dist/core/session/usage-ledger.d.ts.map +1 -1
- package/dist/core/session/usage-ledger.js.map +1 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-cwd.js +0 -1
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +9 -17
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +3 -2
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/source-info.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/telemetry.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -28
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/compress-context.d.ts.map +1 -1
- package/dist/core/tools/compress-context.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hash-store.d.ts.map +1 -1
- package/dist/core/tools/hash-store.js.map +1 -1
- package/dist/core/tools/hashline/apply.d.ts.map +1 -1
- package/dist/core/tools/hashline/apply.js.map +1 -1
- package/dist/core/tools/hashline/hash.d.ts.map +1 -1
- package/dist/core/tools/hashline/hash.js.map +1 -1
- package/dist/core/tools/hashline/parse.d.ts.map +1 -1
- package/dist/core/tools/hashline/parse.js.map +1 -1
- package/dist/core/tools/hashline/resolve.d.ts.map +1 -1
- package/dist/core/tools/hashline/resolve.js.map +1 -1
- package/dist/core/tools/hashline-utils.d.ts.map +1 -1
- package/dist/core/tools/hashline-utils.js.map +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/operations.d.ts +11 -0
- package/dist/core/tools/operations.d.ts.map +1 -1
- package/dist/core/tools/operations.js +54 -28
- package/dist/core/tools/operations.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +12 -18
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/path-utils.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/replace-diff.d.ts.map +1 -1
- package/dist/core/tools/replace-diff.js.map +1 -1
- package/dist/core/tools/replace-normalize.d.ts.map +1 -1
- package/dist/core/tools/replace-normalize.js.map +1 -1
- package/dist/core/tools/replace-render.d.ts +1 -1
- package/dist/core/tools/replace-render.d.ts.map +1 -1
- package/dist/core/tools/replace-render.js.map +1 -1
- package/dist/core/tools/runtime.d.ts.map +1 -1
- package/dist/core/tools/runtime.js.map +1 -1
- package/dist/core/tools/session-history.d.ts.map +1 -1
- package/dist/core/tools/session-history.js.map +1 -1
- package/dist/core/tools/subagent-agents.d.ts.map +1 -1
- package/dist/core/tools/subagent-agents.js.map +1 -1
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/workspace-tool-host.d.ts +1 -0
- package/dist/core/tools/workspace-tool-host.d.ts.map +1 -1
- package/dist/core/tools/workspace-tool-host.js +36 -22
- package/dist/core/tools/workspace-tool-host.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +0 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/workspace-identity.d.ts.map +1 -1
- package/dist/daemon/activity-budget.d.ts.map +1 -1
- package/dist/daemon/activity-budget.js +2 -3
- package/dist/daemon/activity-budget.js.map +1 -1
- package/dist/daemon/command.d.ts.map +1 -1
- package/dist/daemon/command.js.map +1 -1
- package/dist/daemon/config.d.ts +2 -0
- package/dist/daemon/config.d.ts.map +1 -1
- package/dist/daemon/config.js +4 -0
- package/dist/daemon/config.js.map +1 -1
- package/dist/daemon/help.d.ts.map +1 -1
- package/dist/daemon/help.js +4 -3
- package/dist/daemon/help.js.map +1 -1
- package/dist/daemon/lsp-config.d.ts.map +1 -1
- package/dist/daemon/lsp-config.js.map +1 -1
- package/dist/daemon/outbound-budget.d.ts.map +1 -1
- package/dist/daemon/outbound-budget.js +2 -4
- package/dist/daemon/outbound-budget.js.map +1 -1
- package/dist/daemon/security.d.ts.map +1 -1
- package/dist/daemon/security.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/shared-connection.d.ts.map +1 -1
- package/dist/daemon/shared-connection.js +10 -15
- package/dist/daemon/shared-connection.js.map +1 -1
- package/dist/daemon/shared-revision.d.ts.map +1 -1
- package/dist/daemon/shared-revision.js +2 -1
- package/dist/daemon/shared-revision.js.map +1 -1
- package/dist/daemon/shared-roots.d.ts.map +1 -1
- package/dist/daemon/shared-roots.js +0 -1
- package/dist/daemon/shared-roots.js.map +1 -1
- package/dist/daemon/workspace-runtime.d.ts +2 -0
- package/dist/daemon/workspace-runtime.d.ts.map +1 -1
- package/dist/daemon/workspace-runtime.js +43 -15
- package/dist/daemon/workspace-runtime.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -3
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -10
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +4 -9
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +0 -3
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -3
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +6 -16
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +0 -5
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +1 -8
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -6
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +0 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -7
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +2 -8
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +1 -9
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -4
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/hook-execution.js +2 -5
- package/dist/modes/interactive/components/hook-execution.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -9
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/message-card.d.ts.map +1 -1
- package/dist/modes/interactive/components/message-card.js +0 -1
- package/dist/modes/interactive/components/message-card.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +13 -28
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +3 -12
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +9 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +33 -58
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +0 -4
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +0 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +0 -2
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +0 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -24
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +18 -34
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +3 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +0 -4
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +162 -136
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +0 -7
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/dist/modes/rpc/jsonl.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +10 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +33 -2
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/binary-self-update.d.ts +25 -0
- package/dist/utils/binary-self-update.d.ts.map +1 -0
- package/dist/utils/binary-self-update.js +159 -0
- package/dist/utils/binary-self-update.js.map +1 -0
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/deprecation.d.ts.map +1 -1
- package/dist/utils/deprecation.js.map +1 -1
- package/dist/utils/directory-completions.d.ts +8 -0
- package/dist/utils/directory-completions.d.ts.map +1 -1
- package/dist/utils/directory-completions.js +42 -1
- package/dist/utils/directory-completions.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/exif-orientation.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/grip-user-agent.d.ts.map +1 -1
- package/dist/utils/grip-user-agent.js.map +1 -1
- package/dist/utils/html.d.ts.map +1 -1
- package/dist/utils/html.js.map +1 -1
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts.map +1 -1
- package/dist/utils/image-process.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/image-resize-worker.d.ts.map +1 -1
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/open-browser.d.ts.map +1 -1
- package/dist/utils/open-browser.js.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/photon.js +10 -5
- package/dist/utils/photon.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +1 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- 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.map +1 -1
- package/docs/extensions.md +31 -1
- package/docs/sandbox.md +6 -0
- package/docs/sessions.md +1 -1
- package/docs/skills.md +4 -4
- package/docs/usage.md +2 -1
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +602 -834
- package/package.json +20 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tree-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@greppleai/grip-agent-core\";\nimport type { AssistantMessage } from \"@greppleai/grip-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\ttype Focusable,\n\tgetKeybindings,\n\tInput,\n\tSpacer,\n\tText,\n\tTruncatedText,\n\ttruncateToWidth,\n} from \"@greppleai/grip-tui\";\nimport type { SessionTreeNode } from \"../../../core/session/types.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n/** Gutter info: position (displayIndent where connector was) and whether to show │ */\ninterface GutterInfo {\n\tposition: number; // displayIndent level where the connector was shown\n\tshow: boolean; // true = show │, false = show spaces\n}\n\n/** Flattened tree node for navigation */\ninterface FlatNode {\n\tnode: SessionTreeNode;\n\t/** Indentation level (each level = 3 chars) */\n\tindent: number;\n\t/** Whether to show connector (├─ or └─) - true if parent has multiple children */\n\tshowConnector: boolean;\n\t/** If showConnector, true = last sibling (└─), false = not last (├─) */\n\tisLast: boolean;\n\t/** Gutter info for each ancestor branch point */\n\tgutters: GutterInfo[];\n\t/** True if this node is a root under a virtual branching root (multiple roots) */\n\tisVirtualRootChild: boolean;\n}\n\ninterface TreeTraversalItem {\n\tnode: SessionTreeNode;\n\tindent: number;\n\tjustBranched: boolean;\n\tshowConnector: boolean;\n\tisLast: boolean;\n\tgutters: GutterInfo[];\n\tisVirtualRootChild: boolean;\n}\n\ninterface VisibleTreeStructure {\n\tparentMap: Map<string, string | null>;\n\tchildrenMap: Map<string | null, string[]>;\n\tnodesById: Map<string, FlatNode>;\n\trootIds: string[];\n}\n\ninterface VisibleChildLayout {\n\tindent: number;\n\tgutters: GutterInfo[];\n\tbranched: boolean;\n}\n// grip-ignore noNearIdenticalDataStructures: Viewport slice indices and terminal selection cell columns evolve independently.\ninterface VisibleNodeRange {\n\tstart: number;\n\tend: number;\n}\n\ntype BranchSegmentTraversalDirection = \"up\" | \"down\";\n\n/** Filter mode for tree display */\nexport type FilterMode = \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\";\n\nconst FILTER_MODES: readonly FilterMode[] = [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"];\n\nfunction hasTreeSearchControlCharacters(value: string): boolean {\n\tfor (const character of value) {\n\t\tconst code = character.charCodeAt(0);\n\t\tif (code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f)) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Tree list component with selection and ASCII art visualization\n */\n/** Tool call info for lookup */\ninterface ToolCallInfo {\n\tname: string;\n\targuments: Record<string, unknown>;\n}\n\ntype TreeFileMutationToolName = \"write\" | \"edit\";\ntype TreeSearchToolName = \"grep\" | \"find\";\n\nfunction shortenTreeToolPath(path: string): string {\n\tconst home = process.env.HOME || process.env.USERPROFILE || \"\";\n\treturn home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;\n}\n\nfunction formatTreeReadToolCall(args: Record<string, unknown>): string {\n\tconst path = shortenTreeToolPath(String(args.path || args.file_path || \"\"));\n\tconst offset = args.offset as number | undefined;\n\tconst limit = args.limit as number | undefined;\n\tlet display = path;\n\tif (offset !== undefined || limit !== undefined) {\n\t\tconst start = offset ?? 1;\n\t\tconst end = limit !== undefined ? start + limit - 1 : \"\";\n\t\tdisplay += `:${start}${end ? `-${end}` : \"\"}`;\n\t}\n\treturn `[read: ${display}]`;\n}\n\nfunction formatTreeFileMutationToolCall(name: TreeFileMutationToolName, args: Record<string, unknown>): string {\n\treturn `[${name}: ${shortenTreeToolPath(String(args.path || args.file_path || \"\"))}]`;\n}\n\nfunction formatTreeBashToolCall(args: Record<string, unknown>): string {\n\tconst rawCommand = String(args.command || \"\");\n\tconst command = rawCommand\n\t\t.replace(/[\\n\\t]/g, \" \")\n\t\t.trim()\n\t\t.slice(0, 50);\n\treturn `[bash: ${command}${rawCommand.length > 50 ? \"...\" : \"\"}]`;\n}\n\nfunction formatTreeSearchToolCall(name: TreeSearchToolName, args: Record<string, unknown>): string {\n\tconst pattern = String(args.pattern || \"\");\n\tconst path = shortenTreeToolPath(String(args.path || \".\"));\n\treturn name === \"grep\" ? `[grep: /${pattern}/ in ${path}]` : `[find: ${pattern} in ${path}]`;\n}\n\nfunction formatCustomTreeToolCall(name: string, args: Record<string, unknown>): string {\n\tconst argsString = JSON.stringify(args).slice(0, 40);\n\treturn `[${name}: ${argsString}${JSON.stringify(args).length > 40 ? \"...\" : \"\"}]`;\n}\n\nclass TreeList implements Component {\n\tprivate flatNodes: FlatNode[] = [];\n\tprivate filteredNodes: FlatNode[] = [];\n\tprivate selectedIndex = 0;\n\tprivate currentLeafId: string | null;\n\tprivate maxVisibleLines: number;\n\tprivate filterMode: FilterMode = \"default\";\n\tprivate searchQuery = \"\";\n\tprivate toolCallMap: Map<string, ToolCallInfo> = new Map();\n\tprivate multipleRoots = false;\n\tprivate showLabelTimestamps = false;\n\tprivate activePathIds: Set<string> = new Set();\n\tprivate visibleParentMap: Map<string, string | null> = new Map();\n\tprivate visibleChildrenMap: Map<string | null, string[]> = new Map();\n\tprivate lastSelectedId: string | null = null;\n\tprivate foldedNodes: Set<string> = new Set();\n\n\tpublic onSelect?: (entryId: string) => void;\n\tpublic onCancel?: () => void;\n\tpublic onCopy?: (text: string | undefined) => void;\n\tpublic onLabelEdit?: (entryId: string, currentLabel: string | undefined) => void;\n\n\tconstructor(\n\t\ttree: SessionTreeNode[],\n\t\tcurrentLeafId: string | null,\n\t\tmaxVisibleLines: number,\n\t\tinitialSelectedId?: string,\n\t\tinitialFilterMode?: FilterMode,\n\t) {\n\t\tthis.currentLeafId = currentLeafId;\n\t\tthis.maxVisibleLines = maxVisibleLines;\n\t\tthis.filterMode = initialFilterMode ?? \"default\";\n\t\tthis.multipleRoots = tree.length > 1;\n\t\tthis.flatNodes = this.flattenTree(tree);\n\t\tthis.buildActivePath();\n\t\tthis.applyFilter();\n\n\t\t// Start with initialSelectedId if provided, otherwise current leaf\n\t\tconst targetId = initialSelectedId ?? currentLeafId;\n\t\tthis.selectedIndex = this.findNearestVisibleIndex(targetId);\n\t\tthis.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? null;\n\t}\n\n\t/**\n\t * Find the index of the nearest visible entry, walking up the parent chain if needed.\n\t * Returns the index in filteredNodes, or the last index as fallback.\n\t */\n\tprivate findNearestVisibleIndex(entryId: string | null): number {\n\t\tif (this.filteredNodes.length === 0) return 0;\n\n\t\t// Build a map for parent lookup\n\t\tconst entryMap = new Map<string, FlatNode>();\n\t\tfor (const flatNode of this.flatNodes) {\n\t\t\tentryMap.set(flatNode.node.entry.id, flatNode);\n\t\t}\n\n\t\t// Build a map of visible entry IDs to their indices in filteredNodes\n\t\tconst visibleIdToIndex = new Map<string, number>(this.filteredNodes.map((node, i) => [node.node.entry.id, i]));\n\n\t\t// Walk from entryId up to root, looking for a visible entry\n\t\tlet currentId = entryId;\n\t\twhile (currentId !== null) {\n\t\t\tconst index = visibleIdToIndex.get(currentId);\n\t\t\tif (index !== undefined) return index;\n\t\t\tconst node = entryMap.get(currentId);\n\t\t\tif (!node) break;\n\t\t\tcurrentId = node.node.entry.parentId ?? null;\n\t\t}\n\n\t\t// Fallback: last visible entry\n\t\treturn this.filteredNodes.length - 1;\n\t}\n\n\t/** Build the set of entry IDs on the path from root to current leaf */\n\tprivate buildActivePath(): void {\n\t\tthis.activePathIds.clear();\n\t\tif (!this.currentLeafId) return;\n\n\t\t// Build a map of id -> entry for parent lookup\n\t\tconst entryMap = new Map<string, FlatNode>();\n\t\tfor (const flatNode of this.flatNodes) {\n\t\t\tentryMap.set(flatNode.node.entry.id, flatNode);\n\t\t}\n\n\t\t// Walk from leaf to root\n\t\tlet currentId: string | null = this.currentLeafId;\n\t\twhile (currentId) {\n\t\t\tthis.activePathIds.add(currentId);\n\t\t\tconst node = entryMap.get(currentId);\n\t\t\tif (!node) break;\n\t\t\tcurrentId = node.node.entry.parentId ?? null;\n\t\t}\n\t}\n\n\tprivate findActiveSubtrees(roots: SessionTreeNode[]): Map<SessionTreeNode, boolean> {\n\t\tconst allNodes: SessionTreeNode[] = [];\n\t\tconst preOrderStack = [...roots];\n\t\twhile (preOrderStack.length > 0) {\n\t\t\tconst node = preOrderStack.pop()!;\n\t\t\tallNodes.push(node);\n\t\t\tfor (let i = node.children.length - 1; i >= 0; i--) preOrderStack.push(node.children[i]);\n\t\t}\n\n\t\tconst containsActive = new Map<SessionTreeNode, boolean>();\n\t\tfor (let i = allNodes.length - 1; i >= 0; i--) {\n\t\t\tconst node = allNodes[i];\n\t\t\tlet hasActiveEntry = this.currentLeafId !== null && node.entry.id === this.currentLeafId;\n\t\t\tfor (const child of node.children) {\n\t\t\t\tif (containsActive.get(child)) hasActiveEntry = true;\n\t\t\t}\n\t\t\tcontainsActive.set(node, hasActiveEntry);\n\t\t}\n\t\treturn containsActive;\n\t}\n\n\tprivate createTreeTraversalStack(\n\t\troots: SessionTreeNode[],\n\t\tcontainsActive: Map<SessionTreeNode, boolean>,\n\t): TreeTraversalItem[] {\n\t\tconst orderedRoots = [...roots].sort((a, b) => Number(containsActive.get(b)) - Number(containsActive.get(a)));\n\t\tconst stack: TreeTraversalItem[] = [];\n\t\tfor (let i = orderedRoots.length - 1; i >= 0; i--) {\n\t\t\tstack.push({\n\t\t\t\tnode: orderedRoots[i],\n\t\t\t\tindent: this.multipleRoots ? 1 : 0,\n\t\t\t\tjustBranched: this.multipleRoots,\n\t\t\t\tshowConnector: this.multipleRoots,\n\t\t\t\tisLast: i === orderedRoots.length - 1,\n\t\t\t\tgutters: [],\n\t\t\t\tisVirtualRootChild: this.multipleRoots,\n\t\t\t});\n\t\t}\n\t\treturn stack;\n\t}\n\n\tprivate recordAssistantToolCalls(node: SessionTreeNode): void {\n\t\tconst entry = node.entry;\n\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") return;\n\t\tconst content = (entry.message as { content?: unknown }).content;\n\t\tif (!Array.isArray(content)) return;\n\t\tfor (const block of content) {\n\t\t\tif (typeof block !== \"object\" || block === null || !(\"type\" in block) || block.type !== \"toolCall\") continue;\n\t\t\tconst toolCall = block as { id: string; name: string; arguments: Record<string, unknown> };\n\t\t\tthis.toolCallMap.set(toolCall.id, { name: toolCall.name, arguments: toolCall.arguments });\n\t\t}\n\t}\n\n\tprivate prioritizeActiveChildren(\n\t\tchildren: SessionTreeNode[],\n\t\tcontainsActive: Map<SessionTreeNode, boolean>,\n\t): SessionTreeNode[] {\n\t\tconst prioritized: SessionTreeNode[] = [];\n\t\tconst rest: SessionTreeNode[] = [];\n\t\tfor (const child of children) {\n\t\t\tif (containsActive.get(child)) prioritized.push(child);\n\t\t\telse rest.push(child);\n\t\t}\n\t\treturn [...prioritized, ...rest];\n\t}\n\n\tprivate getTraversalChildIndent(item: TreeTraversalItem, multipleChildren: boolean): number {\n\t\tif (multipleChildren || (item.justBranched && item.indent > 0)) return item.indent + 1;\n\t\treturn item.indent;\n\t}\n\n\tprivate getTraversalChildGutters(item: TreeTraversalItem): GutterInfo[] {\n\t\tif (!item.showConnector || item.isVirtualRootChild) return item.gutters;\n\t\tconst currentDisplayIndent = this.multipleRoots ? Math.max(0, item.indent - 1) : item.indent;\n\t\treturn [...item.gutters, { position: Math.max(0, currentDisplayIndent - 1), show: !item.isLast }];\n\t}\n\n\tprivate pushTraversalChildren(\n\t\tstack: TreeTraversalItem[],\n\t\titem: TreeTraversalItem,\n\t\tcontainsActive: Map<SessionTreeNode, boolean>,\n\t): void {\n\t\tconst orderedChildren = this.prioritizeActiveChildren(item.node.children, containsActive);\n\t\tconst multipleChildren = orderedChildren.length > 1;\n\t\tconst childIndent = this.getTraversalChildIndent(item, multipleChildren);\n\t\tconst childGutters = this.getTraversalChildGutters(item);\n\t\tfor (let i = orderedChildren.length - 1; i >= 0; i--) {\n\t\t\tstack.push({\n\t\t\t\tnode: orderedChildren[i],\n\t\t\t\tindent: childIndent,\n\t\t\t\tjustBranched: multipleChildren,\n\t\t\t\tshowConnector: multipleChildren,\n\t\t\t\tisLast: i === orderedChildren.length - 1,\n\t\t\t\tgutters: childGutters,\n\t\t\t\tisVirtualRootChild: false,\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate flattenTree(roots: SessionTreeNode[]): FlatNode[] {\n\t\tthis.toolCallMap.clear();\n\t\tconst result: FlatNode[] = [];\n\t\tconst containsActive = this.findActiveSubtrees(roots);\n\t\tconst stack = this.createTreeTraversalStack(roots, containsActive);\n\n\t\twhile (stack.length > 0) {\n\t\t\tconst item = stack.pop()!;\n\t\t\tthis.recordAssistantToolCalls(item.node);\n\t\t\tresult.push({\n\t\t\t\tnode: item.node,\n\t\t\t\tindent: item.indent,\n\t\t\t\tshowConnector: item.showConnector,\n\t\t\t\tisLast: item.isLast,\n\t\t\t\tgutters: item.gutters,\n\t\t\t\tisVirtualRootChild: item.isVirtualRootChild,\n\t\t\t});\n\t\t\tthis.pushTraversalChildren(stack, item, containsActive);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate shouldDisplayAssistantNode(flatNode: FlatNode): boolean {\n\t\tconst entry = flatNode.node.entry;\n\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\" || entry.id === this.currentLeafId) {\n\t\t\treturn true;\n\t\t}\n\t\tconst message = entry.message as { stopReason?: string; content?: unknown };\n\t\tconst hasText = this.hasTextContent(message.content);\n\t\tconst isErrorOrAborted =\n\t\t\tmessage.stopReason !== undefined && message.stopReason !== \"stop\" && message.stopReason !== \"toolUse\";\n\t\treturn hasText || isErrorOrAborted;\n\t}\n\n\tprivate passesNodeFilterMode(flatNode: FlatNode): boolean {\n\t\tconst entry = flatNode.node.entry;\n\t\tconst isSettingsEntry =\n\t\t\tentry.type === \"label\" ||\n\t\t\tentry.type === \"custom\" ||\n\t\t\tentry.type === \"model_change\" ||\n\t\t\tentry.type === \"thinking_level_change\" ||\n\t\t\tentry.type === \"session_info\";\n\t\tswitch (this.filterMode) {\n\t\t\tcase \"user-only\":\n\t\t\t\treturn entry.type === \"message\" && entry.message.role === \"user\";\n\t\t\tcase \"no-tools\":\n\t\t\t\treturn !isSettingsEntry && !(entry.type === \"message\" && entry.message.role === \"toolResult\");\n\t\t\tcase \"labeled-only\":\n\t\t\t\treturn flatNode.node.label !== undefined;\n\t\t\tcase \"all\":\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\treturn !isSettingsEntry;\n\t\t}\n\t}\n\n\tprivate matchesNodeSearch(flatNode: FlatNode, searchTokens: string[]): boolean {\n\t\tif (searchTokens.length === 0) return true;\n\t\tconst nodeText: string = this.getSearchableText(flatNode.node).toLowerCase();\n\t\treturn searchTokens.every((token) => nodeText.includes(token));\n\t}\n\n\tprivate shouldIncludeFilteredNode(flatNode: FlatNode, searchTokens: string[]): boolean {\n\t\tif (!this.shouldDisplayAssistantNode(flatNode)) return false;\n\t\tif (!this.passesNodeFilterMode(flatNode)) return false;\n\t\treturn this.matchesNodeSearch(flatNode, searchTokens);\n\t}\n\tprivate applyFilter(): void {\n\t\t// Update lastSelectedId only when we have a valid selection (non-empty list)\n\t\t// This preserves the selection when switching through empty filter results\n\t\tif (this.filteredNodes.length > 0) {\n\t\t\tthis.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? this.lastSelectedId;\n\t\t}\n\n\t\tconst searchTokens = this.searchQuery.toLowerCase().split(/\\s+/).filter(Boolean);\n\n\t\tthis.filteredNodes = this.flatNodes.filter((flatNode) => this.shouldIncludeFilteredNode(flatNode, searchTokens));\n\n\t\t// Filter out descendants of folded nodes.\n\t\tif (this.foldedNodes.size > 0) {\n\t\t\tconst skipSet = new Set<string>();\n\t\t\tfor (const flatNode of this.flatNodes) {\n\t\t\t\tconst { id, parentId } = flatNode.node.entry;\n\t\t\t\tif (parentId != null && (this.foldedNodes.has(parentId) || skipSet.has(parentId))) {\n\t\t\t\t\tskipSet.add(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.filteredNodes = this.filteredNodes.filter((flatNode) => !skipSet.has(flatNode.node.entry.id));\n\t\t}\n\n\t\t// Recalculate visual structure (indent, connectors, gutters) based on visible tree\n\t\tthis.recalculateVisualStructure();\n\n\t\t// Try to preserve cursor on the same node, or find nearest visible ancestor\n\t\tif (this.lastSelectedId) {\n\t\t\tthis.selectedIndex = this.findNearestVisibleIndex(this.lastSelectedId);\n\t\t} else if (this.selectedIndex >= this.filteredNodes.length) {\n\t\t\t// Clamp index if out of bounds\n\t\t\tthis.selectedIndex = Math.max(0, this.filteredNodes.length - 1);\n\t\t}\n\n\t\t// Update lastSelectedId to the actual selection (may have changed due to parent walk)\n\t\tif (this.filteredNodes.length > 0) {\n\t\t\tthis.lastSelectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id ?? this.lastSelectedId;\n\t\t}\n\t}\n\n\tprivate findNearestVisibleAncestor(\n\t\tnodeId: string,\n\t\tvisibleIds: ReadonlySet<string>,\n\t\tnodesById: ReadonlyMap<string, FlatNode>,\n\t): string | null {\n\t\tlet currentId = nodesById.get(nodeId)?.node.entry.parentId ?? null;\n\t\twhile (currentId !== null) {\n\t\t\tif (visibleIds.has(currentId)) return currentId;\n\t\t\tcurrentId = nodesById.get(currentId)?.node.entry.parentId ?? null;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate buildVisibleTreeStructure(): VisibleTreeStructure {\n\t\tconst visibleIds = new Set(this.filteredNodes.map((flatNode) => flatNode.node.entry.id));\n\t\tconst allNodesById = new Map<string, FlatNode>();\n\t\tfor (const flatNode of this.flatNodes) allNodesById.set(flatNode.node.entry.id, flatNode);\n\t\tconst parentMap = new Map<string, string | null>();\n\t\tconst childrenMap = new Map<string | null, string[]>([[null, []]]);\n\t\tconst nodesById = new Map<string, FlatNode>();\n\t\tfor (const flatNode of this.filteredNodes) {\n\t\t\tconst nodeId = flatNode.node.entry.id;\n\t\t\tconst ancestorId = this.findNearestVisibleAncestor(nodeId, visibleIds, allNodesById);\n\t\t\tparentMap.set(nodeId, ancestorId);\n\t\t\tnodesById.set(nodeId, flatNode);\n\t\t\tlet children = childrenMap.get(ancestorId);\n\t\t\tif (!children) {\n\t\t\t\tchildren = [];\n\t\t\t\tchildrenMap.set(ancestorId, children);\n\t\t\t}\n\t\t\tchildren.push(nodeId);\n\t\t}\n\t\treturn { parentMap, childrenMap, nodesById, rootIds: childrenMap.get(null) ?? [] };\n\t}\n\n\tprivate resolveVisibleChildLayout(item: TreeTraversalItem, multipleChildren: boolean): VisibleChildLayout {\n\t\tlet indent = item.indent;\n\t\tif (multipleChildren || (item.justBranched && item.indent > 0)) indent++;\n\t\tconst connectorDisplayed = item.showConnector && !item.isVirtualRootChild;\n\t\tconst currentDisplayIndent = this.multipleRoots ? Math.max(0, item.indent - 1) : item.indent;\n\t\tconst connectorPosition = Math.max(0, currentDisplayIndent - 1);\n\t\tconst gutters = connectorDisplayed\n\t\t\t? [...item.gutters, { position: connectorPosition, show: !item.isLast }]\n\t\t\t: item.gutters;\n\t\treturn { indent, gutters, branched: multipleChildren };\n\t}\n\n\tprivate layoutVisibleTree(structure: VisibleTreeStructure): void {\n\t\tconst stack: TreeTraversalItem[] = [];\n\t\tfor (let index = structure.rootIds.length - 1; index >= 0; index--) {\n\t\t\tconst flatNode = structure.nodesById.get(structure.rootIds[index]);\n\t\t\tif (!flatNode) continue;\n\t\t\tstack.push({\n\t\t\t\tnode: flatNode.node,\n\t\t\t\tindent: this.multipleRoots ? 1 : 0,\n\t\t\t\tjustBranched: this.multipleRoots,\n\t\t\t\tshowConnector: this.multipleRoots,\n\t\t\t\tisLast: index === structure.rootIds.length - 1,\n\t\t\t\tgutters: [],\n\t\t\t\tisVirtualRootChild: this.multipleRoots,\n\t\t\t});\n\t\t}\n\t\twhile (stack.length > 0) {\n\t\t\tconst item = stack.pop()!;\n\t\t\tconst nodeId = item.node.entry.id;\n\t\t\tconst flatNode = structure.nodesById.get(nodeId);\n\t\t\tif (!flatNode) continue;\n\t\t\tflatNode.indent = item.indent;\n\t\t\tflatNode.showConnector = item.showConnector;\n\t\t\tflatNode.isLast = item.isLast;\n\t\t\tflatNode.gutters = item.gutters;\n\t\t\tflatNode.isVirtualRootChild = item.isVirtualRootChild;\n\t\t\tconst children = structure.childrenMap.get(nodeId) ?? [];\n\t\t\tconst childLayout = this.resolveVisibleChildLayout(item, children.length > 1);\n\t\t\tfor (let index = children.length - 1; index >= 0; index--) {\n\t\t\t\tconst child = structure.nodesById.get(children[index]);\n\t\t\t\tif (!child) continue;\n\t\t\t\tstack.push({\n\t\t\t\t\tnode: child.node,\n\t\t\t\t\tindent: childLayout.indent,\n\t\t\t\t\tjustBranched: childLayout.branched,\n\t\t\t\t\tshowConnector: childLayout.branched,\n\t\t\t\t\tisLast: index === children.length - 1,\n\t\t\t\t\tgutters: childLayout.gutters,\n\t\t\t\t\tisVirtualRootChild: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recompute indentation/connectors for the filtered view.\n\t * Filtering can hide intermediate entries, so descendants attach to the nearest visible ancestor.\n\t */\n\tprivate recalculateVisualStructure(): void {\n\t\tif (this.filteredNodes.length === 0) return;\n\t\tconst structure = this.buildVisibleTreeStructure();\n\t\tthis.multipleRoots = structure.rootIds.length > 1;\n\t\tthis.layoutVisibleTree(structure);\n\t\tthis.visibleParentMap = structure.parentMap;\n\t\tthis.visibleChildrenMap = structure.childrenMap;\n\t}\n\n\t/** Get searchable text content from a node */\n\tprivate getSearchableText(node: SessionTreeNode): string {\n\t\tconst entry = node.entry;\n\t\tconst parts: string[] = [];\n\n\t\tif (node.label) {\n\t\t\tparts.push(node.label);\n\t\t}\n\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\": {\n\t\t\t\tconst msg = entry.message;\n\t\t\t\tparts.push(msg.role);\n\t\t\t\tif (\"content\" in msg && msg.content) {\n\t\t\t\t\tparts.push(this.extractContent(msg.content));\n\t\t\t\t}\n\t\t\t\tif (msg.role === \"bashExecution\") {\n\t\t\t\t\tconst bashMsg = msg as { command?: string };\n\t\t\t\t\tif (bashMsg.command) parts.push(bashMsg.command);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"custom_message\": {\n\t\t\t\tparts.push(entry.customType);\n\t\t\t\tif (typeof entry.content === \"string\") {\n\t\t\t\t\tparts.push(entry.content);\n\t\t\t\t} else {\n\t\t\t\t\tparts.push(this.extractContent(entry.content));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"compaction\":\n\t\t\t\tparts.push(\"compaction\");\n\t\t\t\tbreak;\n\t\t\tcase \"branch_summary\":\n\t\t\t\tparts.push(\"branch summary\", entry.summary);\n\t\t\t\tbreak;\n\t\t\tcase \"session_info\":\n\t\t\t\tparts.push(\"title\");\n\t\t\t\tif (entry.name) parts.push(entry.name);\n\t\t\t\tbreak;\n\t\t\tcase \"model_change\":\n\t\t\t\tparts.push(\"model\", entry.modelId);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_level_change\":\n\t\t\t\tparts.push(\"thinking\", entry.thinkingLevel);\n\t\t\t\tbreak;\n\t\t\tcase \"custom\":\n\t\t\t\tparts.push(\"custom\", entry.customType);\n\t\t\t\tbreak;\n\t\t\tcase \"label\":\n\t\t\t\tparts.push(\"label\", entry.label ?? \"\");\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn parts.join(\" \");\n\t}\n\n\tinvalidate(): void {}\n\n\tgetSearchQuery(): string {\n\t\treturn this.searchQuery;\n\t}\n\n\tgetSelectedNode(): SessionTreeNode | undefined {\n\t\treturn this.filteredNodes[this.selectedIndex]?.node;\n\t}\n\n\tcopySelected(): void {\n\t\tconst node = this.getSelectedNode();\n\t\tthis.onCopy?.(node ? this.getEntryCopyText(node) : undefined);\n\t}\n\n\tupdateNodeLabel(entryId: string, label: string | undefined, labelTimestamp?: string): void {\n\t\tfor (const flatNode of this.flatNodes) {\n\t\t\tif (flatNode.node.entry.id === entryId) {\n\t\t\t\tflatNode.node.label = label;\n\t\t\t\tflatNode.node.labelTimestamp = label ? (labelTimestamp ?? new Date().toISOString()) : undefined;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getStatusLabels(): string {\n\t\tlet labels = \"\";\n\t\tswitch (this.filterMode) {\n\t\t\tcase \"no-tools\":\n\t\t\t\tlabels += \" [no-tools]\";\n\t\t\t\tbreak;\n\t\t\tcase \"user-only\":\n\t\t\t\tlabels += \" [user]\";\n\t\t\t\tbreak;\n\t\t\tcase \"labeled-only\":\n\t\t\t\tlabels += \" [labeled]\";\n\t\t\t\tbreak;\n\t\t\tcase \"all\":\n\t\t\t\tlabels += \" [all]\";\n\t\t\t\tbreak;\n\t\t}\n\t\tif (this.showLabelTimestamps) {\n\t\t\tlabels += \" [+label time]\";\n\t\t}\n\t\treturn labels;\n\t}\n\n\tprivate getVisibleNodeRange(): VisibleNodeRange {\n\t\tconst start = Math.max(\n\t\t\t0,\n\t\t\tMath.min(\n\t\t\t\tthis.selectedIndex - Math.floor(this.maxVisibleLines / 2),\n\t\t\t\tthis.filteredNodes.length - this.maxVisibleLines,\n\t\t\t),\n\t\t);\n\t\treturn { start, end: Math.min(start + this.maxVisibleLines, this.filteredNodes.length) };\n\t}\n\n\tprivate renderPrefixCharacter(\n\t\tflatNode: FlatNode,\n\t\tentryId: string,\n\t\tlevel: number,\n\t\tposition: number,\n\t\tconnectorPosition: number,\n\t\tisFolded: boolean,\n\t): string {\n\t\tconst gutter = flatNode.gutters.find((candidate) => candidate.position === level);\n\t\tif (gutter) return position === 0 && gutter.show ? \"│\" : \" \";\n\t\tif (level !== connectorPosition) return \" \";\n\t\tif (position === 0) return flatNode.isLast ? \"└\" : \"├\";\n\t\tif (position !== 1) return \" \";\n\t\tif (isFolded) return \"⊞\";\n\t\treturn this.isFoldable(entryId) ? \"⊟\" : \"─\";\n\t}\n\n\tprivate renderNodePrefix(flatNode: FlatNode): string {\n\t\tconst displayIndent = this.multipleRoots ? Math.max(0, flatNode.indent - 1) : flatNode.indent;\n\t\tconst showsConnector = flatNode.showConnector && !flatNode.isVirtualRootChild;\n\t\tconst connectorPosition = showsConnector ? displayIndent - 1 : -1;\n\t\tconst isFolded = this.foldedNodes.has(flatNode.node.entry.id);\n\t\tconst characters: string[] = [];\n\t\tfor (let index = 0; index < displayIndent * 3; index++) {\n\t\t\tcharacters.push(\n\t\t\t\tthis.renderPrefixCharacter(\n\t\t\t\t\tflatNode,\n\t\t\t\t\tflatNode.node.entry.id,\n\t\t\t\t\tMath.floor(index / 3),\n\t\t\t\t\tindex % 3,\n\t\t\t\t\tconnectorPosition,\n\t\t\t\t\tisFolded,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst foldMarker = isFolded && !showsConnector ? theme.fg(\"accent\", \"⊞ \") : \"\";\n\t\treturn theme.fg(\"dim\", characters.join(\"\")) + foldMarker;\n\t}\n\n\tprivate renderNodeLine(flatNode: FlatNode, index: number, width: number): string {\n\t\tconst entry = flatNode.node.entry;\n\t\tconst isSelected = index === this.selectedIndex;\n\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"› \") : \" \";\n\t\tconst pathMarker = this.activePathIds.has(entry.id) ? theme.fg(\"accent\", \"• \") : \"\";\n\t\tconst label = flatNode.node.label ? theme.fg(\"warning\", `[${flatNode.node.label}] `) : \"\";\n\t\tconst labelTimestamp =\n\t\t\tthis.showLabelTimestamps && flatNode.node.label && flatNode.node.labelTimestamp\n\t\t\t\t? theme.fg(\"muted\", `${this.formatLabelTimestamp(flatNode.node.labelTimestamp)} `)\n\t\t\t\t: \"\";\n\t\tconst content = this.getEntryDisplayText(flatNode.node, isSelected);\n\t\tconst line = cursor + this.renderNodePrefix(flatNode) + pathMarker + label + labelTimestamp + content;\n\t\treturn truncateToWidth(isSelected ? theme.bg(\"selectedBg\", line) : line, width);\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.filteredNodes.length === 0) {\n\t\t\treturn [\n\t\t\t\ttruncateToWidth(theme.fg(\"muted\", \" No entries found\"), width),\n\t\t\t\ttruncateToWidth(theme.fg(\"muted\", ` (0/0)${this.getStatusLabels()}`), width),\n\t\t\t];\n\t\t}\n\t\tconst lines: string[] = [];\n\t\tconst range = this.getVisibleNodeRange();\n\t\tfor (let index = range.start; index < range.end; index++) {\n\t\t\tlines.push(this.renderNodeLine(this.filteredNodes[index], index, width));\n\t\t}\n\t\tlines.push(\n\t\t\ttruncateToWidth(\n\t\t\t\ttheme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filteredNodes.length})${this.getStatusLabels()}`),\n\t\t\t\twidth,\n\t\t\t),\n\t\t);\n\t\treturn lines;\n\t}\n\tprivate normalizeDisplayText(value: string): string {\n\t\treturn value.replace(/[\\n\\t]/g, \" \").trim();\n\t}\n\n\tprivate getAssistantDisplayText(message: AssistantMessage): string {\n\t\tconst textContent = this.normalizeDisplayText(this.extractContent(message.content));\n\t\tif (textContent) return theme.fg(\"success\", \"assistant: \") + textContent;\n\t\tif (message.stopReason === \"aborted\") {\n\t\t\treturn theme.fg(\"success\", \"assistant: \") + theme.fg(\"muted\", \"(aborted)\");\n\t\t}\n\t\tif (message.errorMessage) {\n\t\t\tconst errorMessage = this.normalizeDisplayText(message.errorMessage).slice(0, 80);\n\t\t\treturn theme.fg(\"success\", \"assistant: \") + theme.fg(\"error\", errorMessage);\n\t\t}\n\t\treturn theme.fg(\"success\", \"assistant: \") + theme.fg(\"muted\", \"(no content)\");\n\t}\n\n\tprivate getMessageDisplayText(message: AgentMessage): string {\n\t\tswitch (message.role) {\n\t\t\tcase \"user\":\n\t\t\t\treturn theme.fg(\"accent\", \"user: \") + this.normalizeDisplayText(this.extractContent(message.content));\n\t\t\tcase \"assistant\":\n\t\t\t\treturn this.getAssistantDisplayText(message);\n\t\t\tcase \"toolResult\": {\n\t\t\t\tconst toolCall = this.toolCallMap.get(message.toolCallId);\n\t\t\t\treturn toolCall\n\t\t\t\t\t? theme.fg(\"muted\", this.formatToolCall(toolCall.name, toolCall.arguments))\n\t\t\t\t\t: theme.fg(\"muted\", `[${message.toolName ?? \"tool\"}]`);\n\t\t\t}\n\t\t\tcase \"bashExecution\":\n\t\t\t\treturn theme.fg(\"dim\", `[bash]: ${this.normalizeDisplayText(message.command ?? \"\")}`);\n\t\t\tdefault:\n\t\t\t\treturn theme.fg(\"dim\", `[${message.role}]`);\n\t\t}\n\t}\n\n\tprivate getEntryDisplayText(node: SessionTreeNode, isSelected: boolean): string {\n\t\tconst entry = node.entry;\n\t\tlet result: string;\n\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\":\n\t\t\t\tresult = this.getMessageDisplayText(entry.message);\n\t\t\t\tbreak;\n\t\t\tcase \"custom_message\":\n\t\t\t\tresult =\n\t\t\t\t\ttheme.fg(\"customMessageLabel\", `[${entry.customType}]: `) +\n\t\t\t\t\tthis.normalizeDisplayText(this.extractFullContent(entry.content));\n\t\t\t\tbreak;\n\t\t\tcase \"compaction\": {\n\t\t\t\tconst tokens = Math.round(entry.tokensBefore / 1000);\n\t\t\t\tresult = theme.fg(\"borderAccent\", `[compaction: ${tokens}k tokens]`);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"branch_summary\":\n\t\t\t\tresult = theme.fg(\"warning\", `[branch summary]: `) + this.normalizeDisplayText(entry.summary);\n\t\t\t\tbreak;\n\t\t\tcase \"model_change\":\n\t\t\t\tresult = theme.fg(\"dim\", `[model: ${entry.modelId}]`);\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_level_change\":\n\t\t\t\tresult = theme.fg(\"dim\", `[thinking: ${entry.thinkingLevel}]`);\n\t\t\t\tbreak;\n\t\t\tcase \"custom\":\n\t\t\t\tresult = theme.fg(\"dim\", `[custom: ${entry.customType}]`);\n\t\t\t\tbreak;\n\t\t\tcase \"label\":\n\t\t\t\tresult = theme.fg(\"dim\", `[label: ${entry.label ?? \"(cleared)\"}]`);\n\t\t\t\tbreak;\n\t\t\tcase \"session_info\":\n\t\t\t\tresult = entry.name\n\t\t\t\t\t? [theme.fg(\"dim\", \"[title: \"), theme.fg(\"dim\", entry.name), theme.fg(\"dim\", \"]\")].join(\"\")\n\t\t\t\t\t: [theme.fg(\"dim\", \"[title: \"), theme.italic(theme.fg(\"dim\", \"empty\")), theme.fg(\"dim\", \"]\")].join(\"\");\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tresult = \"\";\n\t\t}\n\n\t\treturn isSelected ? theme.bold(result) : result;\n\t}\n\n\tprivate formatLabelTimestamp(timestamp: string): string {\n\t\tconst date = new Date(timestamp);\n\t\tconst now = new Date();\n\t\tconst hours = date.getHours().toString().padStart(2, \"0\");\n\t\tconst minutes = date.getMinutes().toString().padStart(2, \"0\");\n\t\tconst time = `${hours}:${minutes}`;\n\n\t\tif (\n\t\t\tdate.getFullYear() === now.getFullYear() &&\n\t\t\tdate.getMonth() === now.getMonth() &&\n\t\t\tdate.getDate() === now.getDate()\n\t\t) {\n\t\t\treturn time;\n\t\t}\n\n\t\tconst month = date.getMonth() + 1;\n\t\tconst day = date.getDate();\n\t\tif (date.getFullYear() === now.getFullYear()) {\n\t\t\treturn `${month}/${day} ${time}`;\n\t\t}\n\n\t\tconst year = date.getFullYear().toString().slice(-2);\n\t\treturn `${year}/${month}/${day} ${time}`;\n\t}\n\n\tprivate extractContent(content: unknown): string {\n\t\treturn this.extractFullContent(content).slice(0, 200);\n\t}\n\n\tprivate extractFullContent(content: unknown): string {\n\t\tif (typeof content === \"string\") return content;\n\t\tif (!Array.isArray(content)) return \"\";\n\n\t\tlet result = \"\";\n\t\tfor (const block of content) {\n\t\t\tif (typeof block === \"object\" && block !== null && \"type\" in block && block.type === \"text\") {\n\t\t\t\tresult += (block as { text: string }).text;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate getEntryCopyText(node: SessionTreeNode): string | undefined {\n\t\tconst entry = node.entry;\n\t\tlet text: string | undefined;\n\n\t\tswitch (entry.type) {\n\t\t\tcase \"message\":\n\t\t\t\tif (entry.message.role === \"bashExecution\") {\n\t\t\t\t\ttext = entry.message.command;\n\t\t\t\t} else if (\"content\" in entry.message) {\n\t\t\t\t\ttext = this.extractFullContent(entry.message.content);\n\t\t\t\t\tif (!text && entry.message.role === \"assistant\") {\n\t\t\t\t\t\ttext = entry.message.errorMessage;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"custom_message\":\n\t\t\t\ttext = this.extractFullContent(entry.content);\n\t\t\t\tbreak;\n\t\t\tcase \"compaction\":\n\t\t\t\ttext = entry.summary;\n\t\t\t\tbreak;\n\t\t\tcase \"branch_summary\":\n\t\t\t\ttext = entry.summary;\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn text?.trim() ? text : undefined;\n\t}\n\n\tprivate hasTextContent(content: unknown): boolean {\n\t\tif (typeof content === \"string\") return content.trim().length > 0;\n\t\tif (Array.isArray(content)) {\n\t\t\tfor (const c of content) {\n\t\t\t\tif (typeof c === \"object\" && c !== null && \"type\" in c && c.type === \"text\") {\n\t\t\t\t\tconst text = (c as { text?: string }).text;\n\t\t\t\t\tif (text && text.trim().length > 0) return true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate formatToolCall(name: string, args: Record<string, unknown>): string {\n\t\tswitch (name) {\n\t\t\tcase \"read\":\n\t\t\t\treturn formatTreeReadToolCall(args);\n\t\t\tcase \"write\":\n\t\t\tcase \"edit\":\n\t\t\t\treturn formatTreeFileMutationToolCall(name, args);\n\t\t\tcase \"bash\":\n\t\t\t\treturn formatTreeBashToolCall(args);\n\t\t\tcase \"grep\":\n\t\t\tcase \"find\":\n\t\t\t\treturn formatTreeSearchToolCall(name, args);\n\t\t\tcase \"ls\":\n\t\t\t\treturn `[ls: ${shortenTreeToolPath(String(args.path || \".\"))}]`;\n\t\t\tdefault:\n\t\t\t\treturn formatCustomTreeToolCall(name, args);\n\t\t}\n\t}\n\n\tprivate foldSelectedNodeOrMoveToPreviousBranch(): void {\n\t\tconst currentId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n\t\tif (currentId && this.isFoldable(currentId) && !this.foldedNodes.has(currentId)) {\n\t\t\tthis.foldedNodes.add(currentId);\n\t\t\tthis.applyFilter();\n\t\t\treturn;\n\t\t}\n\t\tthis.selectedIndex = this.findBranchSegmentStart(\"up\");\n\t}\n\n\tprivate unfoldSelectedNodeOrMoveToNextBranch(): void {\n\t\tconst currentId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n\t\tif (currentId && this.foldedNodes.has(currentId)) {\n\t\t\tthis.foldedNodes.delete(currentId);\n\t\t\tthis.applyFilter();\n\t\t\treturn;\n\t\t}\n\t\tthis.selectedIndex = this.findBranchSegmentStart(\"down\");\n\t}\n\n\tprivate handleTreeMovementInput(keyData: string): boolean {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredNodes.length - 1 : this.selectedIndex - 1;\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredNodes.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.tree.foldOrUp\")) {\n\t\t\tthis.foldSelectedNodeOrMoveToPreviousBranch();\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.tree.unfoldOrDown\")) {\n\t\t\tthis.unfoldSelectedNodeOrMoveToNextBranch();\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.editor.cursorLeft\") || kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisibleLines);\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.editor.cursorRight\") || kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.selectedIndex = Math.min(this.filteredNodes.length - 1, this.selectedIndex + this.maxVisibleLines);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate cancelSearchOrSelection(): void {\n\t\tif (!this.searchQuery) {\n\t\t\tthis.onCancel?.();\n\t\t\treturn;\n\t\t}\n\t\tthis.searchQuery = \"\";\n\t\tthis.foldedNodes.clear();\n\t\tthis.applyFilter();\n\t}\n\n\tprivate handleTreeSelectionInput(keyData: string): boolean {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selected = this.filteredNodes[this.selectedIndex];\n\t\t\tif (selected) this.onSelect?.(selected.node.entry.id);\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.message.copy\")) {\n\t\t\tthis.copySelected();\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.cancelSearchOrSelection();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate setFilterMode(mode: FilterMode): void {\n\t\tthis.filterMode = mode;\n\t\tthis.foldedNodes.clear();\n\t\tthis.applyFilter();\n\t}\n\n\tprivate toggleFilterMode(mode: FilterMode): void {\n\t\tthis.setFilterMode(this.filterMode === mode ? \"default\" : mode);\n\t}\n\n\tprivate cycleFilterMode(step: number): void {\n\t\tconst currentIndex = FILTER_MODES.indexOf(this.filterMode);\n\t\tthis.setFilterMode(FILTER_MODES[(currentIndex + step + FILTER_MODES.length) % FILTER_MODES.length]);\n\t}\n\n\tprivate handleTreeFilterInput(keyData: string): boolean {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.tree.filter.default\")) this.setFilterMode(\"default\");\n\t\telse if (kb.matches(keyData, \"app.tree.filter.noTools\")) this.toggleFilterMode(\"no-tools\");\n\t\telse if (kb.matches(keyData, \"app.tree.filter.userOnly\")) this.toggleFilterMode(\"user-only\");\n\t\telse if (kb.matches(keyData, \"app.tree.filter.labeledOnly\")) this.toggleFilterMode(\"labeled-only\");\n\t\telse if (kb.matches(keyData, \"app.tree.filter.all\")) this.toggleFilterMode(\"all\");\n\t\telse if (kb.matches(keyData, \"app.tree.filter.cycleBackward\")) this.cycleFilterMode(-1);\n\t\telse if (kb.matches(keyData, \"app.tree.filter.cycleForward\")) this.cycleFilterMode(1);\n\t\telse return false;\n\t\treturn true;\n\t}\n\n\tprivate appendTreeSearchInput(keyData: string): void {\n\t\tif (keyData.length === 0 || hasTreeSearchControlCharacters(keyData)) return;\n\t\tthis.searchQuery += keyData;\n\t\tthis.foldedNodes.clear();\n\t\tthis.applyFilter();\n\t}\n\n\tprivate handleTreeEditingInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.editor.deleteCharBackward\")) {\n\t\t\tif (this.searchQuery.length > 0) {\n\t\t\t\tthis.searchQuery = this.searchQuery.slice(0, -1);\n\t\t\t\tthis.foldedNodes.clear();\n\t\t\t\tthis.applyFilter();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.tree.editLabel\")) {\n\t\t\tconst selected = this.filteredNodes[this.selectedIndex];\n\t\t\tif (selected) this.onLabelEdit?.(selected.node.entry.id, selected.node.label);\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.tree.toggleLabelTimestamp\")) {\n\t\t\tthis.showLabelTimestamps = !this.showLabelTimestamps;\n\t\t\treturn;\n\t\t}\n\t\tthis.appendTreeSearchInput(keyData);\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tif (this.handleTreeMovementInput(keyData)) return;\n\t\tif (this.handleTreeSelectionInput(keyData)) return;\n\t\tif (this.handleTreeFilterInput(keyData)) return;\n\t\tthis.handleTreeEditingInput(keyData);\n\t}\n\n\t/**\n\t * Whether a node can be folded. A node is foldable if it has visible children\n\t * and is either a root (no visible parent) or a segment start (visible parent\n\t * has multiple visible children).\n\t */\n\tprivate isFoldable(entryId: string): boolean {\n\t\tconst children = this.visibleChildrenMap.get(entryId);\n\t\tif (!children || children.length === 0) return false;\n\t\tconst parentId = this.visibleParentMap.get(entryId);\n\t\tif (parentId === null || parentId === undefined) return true;\n\t\tconst siblings = this.visibleChildrenMap.get(parentId);\n\t\treturn siblings !== undefined && siblings.length > 1;\n\t}\n\n\tprivate findNextBranchSegmentStart(selectedId: string, indexByEntryId: ReadonlyMap<string, number>): number {\n\t\tlet currentId = selectedId;\n\t\twhile (true) {\n\t\t\tconst children = this.visibleChildrenMap.get(currentId) ?? [];\n\t\t\tif (children.length === 0) return indexByEntryId.get(currentId)!;\n\t\t\tif (children.length > 1) return indexByEntryId.get(children[0])!;\n\t\t\tcurrentId = children[0];\n\t\t}\n\t}\n\n\tprivate findPreviousBranchSegmentStart(selectedId: string, indexByEntryId: ReadonlyMap<string, number>): number {\n\t\tlet currentId = selectedId;\n\t\twhile (true) {\n\t\t\tconst parentId = this.visibleParentMap.get(currentId) ?? null;\n\t\t\tif (parentId === null) return indexByEntryId.get(currentId)!;\n\t\t\tconst siblings = this.visibleChildrenMap.get(parentId) ?? [];\n\t\t\tif (siblings.length > 1) {\n\t\t\t\tconst segmentStart = indexByEntryId.get(currentId)!;\n\t\t\t\tif (segmentStart < this.selectedIndex) return segmentStart;\n\t\t\t}\n\t\t\tcurrentId = parentId;\n\t\t}\n\t}\n\n\t/**\n\t * Find the index of the next branch segment start in the given direction.\n\t * A segment start is the first child of a branch point.\n\t *\n\t * \"up\" walks the visible parent chain; \"down\" walks visible children\n\t * (always following the first child).\n\t */\n\tprivate findBranchSegmentStart(direction: BranchSegmentTraversalDirection): number {\n\t\tconst selectedId = this.filteredNodes[this.selectedIndex]?.node.entry.id;\n\t\tif (!selectedId) return this.selectedIndex;\n\n\t\tconst indexByEntryId = new Map(this.filteredNodes.map((node, index) => [node.node.entry.id, index]));\n\t\treturn direction === \"down\"\n\t\t\t? this.findNextBranchSegmentStart(selectedId, indexByEntryId)\n\t\t\t: this.findPreviousBranchSegmentStart(selectedId, indexByEntryId);\n\t}\n}\n\n/** Component that displays the current search query */\nclass SearchLine implements Component {\n\tprivate treeList: TreeList;\n\n\tconstructor(treeList: TreeList) {\n\t\tthis.treeList = treeList;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst query = this.treeList.getSearchQuery();\n\t\tif (query) {\n\t\t\treturn [truncateToWidth(` ${theme.fg(\"muted\", \"Type to search:\")} ${theme.fg(\"accent\", query)}`, width)];\n\t\t}\n\t\treturn [truncateToWidth(` ${theme.fg(\"muted\", \"Type to search:\")}`, width)];\n\t}\n\n\thandleInput(_keyData: string): void {}\n}\n\n/** Label input component shown when editing a label */\nclass LabelInput implements Component, Focusable {\n\tprivate input: Input;\n\tprivate entryId: string;\n\tpublic onSubmit?: (entryId: string, label: string | undefined) => void;\n\tpublic onCancel?: () => void;\n\n\t// Focusable implementation - propagate to input for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tconstructor(entryId: string, currentLabel: string | undefined) {\n\t\tthis.entryId = entryId;\n\t\tthis.input = new Input();\n\t\tif (currentLabel) {\n\t\t\tthis.input.setValue(currentLabel);\n\t\t}\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \";\n\t\tconst availableWidth = width - indent.length;\n\t\tlines.push(truncateToWidth(`${indent}${theme.fg(\"muted\", \"Label (empty to remove):\")}`, width));\n\t\tlines.push(...this.input.render(availableWidth).map((line) => truncateToWidth(`${indent}${line}`, width)));\n\t\tlines.push(\n\t\t\ttruncateToWidth(\n\t\t\t\t`${indent}${keyHint(\"tui.select.confirm\", \"save\")} ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\twidth,\n\t\t\t),\n\t\t);\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst value = this.input.getValue().trim();\n\t\t\tthis.onSubmit?.(this.entryId, value || undefined);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancel?.();\n\t\t} else {\n\t\t\tthis.input.handleInput(keyData);\n\t\t}\n\t}\n}\n\n/**\n * Component that renders a session tree selector for navigation\n */\nexport class TreeSelectorComponent extends Container implements Focusable {\n\tprivate treeList: TreeList;\n\tprivate labelInput: LabelInput | null = null;\n\tprivate labelInputContainer: Container;\n\tprivate treeContainer: Container;\n\tprivate onLabelChangeCallback?: (entryId: string, label: string | undefined) => void;\n\tpublic onCopy?: (text: string | undefined) => void;\n\n\t// Focusable implementation - propagate to labelInput when active for IME cursor positioning\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\t// Propagate to labelInput when it's active\n\t\tif (this.labelInput) {\n\t\t\tthis.labelInput.focused = value;\n\t\t}\n\t}\n\n\tconstructor(\n\t\ttree: SessionTreeNode[],\n\t\tcurrentLeafId: string | null,\n\t\tterminalHeight: number,\n\t\tonSelect: (entryId: string) => void,\n\t\tonCancel: () => void,\n\t\tonLabelChange?: (entryId: string, label: string | undefined) => void,\n\t\tinitialSelectedId?: string,\n\t\tinitialFilterMode?: FilterMode,\n\t) {\n\t\tsuper();\n\n\t\tthis.onLabelChangeCallback = onLabelChange;\n\t\tconst maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));\n\n\t\tthis.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode);\n\t\tthis.treeList.onSelect = onSelect;\n\t\tthis.treeList.onCancel = onCancel;\n\t\tthis.treeList.onCopy = (text) => this.onCopy?.(text);\n\t\tthis.treeList.onLabelEdit = (entryId, currentLabel) => this.showLabelInput(entryId, currentLabel);\n\n\t\tthis.treeContainer = new Container();\n\t\tthis.treeContainer.addChild(this.treeList);\n\n\t\tthis.labelInputContainer = new Container();\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Text(theme.bold(\" Session Tree\"), 1, 0));\n\t\tconst filterKeys = [\n\t\t\tkeyText(\"app.tree.filter.default\"),\n\t\t\tkeyText(\"app.tree.filter.noTools\"),\n\t\t\tkeyText(\"app.tree.filter.userOnly\"),\n\t\t\tkeyText(\"app.tree.filter.labeledOnly\"),\n\t\t\tkeyText(\"app.tree.filter.all\"),\n\t\t].join(\"/\");\n\t\tconst cycleKeys = `${keyText(\"app.tree.filter.cycleForward\")}/${keyText(\"app.tree.filter.cycleBackward\")}`;\n\t\tconst branchKeys = `${keyText(\"app.tree.foldOrUp\")}/${keyText(\"app.tree.unfoldOrDown\")}`;\n\t\tthis.addChild(\n\t\t\tnew TruncatedText(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t` ↑/↓: move. ←/→: page. ${branchKeys}: fold/branch. ${keyText(\"app.message.copy\")}: copy. ${keyText(\"app.tree.editLabel\")}: label. ${filterKeys}: filters (${cycleKeys} cycle). ${keyText(\"app.tree.toggleLabelTimestamp\")}: label time`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new SearchLine(this.treeList));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.treeContainer);\n\t\tthis.addChild(this.labelInputContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tif (tree.length === 0) {\n\t\t\tsetTimeout(() => onCancel(), 100);\n\t\t}\n\t}\n\n\tprivate showLabelInput(entryId: string, currentLabel: string | undefined): void {\n\t\tthis.labelInput = new LabelInput(entryId, currentLabel);\n\t\tthis.labelInput.onSubmit = (id, label) => {\n\t\t\tthis.treeList.updateNodeLabel(id, label);\n\t\t\tthis.onLabelChangeCallback?.(id, label);\n\t\t\tthis.hideLabelInput();\n\t\t};\n\t\tthis.labelInput.onCancel = () => this.hideLabelInput();\n\n\t\t// Propagate current focused state to the new labelInput\n\t\tthis.labelInput.focused = this._focused;\n\n\t\tthis.treeContainer.clear();\n\t\tthis.labelInputContainer.clear();\n\t\tthis.labelInputContainer.addChild(this.labelInput);\n\t}\n\n\tprivate hideLabelInput(): void {\n\t\tthis.labelInput = null;\n\t\tthis.labelInputContainer.clear();\n\t\tthis.treeContainer.clear();\n\t\tthis.treeContainer.addChild(this.treeList);\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tif (this.labelInput) {\n\t\t\tthis.labelInput.handleInput(keyData);\n\t\t} else {\n\t\t\tthis.treeList.handleInput(keyData);\n\t\t}\n\t}\n\n\tgetTreeList(): TreeList {\n\t\treturn this.treeList;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tree-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tree-selector.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,26 +48,20 @@ function formatCustomTreeToolCall(name, args) {
|
|
|
48
48
|
return `[${name}: ${argsString}${JSON.stringify(args).length > 40 ? "..." : ""}]`;
|
|
49
49
|
}
|
|
50
50
|
class TreeList {
|
|
51
|
-
flatNodes = [];
|
|
52
|
-
filteredNodes = [];
|
|
53
|
-
selectedIndex = 0;
|
|
54
|
-
currentLeafId;
|
|
55
|
-
maxVisibleLines;
|
|
56
|
-
filterMode = "default";
|
|
57
|
-
searchQuery = "";
|
|
58
|
-
toolCallMap = new Map();
|
|
59
|
-
multipleRoots = false;
|
|
60
|
-
showLabelTimestamps = false;
|
|
61
|
-
activePathIds = new Set();
|
|
62
|
-
visibleParentMap = new Map();
|
|
63
|
-
visibleChildrenMap = new Map();
|
|
64
|
-
lastSelectedId = null;
|
|
65
|
-
foldedNodes = new Set();
|
|
66
|
-
onSelect;
|
|
67
|
-
onCancel;
|
|
68
|
-
onCopy;
|
|
69
|
-
onLabelEdit;
|
|
70
51
|
constructor(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode) {
|
|
52
|
+
this.flatNodes = [];
|
|
53
|
+
this.filteredNodes = [];
|
|
54
|
+
this.selectedIndex = 0;
|
|
55
|
+
this.filterMode = "default";
|
|
56
|
+
this.searchQuery = "";
|
|
57
|
+
this.toolCallMap = new Map();
|
|
58
|
+
this.multipleRoots = false;
|
|
59
|
+
this.showLabelTimestamps = false;
|
|
60
|
+
this.activePathIds = new Set();
|
|
61
|
+
this.visibleParentMap = new Map();
|
|
62
|
+
this.visibleChildrenMap = new Map();
|
|
63
|
+
this.lastSelectedId = null;
|
|
64
|
+
this.foldedNodes = new Set();
|
|
71
65
|
this.currentLeafId = currentLeafId;
|
|
72
66
|
this.maxVisibleLines = maxVisibleLines;
|
|
73
67
|
this.filterMode = initialFilterMode ?? "default";
|
|
@@ -945,7 +939,6 @@ class TreeList {
|
|
|
945
939
|
}
|
|
946
940
|
/** Component that displays the current search query */
|
|
947
941
|
class SearchLine {
|
|
948
|
-
treeList;
|
|
949
942
|
constructor(treeList) {
|
|
950
943
|
this.treeList = treeList;
|
|
951
944
|
}
|
|
@@ -961,12 +954,6 @@ class SearchLine {
|
|
|
961
954
|
}
|
|
962
955
|
/** Label input component shown when editing a label */
|
|
963
956
|
class LabelInput {
|
|
964
|
-
input;
|
|
965
|
-
entryId;
|
|
966
|
-
onSubmit;
|
|
967
|
-
onCancel;
|
|
968
|
-
// Focusable implementation - propagate to input for IME cursor positioning
|
|
969
|
-
_focused = false;
|
|
970
957
|
get focused() {
|
|
971
958
|
return this._focused;
|
|
972
959
|
}
|
|
@@ -975,6 +962,8 @@ class LabelInput {
|
|
|
975
962
|
this.input.focused = value;
|
|
976
963
|
}
|
|
977
964
|
constructor(entryId, currentLabel) {
|
|
965
|
+
// Focusable implementation - propagate to input for IME cursor positioning
|
|
966
|
+
this._focused = false;
|
|
978
967
|
this.entryId = entryId;
|
|
979
968
|
this.input = new Input();
|
|
980
969
|
if (currentLabel) {
|
|
@@ -1009,14 +998,6 @@ class LabelInput {
|
|
|
1009
998
|
* Component that renders a session tree selector for navigation
|
|
1010
999
|
*/
|
|
1011
1000
|
export class TreeSelectorComponent extends Container {
|
|
1012
|
-
treeList;
|
|
1013
|
-
labelInput = null;
|
|
1014
|
-
labelInputContainer;
|
|
1015
|
-
treeContainer;
|
|
1016
|
-
onLabelChangeCallback;
|
|
1017
|
-
onCopy;
|
|
1018
|
-
// Focusable implementation - propagate to labelInput when active for IME cursor positioning
|
|
1019
|
-
_focused = false;
|
|
1020
1001
|
get focused() {
|
|
1021
1002
|
return this._focused;
|
|
1022
1003
|
}
|
|
@@ -1029,6 +1010,9 @@ export class TreeSelectorComponent extends Container {
|
|
|
1029
1010
|
}
|
|
1030
1011
|
constructor(tree, currentLeafId, terminalHeight, onSelect, onCancel, onLabelChange, initialSelectedId, initialFilterMode) {
|
|
1031
1012
|
super();
|
|
1013
|
+
this.labelInput = null;
|
|
1014
|
+
// Focusable implementation - propagate to labelInput when active for IME cursor positioning
|
|
1015
|
+
this._focused = false;
|
|
1032
1016
|
this.onLabelChangeCallback = onLabelChange;
|
|
1033
1017
|
const maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));
|
|
1034
1018
|
this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode);
|