@bastani/atomic 0.9.2 → 0.9.3-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +2 -2
- package/dist/builtin/cursor/CHANGELOG.md +15 -0
- package/dist/builtin/cursor/README.md +2 -1
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/cursor/src/cursor-models-raw.json +2 -9
- package/dist/builtin/cursor/src/model-mapper.ts +14 -3
- package/dist/builtin/cursor/src/proto/protobuf-codec-base64.ts +22 -0
- package/dist/builtin/cursor/src/proto/protobuf-codec-request.ts +53 -13
- package/dist/builtin/cursor/src/proto/protobuf-codec-wire.ts +24 -7
- package/dist/builtin/cursor/src/proto/protobuf-codec.ts +3 -2
- package/dist/builtin/cursor/src/stream.ts +5 -11
- package/dist/builtin/cursor/src/transport-types.ts +3 -0
- package/dist/builtin/cursor/src/transport.ts +1 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/direct-tools.ts +4 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/proxy-call.ts +3 -1
- package/dist/builtin/mcp/utils.ts +18 -7
- package/dist/builtin/subagents/CHANGELOG.md +20 -0
- package/dist/builtin/subagents/README.md +6 -6
- package/dist/builtin/subagents/agents/code-simplifier.md +7 -6
- package/dist/builtin/subagents/agents/codebase-analyzer.md +5 -4
- package/dist/builtin/subagents/agents/codebase-locator.md +3 -3
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +10 -10
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +4 -4
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +3 -3
- package/dist/builtin/subagents/agents/codebase-research-locator.md +4 -4
- package/dist/builtin/subagents/agents/debugger.md +5 -5
- package/dist/builtin/subagents/agents/worker.md +56 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
- package/dist/builtin/subagents/src/agents/agent-loaders.ts +3 -5
- package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +3 -3
- package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -0
- package/dist/builtin/subagents/src/extension/index.ts +6 -3
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -7
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -3
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +1 -4
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +15 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +35 -1
- package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +2 -2
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -1
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +4 -2
- package/dist/builtin/subagents/src/shared/types-async.ts +1 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +5 -5
- package/dist/builtin/subagents/src/shared/types-runtime.ts +2 -1
- package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +27 -5
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-layout.ts +27 -4
- package/dist/builtin/subagents/src/tui/render-result-animation.ts +22 -31
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +6 -6
- package/dist/builtin/subagents/src/tui/render-result.ts +20 -19
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +3 -3
- package/dist/builtin/subagents/src/tui/render-widget.ts +46 -7
- package/dist/builtin/subagents/src/tui/render.ts +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +56 -0
- package/dist/builtin/workflows/README.md +3 -3
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +11 -6
- package/dist/builtin/workflows/builtin/goal-ledger.ts +33 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -28
- package/dist/builtin/workflows/builtin/goal-reducer.ts +2 -2
- package/dist/builtin/workflows/builtin/goal-reports.ts +2 -5
- package/dist/builtin/workflows/builtin/goal-review.ts +1 -1
- package/dist/builtin/workflows/builtin/goal-runner.ts +10 -17
- package/dist/builtin/workflows/builtin/open-claude-design-feedback.ts +3 -3
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +1 -3
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +7 -17
- package/dist/builtin/workflows/builtin/ralph-runner.ts +11 -18
- package/dist/builtin/workflows/builtin/shared-prompts.ts +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +1 -1
- package/dist/builtin/workflows/src/durable/backend.ts +343 -0
- package/dist/builtin/workflows/src/durable/child-primitive.ts +79 -0
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +421 -0
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +171 -0
- package/dist/builtin/workflows/src/durable/factory.ts +96 -0
- package/dist/builtin/workflows/src/durable/file-backend.ts +433 -0
- package/dist/builtin/workflows/src/durable/index.ts +73 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +217 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +299 -0
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +171 -0
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +284 -0
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +180 -0
- package/dist/builtin/workflows/src/durable/types.ts +168 -0
- package/dist/builtin/workflows/src/durable/ui-primitive.ts +96 -0
- package/dist/builtin/workflows/src/engine/options.ts +3 -0
- package/dist/builtin/workflows/src/engine/primitives/parallel.ts +2 -2
- package/dist/builtin/workflows/src/engine/primitives/task.ts +4 -4
- package/dist/builtin/workflows/src/engine/primitives/ui.ts +22 -8
- package/dist/builtin/workflows/src/engine/primitives/workflow.ts +8 -0
- package/dist/builtin/workflows/src/engine/run-durable-finalize.ts +69 -0
- package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +31 -0
- package/dist/builtin/workflows/src/engine/run.ts +148 -6
- package/dist/builtin/workflows/src/engine/runtime.ts +8 -2
- package/dist/builtin/workflows/src/extension/config-loader.ts +35 -15
- package/dist/builtin/workflows/src/extension/discovery.ts +20 -8
- package/dist/builtin/workflows/src/extension/extension-factory.ts +6 -12
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +5 -1
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +4 -2
- package/dist/builtin/workflows/src/extension/runtime.ts +48 -9
- package/dist/builtin/workflows/src/extension/wiring.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +143 -4
- package/dist/builtin/workflows/src/runs/background/quit.ts +61 -0
- package/dist/builtin/workflows/src/runs/background/status.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +74 -33
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +20 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +8 -7
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +1 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +19 -2
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +10 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +5 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-send-user-message.ts +25 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +16 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +20 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +23 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +30 -1
- package/dist/builtin/workflows/src/shared/store-public-types.ts +6 -2
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +12 -6
- package/dist/builtin/workflows/src/shared/types.ts +55 -0
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +11 -10
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -1
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +41 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +82 -24
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -0
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +22 -2
- package/dist/builtin/workflows/src/tui/graph-view-types.ts +4 -5
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -11
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +9 -3
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +11 -2
- package/dist/builtin/workflows/src/tui/stage-chat-view-live-events.ts +35 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +51 -17
- package/dist/builtin/workflows/src/tui/stage-chat-view-status.ts +36 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +5 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -1
- package/dist/builtin/workflows/src/tui/status-list.ts +14 -2
- package/dist/builtin/workflows/src/tui/widget.ts +23 -8
- package/dist/builtin/workflows/src/tui/workflow-attach-pane-types.ts +5 -4
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +8 -8
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +151 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/config-self-update.d.ts.map +1 -1
- package/dist/config-self-update.js +3 -4
- package/dist/config-self-update.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -5
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts +1 -0
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +1 -0
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +23 -0
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -0
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +29 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +36 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +14 -2
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.js +50 -1
- package/dist/core/compaction/context-compaction-metrics.js.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.js +2 -0
- package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +1 -1
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-application.js +5 -5
- package/dist/core/compaction/context-deletion-application.js.map +1 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +2 -0
- package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-targets.js +23 -3
- package/dist/core/compaction/context-deletion-targets.js.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +6 -0
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +1 -1
- package/dist/core/compaction/context-deletion-tools.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tools.js +18 -10
- package/dist/core/compaction/context-deletion-tools.js.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.js +2 -4
- package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.js +2 -60
- package/dist/core/copilot-gemini-tool-arguments.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +2 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.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-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +57 -32
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +11 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/tool-events.d.ts +13 -13
- package/dist/core/extensions/tool-events.d.ts.map +1 -1
- package/dist/core/extensions/tool-events.js +3 -3
- package/dist/core/extensions/tool-events.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/flattened-tool-arguments.d.ts +18 -0
- package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
- package/dist/core/flattened-tool-arguments.js +104 -0
- package/dist/core/flattened-tool-arguments.js.map +1 -1
- package/dist/core/messages.d.ts +1 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +46 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-exports.js +1 -1
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +12 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +15 -7
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +20 -9
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +2 -2
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +9 -3
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -1
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-list.d.ts +3 -3
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +27 -8
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +3 -1
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +55 -12
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/session-manager-tool-dependencies.d.ts +10 -0
- package/dist/core/session-manager-tool-dependencies.d.ts.map +1 -0
- package/dist/core/session-manager-tool-dependencies.js +133 -0
- package/dist/core/session-manager-tool-dependencies.js.map +1 -0
- package/dist/core/session-manager-types.d.ts +22 -0
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +4 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +18 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +4 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +15 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +11 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.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/tools/artifact-protocol.d.ts +11 -0
- package/dist/core/tools/artifact-protocol.d.ts.map +1 -0
- package/dist/core/tools/artifact-protocol.js +76 -0
- package/dist/core/tools/artifact-protocol.js.map +1 -0
- package/dist/core/tools/artifacts.d.ts +18 -0
- package/dist/core/tools/artifacts.d.ts.map +1 -0
- package/dist/core/tools/artifacts.js +90 -0
- package/dist/core/tools/artifacts.js.map +1 -0
- package/dist/core/tools/bash-async-jobs.d.ts +20 -0
- package/dist/core/tools/bash-async-jobs.d.ts.map +1 -0
- package/dist/core/tools/bash-async-jobs.js +59 -0
- package/dist/core/tools/bash-async-jobs.js.map +1 -0
- package/dist/core/tools/bash-async-output.d.ts +10 -0
- package/dist/core/tools/bash-async-output.d.ts.map +1 -0
- package/dist/core/tools/bash-async-output.js +80 -0
- package/dist/core/tools/bash-async-output.js.map +1 -0
- package/dist/core/tools/bash-interceptor.d.ts +10 -0
- package/dist/core/tools/bash-interceptor.d.ts.map +1 -0
- package/dist/core/tools/bash-interceptor.js +39 -0
- package/dist/core/tools/bash-interceptor.js.map +1 -0
- package/dist/core/tools/bash-leading-cd.d.ts +7 -0
- package/dist/core/tools/bash-leading-cd.d.ts.map +1 -0
- package/dist/core/tools/bash-leading-cd.js +59 -0
- package/dist/core/tools/bash-leading-cd.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +14 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -0
- package/dist/core/tools/bash-pty-native.js +71 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -0
- package/dist/core/tools/bash.d.ts +28 -17
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +152 -35
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/block-resolver.d.ts +16 -0
- package/dist/core/tools/block-resolver.d.ts.map +1 -0
- package/dist/core/tools/block-resolver.js +74 -0
- package/dist/core/tools/block-resolver.js.map +1 -0
- package/dist/core/tools/conflict-registry.d.ts +16 -0
- package/dist/core/tools/conflict-registry.d.ts.map +1 -0
- package/dist/core/tools/conflict-registry.js +44 -0
- package/dist/core/tools/conflict-registry.js.map +1 -0
- package/dist/core/tools/directory-tree.d.ts +13 -0
- package/dist/core/tools/directory-tree.d.ts.map +1 -0
- package/dist/core/tools/directory-tree.js +81 -0
- package/dist/core/tools/directory-tree.js.map +1 -0
- package/dist/core/tools/edit.d.ts +4 -29
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +136 -228
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/fetch-url.d.ts +74 -0
- package/dist/core/tools/fetch-url.d.ts.map +1 -0
- package/dist/core/tools/fetch-url.js +518 -0
- package/dist/core/tools/fetch-url.js.map +1 -0
- package/dist/core/tools/find.d.ts +27 -9
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +400 -176
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/glob-path-utils.d.ts +8 -0
- package/dist/core/tools/glob-path-utils.d.ts.map +1 -0
- package/dist/core/tools/glob-path-utils.js +26 -0
- package/dist/core/tools/glob-path-utils.js.map +1 -0
- package/dist/core/tools/grep.d.ts +12 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +141 -17
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hashline-engine/apply.d.ts +11 -0
- package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/apply.js +752 -0
- package/dist/core/tools/hashline-engine/apply.js.map +1 -0
- package/dist/core/tools/hashline-engine/block.d.ts +40 -0
- package/dist/core/tools/hashline-engine/block.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/block.js +117 -0
- package/dist/core/tools/hashline-engine/block.js.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts +15 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.js +98 -0
- package/dist/core/tools/hashline-engine/diff-preview.js.map +1 -0
- package/dist/core/tools/hashline-engine/format.d.ts +71 -0
- package/dist/core/tools/hashline-engine/format.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/format.js +178 -0
- package/dist/core/tools/hashline-engine/format.js.map +1 -0
- package/dist/core/tools/hashline-engine/fs.d.ts +81 -0
- package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/fs.js +143 -0
- package/dist/core/tools/hashline-engine/fs.js.map +1 -0
- package/dist/core/tools/hashline-engine/index.d.ts +18 -0
- package/dist/core/tools/hashline-engine/index.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/index.js +20 -0
- package/dist/core/tools/hashline-engine/index.js.map +1 -0
- package/dist/core/tools/hashline-engine/input.d.ts +101 -0
- package/dist/core/tools/hashline-engine/input.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/input.js +398 -0
- package/dist/core/tools/hashline-engine/input.js.map +1 -0
- package/dist/core/tools/hashline-engine/messages.d.ts +99 -0
- package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/messages.js +144 -0
- package/dist/core/tools/hashline-engine/messages.js.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts +45 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.js +90 -0
- package/dist/core/tools/hashline-engine/mismatch.js.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts +21 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.js +33 -0
- package/dist/core/tools/hashline-engine/normalize.js.map +1 -0
- package/dist/core/tools/hashline-engine/parser.d.ts +24 -0
- package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/parser.js +381 -0
- package/dist/core/tools/hashline-engine/parser.js.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts +118 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.js +341 -0
- package/dist/core/tools/hashline-engine/patcher.js.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts +43 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.js +135 -0
- package/dist/core/tools/hashline-engine/prefixes.js.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts +41 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.js +168 -0
- package/dist/core/tools/hashline-engine/recovery.js.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts +65 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.js +108 -0
- package/dist/core/tools/hashline-engine/snapshots.js.map +1 -0
- package/dist/core/tools/hashline-engine/stream.d.ts +3 -0
- package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/stream.js +111 -0
- package/dist/core/tools/hashline-engine/stream.js.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts +69 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.js +430 -0
- package/dist/core/tools/hashline-engine/tokenizer.js.map +1 -0
- package/dist/core/tools/hashline-engine/types.d.ts +166 -0
- package/dist/core/tools/hashline-engine/types.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/types.js +9 -0
- package/dist/core/tools/hashline-engine/types.js.map +1 -0
- package/dist/core/tools/hashline.d.ts +29 -0
- package/dist/core/tools/hashline.d.ts.map +1 -0
- package/dist/core/tools/hashline.js +110 -0
- package/dist/core/tools/hashline.js.map +1 -0
- package/dist/core/tools/index.d.ts +6 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +52 -35
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/notebook.d.ts +38 -0
- package/dist/core/tools/notebook.d.ts.map +1 -0
- package/dist/core/tools/notebook.js +125 -0
- package/dist/core/tools/notebook.js.map +1 -0
- package/dist/core/tools/read-document-extract.d.ts +9 -0
- package/dist/core/tools/read-document-extract.d.ts.map +1 -0
- package/dist/core/tools/read-document-extract.js +212 -0
- package/dist/core/tools/read-document-extract.js.map +1 -0
- package/dist/core/tools/read-selectors.d.ts +24 -0
- package/dist/core/tools/read-selectors.d.ts.map +1 -0
- package/dist/core/tools/read-selectors.js +277 -0
- package/dist/core/tools/read-selectors.js.map +1 -0
- package/dist/core/tools/read-url.d.ts +37 -0
- package/dist/core/tools/read-url.d.ts.map +1 -0
- package/dist/core/tools/read-url.js +39 -0
- package/dist/core/tools/read-url.js.map +1 -0
- package/dist/core/tools/read.d.ts +11 -11
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +224 -94
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts +44 -0
- package/dist/core/tools/resource-selectors.d.ts.map +1 -0
- package/dist/core/tools/resource-selectors.js +808 -0
- package/dist/core/tools/resource-selectors.js.map +1 -0
- package/dist/core/tools/search-details.d.ts +26 -0
- package/dist/core/tools/search-details.d.ts.map +1 -0
- package/dist/core/tools/search-details.js +24 -0
- package/dist/core/tools/search-details.js.map +1 -0
- package/dist/core/tools/search-line-ranges.d.ts +11 -0
- package/dist/core/tools/search-line-ranges.d.ts.map +1 -0
- package/dist/core/tools/search-line-ranges.js +65 -0
- package/dist/core/tools/search-line-ranges.js.map +1 -0
- package/dist/core/tools/search-native.d.ts +97 -0
- package/dist/core/tools/search-native.d.ts.map +1 -0
- package/dist/core/tools/search-native.js +27 -0
- package/dist/core/tools/search-native.js.map +1 -0
- package/dist/core/tools/search.d.ts +24 -0
- package/dist/core/tools/search.d.ts.map +1 -0
- package/dist/core/tools/search.js +573 -0
- package/dist/core/tools/search.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +4 -4
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +3 -3
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/url-ip-guards.d.ts +4 -0
- package/dist/core/tools/url-ip-guards.d.ts.map +1 -0
- package/dist/core/tools/url-ip-guards.js +126 -0
- package/dist/core/tools/url-ip-guards.js.map +1 -0
- package/dist/core/tools/write.d.ts +12 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +166 -14
- 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 -3
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/index-extensions.d.ts +2 -2
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +1 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.js +12 -0
- package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts +4 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js +131 -0
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.js.map +1 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +7 -1
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.js +15 -4
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +9 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.js +3 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js +7 -0
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +26 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js +0 -5
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js +1 -0
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +80 -2
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +3 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +51 -0
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +5 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +12 -0
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.d.ts +11 -0
- package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-onboarding.js +220 -0
- package/dist/modes/interactive/interactive-onboarding.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +4 -0
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +6 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.js +9 -4
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +28 -0
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +21 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/markit.d.ts +8 -0
- package/dist/utils/markit.d.ts.map +1 -0
- package/dist/utils/markit.js +53 -0
- package/dist/utils/markit.js.map +1 -0
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -1
- package/dist/utils/paths.js.map +1 -1
- package/docs/compaction.md +18 -1
- package/docs/containerization.md +1 -1
- package/docs/docs.json +1 -0
- package/docs/extensions.md +25 -36
- package/docs/models.md +1 -1
- package/docs/providers.md +2 -1
- package/docs/quickstart.md +11 -6
- package/docs/sdk.md +5 -5
- package/docs/session-format.md +6 -0
- package/docs/sessions.md +6 -0
- package/docs/settings.md +7 -0
- package/docs/subagents.md +3 -2
- package/docs/tools.md +49 -0
- package/docs/usage.md +3 -3
- package/docs/workflows.md +112 -8
- package/examples/extensions/subagent/README.md +5 -5
- package/examples/extensions/subagent/agents/planner.md +1 -1
- package/examples/extensions/subagent/agents/reviewer.md +1 -1
- package/examples/extensions/subagent/agents/scout.md +2 -2
- package/examples/extensions/subagent/display.ts +3 -3
- package/examples/sdk/05-tools.ts +3 -3
- package/examples/sdk/README.md +1 -1
- package/package.json +5 -3
|
@@ -27,6 +27,7 @@ export declare class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike
|
|
|
27
27
|
isStreaming(): boolean;
|
|
28
28
|
isBashRunning(): boolean;
|
|
29
29
|
isEditingBashCommand(): boolean;
|
|
30
|
+
isCompacting(): boolean;
|
|
30
31
|
hasInputText(): boolean;
|
|
31
32
|
hasAnimationTick(): boolean;
|
|
32
33
|
bodyScrollFromBottom(): number;
|
|
@@ -35,6 +36,7 @@ export declare class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike
|
|
|
35
36
|
statusText(): string;
|
|
36
37
|
scrollToBottom(): void;
|
|
37
38
|
syncAnimationTick(): void;
|
|
39
|
+
clearBusyForTerminalWorkflowStage(): void;
|
|
38
40
|
dispose(): void;
|
|
39
41
|
restoreQueuedMessagesToEditor(): boolean;
|
|
40
42
|
private editorCallbacks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-session-host.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"chat-session-host.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AA+BpE,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACV,0BAA0B,EAC1B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AAEtC,qBAAa,eAAe,CAAC,WAAW,SAAS,uBAAuB,GAAG,KAAK,CAC9E,YAAW,SAAS,EAAE,SAAS;IAE/B,OAAO,UAAQ;IAEf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAE1D,YAAY,IAAI,EAAE,mBAAmB,CAAC,WAAW,CAAC,EAcjD;IAED,cAAc,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,IAAI,CAE9D;IAED,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUrD;IAED,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAEzC;IAED,OAAO,IAAI,SAAS,oBAAoB,CAAC,WAAW,CAAC,EAAE,CAEtD;IAED,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEjD;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9B;IAED,UAAU,IAAI,IAAI,CAIjB;IAED,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAElD;IAED,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7C;IAED,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3C;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEnC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEpC;IAED,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvC;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjC;IAEK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAEK,MAAM,CAAC,IAAI,GAAE,MAAM,GAAG,UAAmB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;IAED,WAAW,IAAI,OAAO,CAErB;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,oBAAoB,IAAI,OAAO,CAE9B;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,YAAY,IAAI,OAAO,CAEtB;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,oBAAoB,IAAI,MAAM,CAE7B;IAED,aAAa,IAAI,MAAM,CAEtB;IAED,SAAS,IAAI,MAAM,CAElB;IAED,UAAU,IAAI,MAAM,CAEnB;IAED,cAAc,IAAI,IAAI,CAErB;IAED,iBAAiB,IAAI,IAAI,CAExB;IAED,iCAAiC,IAAI,IAAI,CAExC;IAED,OAAO,IAAI,IAAI,CAEd;IAED,6BAA6B,IAAI,OAAO,CAEvC;IAED,OAAO,CAAC,eAAe;CAexB","sourcesContent":["import type { AgentSessionEvent } from \"../../../core/agent-session.ts\";\nimport { type Component, type Focusable } from \"@earendil-works/pi-tui\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport {\n abortChatSessionBash,\n abortChatSessionCompaction,\n interruptChatSession,\n restoreQueuedMessagesToEditor,\n submitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n createChatSessionEditor,\n handleChatSessionInput,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent } from \"./chat-session-host-events.ts\";\nimport {\n renderChatSessionBody,\n renderChatSessionEditor,\n renderChatSessionEntry,\n renderChatSessionFooter,\n renderChatSessionPendingMessages,\n renderChatSessionUsage,\n renderChatSessionWorkingStatus,\n transcriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n clearChatSessionBusyForTerminalWorkflowStage,\n disposeChatSession,\n isChatSessionBashRunning,\n isChatSessionStreaming,\n syncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n AgentSnapshotMessage,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n} from \"./chat-session-host-types.ts\";\n\nexport type {\n ChatSessionHostBashRequest,\n ChatSessionHostCommands,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n ChatSessionHostStyle,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never>\n implements Component, Focusable\n{\n focused = true;\n\n private readonly state: ChatSessionHostState<TExtraEntry>;\n\n constructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n this.state = new ChatSessionHostState(opts, {\n renderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n transcriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n });\n this.state.editor = createChatSessionEditor(\n this.state,\n opts.tui,\n opts.keybindings,\n opts.editorTheme,\n opts.editorFactory,\n this.editorCallbacks(),\n );\n this.syncAnimationTick();\n }\n\n appendMessages(messages: readonly AgentSnapshotMessage[]): void {\n this.state.liveChat.appendMessages(messages);\n }\n\n loadSessionFile(sessionFile: string | undefined): void {\n if (this.state.transcript.length > 0 || sessionFile === undefined) return;\n let messages: readonly AgentSnapshotMessage[];\n try {\n messages = SessionManager.open(sessionFile).buildSessionContext()\n .messages as readonly AgentSnapshotMessage[];\n } catch {\n return;\n }\n this.state.liveChat.appendMessages(messages);\n }\n\n appendExtraEntry(entry: TExtraEntry): void {\n this.state.transcript.push(entry);\n }\n\n entries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n return this.state.transcript;\n }\n\n applyAgentEvent(event: AgentSessionEvent): boolean {\n return applyChatSessionAgentEvent(this.state, event);\n }\n\n render(width: number): string[] {\n return this.renderBody(width, 1);\n }\n\n invalidate(): void {\n this.state.transcriptComponent.invalidate();\n this.state.bodyViewport.invalidate();\n this.state.editor?.invalidate();\n }\n\n renderBody(width: number, budget: number): string[] {\n return renderChatSessionBody(this.state, width, budget);\n }\n\n renderPendingMessages(width: number): string[] {\n return renderChatSessionPendingMessages(this.state, width);\n }\n\n renderWorkingStatus(width: number): string[] {\n return renderChatSessionWorkingStatus(this.state, width);\n }\n\n renderUsage(width: number): string[] {\n return renderChatSessionUsage(this.state, width);\n }\n\n renderEditor(width: number): string[] {\n return renderChatSessionEditor(this.state, width, this.focused);\n }\n\n renderFooter(width: number): string[] {\n return renderChatSessionFooter(this.state, width);\n }\n\n handleScrollInput(data: string): boolean {\n return this.state.bodyViewport.handleInput(data);\n }\n\n handleInput(data: string): boolean {\n return handleChatSessionInput(this.state, data, this.editorCallbacks());\n }\n\n async interrupt(): Promise<void> {\n await interruptChatSession(this.state);\n }\n\n async submit(mode: \"auto\" | \"followUp\" = \"auto\", submittedText?: string): Promise<void> {\n await submitChatSession(this.state, mode, submittedText);\n }\n\n isStreaming(): boolean {\n return isChatSessionStreaming(this.state);\n }\n\n isBashRunning(): boolean {\n return isChatSessionBashRunning(this.state);\n }\n\n isEditingBashCommand(): boolean {\n return this.state.isBashMode;\n }\n\n isCompacting(): boolean {\n return this.state.compacting;\n }\n\n hasInputText(): boolean {\n return this.state.inputBuffer.length > 0;\n }\n\n hasAnimationTick(): boolean {\n return this.state.animationTimer !== undefined;\n }\n\n bodyScrollFromBottom(): number {\n return this.state.bodyViewport.getScrollFromBottom();\n }\n\n bodyMaxScroll(): number {\n return this.state.bodyViewport.getMaxScroll();\n }\n\n inputText(): string {\n return this.state.inputBuffer;\n }\n\n statusText(): string {\n return this.state.statusMessage;\n }\n\n scrollToBottom(): void {\n this.state.bodyViewport.scrollToBottom();\n }\n\n syncAnimationTick(): void {\n syncChatSessionAnimationTick(this.state);\n }\n\n clearBusyForTerminalWorkflowStage(): void {\n clearChatSessionBusyForTerminalWorkflowStage(this.state);\n }\n\n dispose(): void {\n disposeChatSession(this.state);\n }\n\n restoreQueuedMessagesToEditor(): boolean {\n return restoreQueuedMessagesToEditor(this.state);\n }\n\n private editorCallbacks(): {\n submit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n restoreQueuedMessagesToEditor: () => boolean;\n abortCompaction: () => void | Promise<void>;\n interrupt: () => void | Promise<void>;\n abortBash: () => void | Promise<void>;\n } {\n return {\n submit: (mode, submittedText) => this.submit(mode, submittedText),\n restoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n abortCompaction: () => abortChatSessionCompaction(this.state),\n interrupt: () => this.interrupt(),\n abortBash: () => abortChatSessionBash(this.state),\n };\n }\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { abortChatSessionBash, abortChatSessionCompaction, interruptChatSession,
|
|
|
3
3
|
import { createChatSessionEditor, handleChatSessionInput, } from "./chat-session-host-editor.js";
|
|
4
4
|
import { applyChatSessionAgentEvent } from "./chat-session-host-events.js";
|
|
5
5
|
import { renderChatSessionBody, renderChatSessionEditor, renderChatSessionEntry, renderChatSessionFooter, renderChatSessionPendingMessages, renderChatSessionUsage, renderChatSessionWorkingStatus, transcriptCacheKey, } from "./chat-session-host-rendering.js";
|
|
6
|
-
import { disposeChatSession, isChatSessionBashRunning, isChatSessionStreaming, syncChatSessionAnimationTick, } from "./chat-session-host-runtime.js";
|
|
6
|
+
import { clearChatSessionBusyForTerminalWorkflowStage, disposeChatSession, isChatSessionBashRunning, isChatSessionStreaming, syncChatSessionAnimationTick, } from "./chat-session-host-runtime.js";
|
|
7
7
|
import { ChatSessionHostState } from "./chat-session-host-state.js";
|
|
8
8
|
export class ChatSessionHost {
|
|
9
9
|
constructor(opts) {
|
|
@@ -87,6 +87,9 @@ export class ChatSessionHost {
|
|
|
87
87
|
isEditingBashCommand() {
|
|
88
88
|
return this.state.isBashMode;
|
|
89
89
|
}
|
|
90
|
+
isCompacting() {
|
|
91
|
+
return this.state.compacting;
|
|
92
|
+
}
|
|
90
93
|
hasInputText() {
|
|
91
94
|
return this.state.inputBuffer.length > 0;
|
|
92
95
|
}
|
|
@@ -111,6 +114,9 @@ export class ChatSessionHost {
|
|
|
111
114
|
syncAnimationTick() {
|
|
112
115
|
syncChatSessionAnimationTick(this.state);
|
|
113
116
|
}
|
|
117
|
+
clearBusyForTerminalWorkflowStage() {
|
|
118
|
+
clearChatSessionBusyForTerminalWorkflowStage(this.state);
|
|
119
|
+
}
|
|
114
120
|
dispose() {
|
|
115
121
|
disposeChatSession(this.state);
|
|
116
122
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-session-host.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAElE,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,6BAA6B,EAC7B,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAepE,MAAM,OAAO,eAAe;IAO1B,YAAY,IAAsC;QAJlD,YAAO,GAAG,IAAI,CAAC;QAKb,IAAI,CAAC,KAAK,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE;YAC1C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC;YACnE,kBAAkB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;SACrF,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,uBAAuB,CACzC,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,GAAG,EACR,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,eAAe,EAAE,CACvB,CAAC;QACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED,cAAc,CAAC,QAAyC;QACtD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,eAAe,CAAC,WAA+B;QAC7C,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO;QAC1E,IAAI,QAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,mBAAmB,EAAE;iBAC9D,QAA2C,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,gBAAgB,CAAC,KAAkB;QACjC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,eAAe,CAAC,KAAwB;QACtC,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,UAAU,CAAC,KAAa,EAAE,MAAc;QACtC,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;IAED,qBAAqB,CAAC,KAAa;QACjC,OAAO,gCAAgC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,mBAAmB,CAAC,KAAa;QAC/B,OAAO,8BAA8B,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,iBAAiB,CAAC,IAAY;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAI,GAAwB,MAAM,EAAE,aAAsB;QACrE,MAAM,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW;QACT,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa;QACX,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC;IACjD,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;IACvD,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;IAChD,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;IAClC,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;IAED,iBAAiB;QACf,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO;QACL,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,6BAA6B;QAC3B,OAAO,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC;IAEO,eAAe;QAOrB,OAAO;YACL,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;YACjE,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACzE,eAAe,EAAE,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;YAC7D,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE;YACjC,SAAS,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;SAClD,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type { AgentSessionEvent } from \"../../../core/agent-session.ts\";\nimport { type Component, type Focusable } from \"@earendil-works/pi-tui\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport {\n abortChatSessionBash,\n abortChatSessionCompaction,\n interruptChatSession,\n restoreQueuedMessagesToEditor,\n submitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n createChatSessionEditor,\n handleChatSessionInput,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent } from \"./chat-session-host-events.ts\";\nimport {\n renderChatSessionBody,\n renderChatSessionEditor,\n renderChatSessionEntry,\n renderChatSessionFooter,\n renderChatSessionPendingMessages,\n renderChatSessionUsage,\n renderChatSessionWorkingStatus,\n transcriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n disposeChatSession,\n isChatSessionBashRunning,\n isChatSessionStreaming,\n syncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n AgentSnapshotMessage,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n} from \"./chat-session-host-types.ts\";\n\nexport type {\n ChatSessionHostBashRequest,\n ChatSessionHostCommands,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n ChatSessionHostStyle,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never>\n implements Component, Focusable\n{\n focused = true;\n\n private readonly state: ChatSessionHostState<TExtraEntry>;\n\n constructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n this.state = new ChatSessionHostState(opts, {\n renderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n transcriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n });\n this.state.editor = createChatSessionEditor(\n this.state,\n opts.tui,\n opts.keybindings,\n opts.editorTheme,\n opts.editorFactory,\n this.editorCallbacks(),\n );\n this.syncAnimationTick();\n }\n\n appendMessages(messages: readonly AgentSnapshotMessage[]): void {\n this.state.liveChat.appendMessages(messages);\n }\n\n loadSessionFile(sessionFile: string | undefined): void {\n if (this.state.transcript.length > 0 || sessionFile === undefined) return;\n let messages: readonly AgentSnapshotMessage[];\n try {\n messages = SessionManager.open(sessionFile).buildSessionContext()\n .messages as readonly AgentSnapshotMessage[];\n } catch {\n return;\n }\n this.state.liveChat.appendMessages(messages);\n }\n\n appendExtraEntry(entry: TExtraEntry): void {\n this.state.transcript.push(entry);\n }\n\n entries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n return this.state.transcript;\n }\n\n applyAgentEvent(event: AgentSessionEvent): boolean {\n return applyChatSessionAgentEvent(this.state, event);\n }\n\n render(width: number): string[] {\n return this.renderBody(width, 1);\n }\n\n invalidate(): void {\n this.state.transcriptComponent.invalidate();\n this.state.bodyViewport.invalidate();\n this.state.editor?.invalidate();\n }\n\n renderBody(width: number, budget: number): string[] {\n return renderChatSessionBody(this.state, width, budget);\n }\n\n renderPendingMessages(width: number): string[] {\n return renderChatSessionPendingMessages(this.state, width);\n }\n\n renderWorkingStatus(width: number): string[] {\n return renderChatSessionWorkingStatus(this.state, width);\n }\n\n renderUsage(width: number): string[] {\n return renderChatSessionUsage(this.state, width);\n }\n\n renderEditor(width: number): string[] {\n return renderChatSessionEditor(this.state, width, this.focused);\n }\n\n renderFooter(width: number): string[] {\n return renderChatSessionFooter(this.state, width);\n }\n\n handleScrollInput(data: string): boolean {\n return this.state.bodyViewport.handleInput(data);\n }\n\n handleInput(data: string): boolean {\n return handleChatSessionInput(this.state, data, this.editorCallbacks());\n }\n\n async interrupt(): Promise<void> {\n await interruptChatSession(this.state);\n }\n\n async submit(mode: \"auto\" | \"followUp\" = \"auto\", submittedText?: string): Promise<void> {\n await submitChatSession(this.state, mode, submittedText);\n }\n\n isStreaming(): boolean {\n return isChatSessionStreaming(this.state);\n }\n\n isBashRunning(): boolean {\n return isChatSessionBashRunning(this.state);\n }\n\n isEditingBashCommand(): boolean {\n return this.state.isBashMode;\n }\n\n hasInputText(): boolean {\n return this.state.inputBuffer.length > 0;\n }\n\n hasAnimationTick(): boolean {\n return this.state.animationTimer !== undefined;\n }\n\n bodyScrollFromBottom(): number {\n return this.state.bodyViewport.getScrollFromBottom();\n }\n\n bodyMaxScroll(): number {\n return this.state.bodyViewport.getMaxScroll();\n }\n\n inputText(): string {\n return this.state.inputBuffer;\n }\n\n statusText(): string {\n return this.state.statusMessage;\n }\n\n scrollToBottom(): void {\n this.state.bodyViewport.scrollToBottom();\n }\n\n syncAnimationTick(): void {\n syncChatSessionAnimationTick(this.state);\n }\n\n dispose(): void {\n disposeChatSession(this.state);\n }\n\n restoreQueuedMessagesToEditor(): boolean {\n return restoreQueuedMessagesToEditor(this.state);\n }\n\n private editorCallbacks(): {\n submit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n restoreQueuedMessagesToEditor: () => boolean;\n abortCompaction: () => void | Promise<void>;\n interrupt: () => void | Promise<void>;\n abortBash: () => void | Promise<void>;\n } {\n return {\n submit: (mode, submittedText) => this.submit(mode, submittedText),\n restoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n abortCompaction: () => abortChatSessionCompaction(this.state),\n interrupt: () => this.interrupt(),\n abortBash: () => abortChatSessionBash(this.state),\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-session-host.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-session-host.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAElE,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,6BAA6B,EAC7B,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,4CAA4C,EAC5C,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAepE,MAAM,OAAO,eAAe;IAO1B,YAAY,IAAsC;QAJlD,YAAO,GAAG,IAAI,CAAC;QAKb,IAAI,CAAC,KAAK,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE;YAC1C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC;YACnE,kBAAkB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;SACrF,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,uBAAuB,CACzC,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,GAAG,EACR,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,eAAe,EAAE,CACvB,CAAC;QACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED,cAAc,CAAC,QAAyC;QACtD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,eAAe,CAAC,WAA+B;QAC7C,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,KAAK,SAAS;YAAE,OAAO;QAC1E,IAAI,QAAyC,CAAC;QAC9C,IAAI,CAAC;YACH,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,mBAAmB,EAAE;iBAC9D,QAA2C,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,gBAAgB,CAAC,KAAkB;QACjC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,eAAe,CAAC,KAAwB;QACtC,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAClC,CAAC;IAED,UAAU,CAAC,KAAa,EAAE,MAAc;QACtC,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;IAED,qBAAqB,CAAC,KAAa;QACjC,OAAO,gCAAgC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,mBAAmB,CAAC,KAAa;QAC/B,OAAO,8BAA8B,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;IAED,YAAY,CAAC,KAAa;QACxB,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,iBAAiB,CAAC,IAAY;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAI,GAAwB,MAAM,EAAE,aAAsB;QACrE,MAAM,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW;QACT,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa;QACX,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC;IACjD,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;IACvD,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;IAChD,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;IAClC,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;IAED,iBAAiB;QACf,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,iCAAiC;QAC/B,4CAA4C,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO;QACL,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,6BAA6B;QAC3B,OAAO,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC;IAEO,eAAe;QAOrB,OAAO;YACL,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;YACjE,6BAA6B,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACzE,eAAe,EAAE,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;YAC7D,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE;YACjC,SAAS,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC;SAClD,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type { AgentSessionEvent } from \"../../../core/agent-session.ts\";\nimport { type Component, type Focusable } from \"@earendil-works/pi-tui\";\nimport { SessionManager } from \"../../../core/session-manager.ts\";\nimport type { ChatTranscriptEntryLike } from \"./chat-transcript.ts\";\nimport {\n abortChatSessionBash,\n abortChatSessionCompaction,\n interruptChatSession,\n restoreQueuedMessagesToEditor,\n submitChatSession,\n} from \"./chat-session-host-actions.ts\";\nimport {\n createChatSessionEditor,\n handleChatSessionInput,\n} from \"./chat-session-host-editor.ts\";\nimport { applyChatSessionAgentEvent } from \"./chat-session-host-events.ts\";\nimport {\n renderChatSessionBody,\n renderChatSessionEditor,\n renderChatSessionEntry,\n renderChatSessionFooter,\n renderChatSessionPendingMessages,\n renderChatSessionUsage,\n renderChatSessionWorkingStatus,\n transcriptCacheKey,\n} from \"./chat-session-host-rendering.ts\";\nimport {\n clearChatSessionBusyForTerminalWorkflowStage,\n disposeChatSession,\n isChatSessionBashRunning,\n isChatSessionStreaming,\n syncChatSessionAnimationTick,\n} from \"./chat-session-host-runtime.ts\";\nimport { ChatSessionHostState } from \"./chat-session-host-state.ts\";\nimport type {\n AgentSnapshotMessage,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n} from \"./chat-session-host-types.ts\";\n\nexport type {\n ChatSessionHostBashRequest,\n ChatSessionHostCommands,\n ChatSessionHostEntry,\n ChatSessionHostOpts,\n ChatSessionHostStyle,\n} from \"./chat-session-host-types.ts\";\n\nexport class ChatSessionHost<TExtraEntry extends ChatTranscriptEntryLike = never>\n implements Component, Focusable\n{\n focused = true;\n\n private readonly state: ChatSessionHostState<TExtraEntry>;\n\n constructor(opts: ChatSessionHostOpts<TExtraEntry>) {\n this.state = new ChatSessionHostState(opts, {\n renderEntry: (state, entry) => renderChatSessionEntry(state, entry),\n transcriptCacheKey: (state, entry, index) => transcriptCacheKey(state, entry, index),\n });\n this.state.editor = createChatSessionEditor(\n this.state,\n opts.tui,\n opts.keybindings,\n opts.editorTheme,\n opts.editorFactory,\n this.editorCallbacks(),\n );\n this.syncAnimationTick();\n }\n\n appendMessages(messages: readonly AgentSnapshotMessage[]): void {\n this.state.liveChat.appendMessages(messages);\n }\n\n loadSessionFile(sessionFile: string | undefined): void {\n if (this.state.transcript.length > 0 || sessionFile === undefined) return;\n let messages: readonly AgentSnapshotMessage[];\n try {\n messages = SessionManager.open(sessionFile).buildSessionContext()\n .messages as readonly AgentSnapshotMessage[];\n } catch {\n return;\n }\n this.state.liveChat.appendMessages(messages);\n }\n\n appendExtraEntry(entry: TExtraEntry): void {\n this.state.transcript.push(entry);\n }\n\n entries(): readonly ChatSessionHostEntry<TExtraEntry>[] {\n return this.state.transcript;\n }\n\n applyAgentEvent(event: AgentSessionEvent): boolean {\n return applyChatSessionAgentEvent(this.state, event);\n }\n\n render(width: number): string[] {\n return this.renderBody(width, 1);\n }\n\n invalidate(): void {\n this.state.transcriptComponent.invalidate();\n this.state.bodyViewport.invalidate();\n this.state.editor?.invalidate();\n }\n\n renderBody(width: number, budget: number): string[] {\n return renderChatSessionBody(this.state, width, budget);\n }\n\n renderPendingMessages(width: number): string[] {\n return renderChatSessionPendingMessages(this.state, width);\n }\n\n renderWorkingStatus(width: number): string[] {\n return renderChatSessionWorkingStatus(this.state, width);\n }\n\n renderUsage(width: number): string[] {\n return renderChatSessionUsage(this.state, width);\n }\n\n renderEditor(width: number): string[] {\n return renderChatSessionEditor(this.state, width, this.focused);\n }\n\n renderFooter(width: number): string[] {\n return renderChatSessionFooter(this.state, width);\n }\n\n handleScrollInput(data: string): boolean {\n return this.state.bodyViewport.handleInput(data);\n }\n\n handleInput(data: string): boolean {\n return handleChatSessionInput(this.state, data, this.editorCallbacks());\n }\n\n async interrupt(): Promise<void> {\n await interruptChatSession(this.state);\n }\n\n async submit(mode: \"auto\" | \"followUp\" = \"auto\", submittedText?: string): Promise<void> {\n await submitChatSession(this.state, mode, submittedText);\n }\n\n isStreaming(): boolean {\n return isChatSessionStreaming(this.state);\n }\n\n isBashRunning(): boolean {\n return isChatSessionBashRunning(this.state);\n }\n\n isEditingBashCommand(): boolean {\n return this.state.isBashMode;\n }\n\n isCompacting(): boolean {\n return this.state.compacting;\n }\n\n hasInputText(): boolean {\n return this.state.inputBuffer.length > 0;\n }\n\n hasAnimationTick(): boolean {\n return this.state.animationTimer !== undefined;\n }\n\n bodyScrollFromBottom(): number {\n return this.state.bodyViewport.getScrollFromBottom();\n }\n\n bodyMaxScroll(): number {\n return this.state.bodyViewport.getMaxScroll();\n }\n\n inputText(): string {\n return this.state.inputBuffer;\n }\n\n statusText(): string {\n return this.state.statusMessage;\n }\n\n scrollToBottom(): void {\n this.state.bodyViewport.scrollToBottom();\n }\n\n syncAnimationTick(): void {\n syncChatSessionAnimationTick(this.state);\n }\n\n clearBusyForTerminalWorkflowStage(): void {\n clearChatSessionBusyForTerminalWorkflowStage(this.state);\n }\n\n dispose(): void {\n disposeChatSession(this.state);\n }\n\n restoreQueuedMessagesToEditor(): boolean {\n return restoreQueuedMessagesToEditor(this.state);\n }\n\n private editorCallbacks(): {\n submit: (mode: \"auto\" | \"followUp\", submittedText?: string) => void | Promise<void>;\n restoreQueuedMessagesToEditor: () => boolean;\n abortCompaction: () => void | Promise<void>;\n interrupt: () => void | Promise<void>;\n abortBash: () => void | Promise<void>;\n } {\n return {\n submit: (mode, submittedText) => this.submit(mode, submittedText),\n restoreQueuedMessagesToEditor: () => this.restoreQueuedMessagesToEditor(),\n abortCompaction: () => abortChatSessionCompaction(this.state),\n interrupt: () => this.interrupt(),\n abortBash: () => abortChatSessionBash(this.state),\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-transcript.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n matchesKey,\n type Component,\n Container,\n Spacer,\n} from \"@earendil-works/pi-tui\";\n\n/**\n * Roles that participate in pi's chat spacing contract.\n *\n * Assistant turns own their leading whitespace internally, and tool rows attach\n * directly under the assistant/tool-call row they belong to. User-like rows get\n * one blank line when they are not the first row in the transcript.\n */\nexport type ChatTranscriptRole =\n | \"assistant\"\n | \"thinking\"\n | \"tool\"\n | \"user\"\n | \"custom\"\n | \"notice\"\n | \"system\"\n | \"summary\";\n\nexport interface ChatTranscriptEntryLike {\n readonly role: ChatTranscriptRole;\n}\n\nexport type ChatTranscriptRenderer<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n) => Component;\n\nexport type ChatTranscriptCacheKey<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n index: number,\n) => string;\n\ninterface CachedChatTranscriptBlock<TEntry extends ChatTranscriptEntryLike> {\n readonly entry: TEntry;\n readonly key: string;\n readonly width: number;\n readonly lines: readonly string[];\n}\n\ninterface RowWindowComponent extends Component {\n readonly supportsRowWindow: true;\n rowCount(width: number): number;\n renderRows(width: number, startRow: number, endRow: number): string[];\n}\n\ninterface WindowedComponentRows {\n readonly kind: \"windowed\";\n readonly component: RowWindowComponent;\n readonly rowCount: number;\n}\n\ninterface StaticComponentRows {\n readonly kind: \"static\";\n readonly lines: readonly string[];\n readonly rowCount: number;\n}\n\ntype ComponentRows = WindowedComponentRows | StaticComponentRows;\n\nexport function addChatTranscriptEntry(\n container: Container,\n component: Component,\n role: ChatTranscriptRole,\n): void {\n if (needsLeadingSpacer(role) && container.children.length > 0) {\n container.addChild(new Spacer(1));\n }\n container.addChild(component);\n}\n\nfunction needsLeadingSpacer(role: ChatTranscriptRole): boolean {\n return (\n role === \"user\" ||\n role === \"custom\" ||\n role === \"notice\" ||\n role === \"system\" ||\n role === \"summary\"\n );\n}\n\n/**\n * Reusable pi chat transcript scaffold for extension surfaces.\n *\n * This intentionally mirrors InteractiveMode.addMessageToChat spacing without\n * coupling consumers to a full AgentSession. Extension UIs can bring their own\n * message model while still rendering inside the same Container/Spacer rhythm\n * as the main chat.\n */\nexport class ChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly entries: readonly TEntry[];\n private readonly renderEntry: ChatTranscriptRenderer<TEntry>;\n readonly supportsRowWindow: boolean;\n\n private readonly cacheKey: ChatTranscriptCacheKey<TEntry> | undefined;\n private blockCache: Array<CachedChatTranscriptBlock<TEntry> | undefined> = [];\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n cacheKey?: ChatTranscriptCacheKey<TEntry>,\n ) {\n this.entries = entries;\n this.renderEntry = renderEntry;\n this.cacheKey = cacheKey;\n this.supportsRowWindow = cacheKey !== undefined;\n }\n\n render(width: number): string[] {\n if (!this.supportsRowWindow) return this.renderAllRows(width);\n return this.renderRows(width, 0, this.rowCount(width));\n }\n\n rowCount(width: number): number {\n if (!this.supportsRowWindow) return this.renderAllRows(width).length;\n this.ensureBlockCache(width);\n let count = 0;\n for (const block of this.blockCache) {\n if (block !== undefined) count += block.lines.length;\n }\n return count;\n }\n\n renderRows(width: number, startRow: number, endRow: number): string[] {\n const start = Math.max(0, Math.floor(startRow));\n const end = Math.max(start, Math.floor(endRow));\n if (end <= start) return [];\n if (!this.supportsRowWindow) return this.renderAllRows(width).slice(start, end);\n\n this.ensureBlockCache(width);\n const lines: string[] = [];\n let cursor = 0;\n for (let index = 0; index < this.entries.length; index += 1) {\n const block = this.blockCache[index];\n if (block === undefined) continue;\n const blockStart = cursor;\n const blockEnd = blockStart + block.lines.length;\n if (blockEnd > start && blockStart < end) {\n const localStart = Math.max(0, start - blockStart);\n const localEnd = Math.min(block.lines.length, end - blockStart);\n lines.push(...block.lines.slice(localStart, localEnd));\n }\n cursor = blockEnd;\n if (cursor >= end) break;\n }\n return lines;\n }\n\n invalidate(): void {\n this.blockCache = [];\n }\n\n private ensureBlockCache(width: number): void {\n if (this.blockCache.length > this.entries.length) {\n this.blockCache.length = this.entries.length;\n }\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry === undefined) continue;\n const key = this.cacheKey?.(entry, index) ?? `${index}:${entry.role}`;\n const cached = this.blockCache[index];\n if (\n cached !== undefined &&\n cached.entry === entry &&\n cached.key === key &&\n cached.width === width\n ) {\n continue;\n }\n this.blockCache[index] = {\n entry,\n key,\n width,\n lines: this.renderEntryBlock(entry, index, width),\n };\n }\n }\n\n private renderAllRows(width: number): string[] {\n const lines: string[] = [];\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry !== undefined) lines.push(...this.renderEntryBlock(entry, index, width));\n }\n return lines;\n }\n\n private renderEntryBlock(entry: TEntry, index: number, width: number): string[] {\n const lines: string[] = [];\n if (index > 0 && needsLeadingSpacer(entry.role)) lines.push(\"\");\n lines.push(...this.renderEntry(entry).render(width));\n return lines;\n }\n}\n\nconst DEFAULT_SCROLL_STEP_ROWS = 4;\n\n/**\n * Sticky-bottom, scrollable viewport for chat-like component stacks.\n *\n * Pi's main interactive chat gets terminal scrollback for free. Extension\n * overlays render into a fixed rectangle, so they need an explicit viewport\n * with the same sticky-bottom default plus keyboard and mouse history controls.\n */\nexport class ScrollableComponentViewport implements Component {\n private components: readonly Component[] = [];\n private visibleRows = 1;\n private scrollFromBottom = 0;\n private lastLineCount = 0;\n private lastWidth = 0;\n private maxScroll = 0;\n\n setComponents(components: readonly Component[]): void {\n this.components = components;\n }\n\n setVisibleRows(rows: number): void {\n this.visibleRows = Math.max(1, Math.floor(rows));\n this.clampScroll();\n }\n\n getScrollFromBottom(): number {\n return this.scrollFromBottom;\n }\n\n getMaxScroll(): number {\n return this.maxScroll;\n }\n\n scrollToBottom(): void {\n this.scrollFromBottom = 0;\n }\n\n scrollToTop(): void {\n this.scrollFromBottom = this.maxScroll;\n }\n\n scrollBy(deltaRows: number): void {\n // Positive deltas move toward newer content; negative deltas move up\n // into older history. Store the offset from the sticky bottom so new\n // streaming output can keep following when the offset is zero.\n this.scrollFromBottom -= deltaRows;\n this.clampScroll();\n }\n\n handleInput(data: string): boolean {\n const wheelDeltaRows = mouseWheelDeltaRows(data);\n if (wheelDeltaRows !== 0) {\n this.scrollBy(wheelDeltaRows);\n return true;\n }\n if (isMouseSequence(data)) return true;\n if (matchesKey(data, \"pageUp\")) {\n this.scrollBy(-this.pageSize());\n return true;\n }\n if (matchesKey(data, \"pageDown\")) {\n this.scrollBy(this.pageSize());\n return true;\n }\n if (matchesKey(data, \"home\")) {\n this.scrollToTop();\n return true;\n }\n if (matchesKey(data, \"end\")) {\n this.scrollToBottom();\n return true;\n }\n return false;\n }\n\n render(width: number): string[] {\n const componentRows = this.measureComponentRows(width);\n const lineCount = componentRows.reduce((sum, rows) => sum + rows.rowCount, 0);\n const maxScroll = Math.max(0, lineCount - this.visibleRows);\n if (this.scrollFromBottom > 0 && this.lastWidth === width && lineCount > this.lastLineCount) {\n this.scrollFromBottom += lineCount - this.lastLineCount;\n }\n this.lastLineCount = lineCount;\n this.lastWidth = width;\n this.maxScroll = maxScroll;\n this.clampScroll();\n\n const start = Math.max(0, maxScroll - this.scrollFromBottom);\n const visible = this.renderVisibleRows(\n componentRows,\n width,\n start,\n start + this.visibleRows,\n );\n while (visible.length < this.visibleRows) visible.push(\" \".repeat(width));\n return visible;\n }\n\n invalidate(): void {\n for (const component of this.components) component.invalidate();\n }\n\n private measureComponentRows(width: number): ComponentRows[] {\n return this.components.map((component) => {\n if (isRowWindowComponent(component)) {\n return {\n kind: \"windowed\",\n component,\n rowCount: component.rowCount(width),\n };\n }\n const lines = component.render(width);\n return {\n kind: \"static\",\n lines,\n rowCount: lines.length,\n };\n });\n }\n\n private renderVisibleRows(\n componentRows: readonly ComponentRows[],\n width: number,\n startRow: number,\n endRow: number,\n ): string[] {\n const lines: string[] = [];\n let cursor = 0;\n for (const rows of componentRows) {\n const componentStart = cursor;\n const componentEnd = componentStart + rows.rowCount;\n if (componentEnd > startRow && componentStart < endRow) {\n const localStart = Math.max(0, startRow - componentStart);\n const localEnd = Math.min(rows.rowCount, endRow - componentStart);\n if (rows.kind === \"windowed\") {\n lines.push(...rows.component.renderRows(width, localStart, localEnd));\n } else {\n lines.push(...rows.lines.slice(localStart, localEnd));\n }\n }\n cursor = componentEnd;\n if (cursor >= endRow) break;\n }\n return lines;\n }\n\n private pageSize(): number {\n return Math.max(4, this.visibleRows - 2);\n }\n\n private clampScroll(): void {\n this.scrollFromBottom = Math.max(0, Math.min(this.maxScroll, this.scrollFromBottom));\n }\n}\n\nfunction isRowWindowComponent(component: Component): component is RowWindowComponent {\n const candidate = component as Partial<RowWindowComponent>;\n return candidate.supportsRowWindow === true &&\n typeof candidate.rowCount === \"function\" &&\n typeof candidate.renderRows === \"function\";\n}\n\nexport class ScrollableChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly viewport = new ScrollableComponentViewport();\n private readonly transcript: ChatTranscriptComponent<TEntry>;\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n ) {\n this.transcript = new ChatTranscriptComponent(entries, renderEntry);\n this.viewport.setComponents([this.transcript]);\n }\n\n setVisibleRows(rows: number): void {\n this.viewport.setVisibleRows(rows);\n }\n\n handleInput(data: string): boolean {\n return this.viewport.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.viewport.render(width);\n }\n\n invalidate(): void {\n this.viewport.invalidate();\n }\n\n getScrollFromBottom(): number {\n return this.viewport.getScrollFromBottom();\n }\n\n getMaxScroll(): number {\n return this.viewport.getMaxScroll();\n }\n\n scrollToBottom(): void {\n this.viewport.scrollToBottom();\n }\n}\n\nfunction mouseWheelDeltaRows(data: string): number {\n const sgr = data.match(/^\\x1b\\[<(\\d+);\\d+;\\d+M$/);\n if (sgr) return wheelDeltaForButtonCode(Number.parseInt(sgr[1]!, 10));\n if (data.startsWith(\"\\x1b[M\") && data.length >= 6) {\n return wheelDeltaForButtonCode(data.charCodeAt(3) - 32);\n }\n return 0;\n}\n\nfunction wheelDeltaForButtonCode(code: number): number {\n if ((code & 64) === 0) return 0;\n const direction = code & 3;\n if (direction === 0) return -DEFAULT_SCROLL_STEP_ROWS;\n if (direction === 1) return DEFAULT_SCROLL_STEP_ROWS;\n return 0;\n}\n\nfunction isMouseSequence(data: string): boolean {\n return /^\\x1b\\[<\\d+;\\d+;\\d+[mM]$/.test(data) || data.startsWith(\"\\x1b[M\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-transcript.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n matchesKey,\n type Component,\n Container,\n Spacer,\n} from \"@earendil-works/pi-tui\";\n\n/**\n * Roles that participate in pi's chat spacing contract.\n *\n * Assistant turns own their leading whitespace internally, and tool rows attach\n * directly under the assistant/tool-call row they belong to. User-like rows get\n * one blank line when they are not the first row in the transcript.\n */\nexport type ChatTranscriptRole =\n | \"assistant\"\n | \"thinking\"\n | \"tool\"\n | \"user\"\n | \"custom\"\n | \"notice\"\n | \"system\"\n | \"summary\";\n\nexport interface ChatTranscriptEntryLike {\n readonly role: ChatTranscriptRole;\n}\n\nexport type ChatTranscriptRenderer<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n) => Component;\n\nexport type ChatTranscriptCacheKey<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n index: number,\n) => string;\n\ninterface CachedChatTranscriptBlock<TEntry extends ChatTranscriptEntryLike> {\n readonly entry: TEntry;\n readonly key: string;\n readonly width: number;\n readonly component: Component;\n readonly lines: readonly string[];\n}\n\ntype DisposableComponent = Component & { dispose?: () => void };\n\ninterface RowWindowComponent extends Component {\n readonly supportsRowWindow: true;\n rowCount(width: number): number;\n renderRows(width: number, startRow: number, endRow: number): string[];\n}\n\ninterface WindowedComponentRows {\n readonly kind: \"windowed\";\n readonly component: RowWindowComponent;\n readonly rowCount: number;\n}\n\ninterface StaticComponentRows {\n readonly kind: \"static\";\n readonly lines: readonly string[];\n readonly rowCount: number;\n}\n\ntype ComponentRows = WindowedComponentRows | StaticComponentRows;\n\nexport function addChatTranscriptEntry(\n container: Container,\n component: Component,\n role: ChatTranscriptRole,\n): void {\n if (needsLeadingSpacer(role) && container.children.length > 0) {\n container.addChild(new Spacer(1));\n }\n container.addChild(component);\n}\n\nfunction needsLeadingSpacer(role: ChatTranscriptRole): boolean {\n return (\n role === \"user\" ||\n role === \"custom\" ||\n role === \"notice\" ||\n role === \"system\" ||\n role === \"summary\"\n );\n}\n\n/**\n * Reusable pi chat transcript scaffold for extension surfaces.\n *\n * This intentionally mirrors InteractiveMode.addMessageToChat spacing without\n * coupling consumers to a full AgentSession. Extension UIs can bring their own\n * message model while still rendering inside the same Container/Spacer rhythm\n * as the main chat.\n */\nexport class ChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly entries: readonly TEntry[];\n private readonly renderEntry: ChatTranscriptRenderer<TEntry>;\n readonly supportsRowWindow: boolean;\n\n private readonly cacheKey: ChatTranscriptCacheKey<TEntry> | undefined;\n private blockCache: Array<CachedChatTranscriptBlock<TEntry> | undefined> = [];\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n cacheKey?: ChatTranscriptCacheKey<TEntry>,\n ) {\n this.entries = entries;\n this.renderEntry = renderEntry;\n this.cacheKey = cacheKey;\n this.supportsRowWindow = cacheKey !== undefined;\n }\n\n render(width: number): string[] {\n if (!this.supportsRowWindow) return this.renderAllRows(width);\n return this.renderRows(width, 0, this.rowCount(width));\n }\n\n rowCount(width: number): number {\n if (!this.supportsRowWindow) return this.renderAllRows(width).length;\n this.ensureBlockCache(width);\n let count = 0;\n for (const block of this.blockCache) {\n if (block !== undefined) count += block.lines.length;\n }\n return count;\n }\n\n renderRows(width: number, startRow: number, endRow: number): string[] {\n const start = Math.max(0, Math.floor(startRow));\n const end = Math.max(start, Math.floor(endRow));\n if (end <= start) return [];\n if (!this.supportsRowWindow) return this.renderAllRows(width).slice(start, end);\n\n this.ensureBlockCache(width);\n const lines: string[] = [];\n let cursor = 0;\n for (let index = 0; index < this.entries.length; index += 1) {\n const block = this.blockCache[index];\n if (block === undefined) continue;\n const blockStart = cursor;\n const blockEnd = blockStart + block.lines.length;\n if (blockEnd > start && blockStart < end) {\n const localStart = Math.max(0, start - blockStart);\n const localEnd = Math.min(block.lines.length, end - blockStart);\n lines.push(...block.lines.slice(localStart, localEnd));\n }\n cursor = blockEnd;\n if (cursor >= end) break;\n }\n return lines;\n }\n\n invalidate(): void {\n for (const block of this.blockCache) disposeComponent(block?.component);\n this.blockCache = [];\n }\n\n private ensureBlockCache(width: number): void {\n if (this.blockCache.length > this.entries.length) {\n for (let index = this.entries.length; index < this.blockCache.length; index += 1) {\n disposeComponent(this.blockCache[index]?.component);\n }\n this.blockCache.length = this.entries.length;\n }\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry === undefined) continue;\n const key = this.cacheKey?.(entry, index) ?? `${index}:${entry.role}`;\n const cached = this.blockCache[index];\n if (\n cached !== undefined &&\n cached.entry === entry &&\n cached.key === key &&\n cached.width === width\n ) {\n continue;\n }\n disposeComponent(cached?.component);\n const component = this.renderEntry(entry);\n this.blockCache[index] = {\n entry,\n key,\n width,\n component,\n lines: this.renderEntryBlock(component, entry, index, width),\n };\n }\n }\n\n private renderAllRows(width: number): string[] {\n const lines: string[] = [];\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry !== undefined) lines.push(...this.renderEntryBlock(this.renderEntry(entry), entry, index, width));\n }\n return lines;\n }\n\n private renderEntryBlock(\n component: Component,\n entry: TEntry,\n index: number,\n width: number,\n ): string[] {\n const lines: string[] = [];\n if (index > 0 && needsLeadingSpacer(entry.role)) lines.push(\"\");\n lines.push(...component.render(width));\n return lines;\n }\n}\n\nfunction disposeComponent(component: Component | undefined): void {\n (component as DisposableComponent | undefined)?.dispose?.();\n}\n\nconst DEFAULT_SCROLL_STEP_ROWS = 4;\n\n/**\n * Sticky-bottom, scrollable viewport for chat-like component stacks.\n *\n * Pi's main interactive chat gets terminal scrollback for free. Extension\n * overlays render into a fixed rectangle, so they need an explicit viewport\n * with the same sticky-bottom default plus keyboard and mouse history controls.\n */\nexport class ScrollableComponentViewport implements Component {\n private components: readonly Component[] = [];\n private visibleRows = 1;\n private scrollFromBottom = 0;\n private lastLineCount = 0;\n private lastWidth = 0;\n private maxScroll = 0;\n\n setComponents(components: readonly Component[]): void {\n this.components = components;\n }\n\n setVisibleRows(rows: number): void {\n this.visibleRows = Math.max(1, Math.floor(rows));\n this.clampScroll();\n }\n\n getScrollFromBottom(): number {\n return this.scrollFromBottom;\n }\n\n getMaxScroll(): number {\n return this.maxScroll;\n }\n\n scrollToBottom(): void {\n this.scrollFromBottom = 0;\n }\n\n scrollToTop(): void {\n this.scrollFromBottom = this.maxScroll;\n }\n\n scrollBy(deltaRows: number): void {\n // Positive deltas move toward newer content; negative deltas move up\n // into older history. Store the offset from the sticky bottom so new\n // streaming output can keep following when the offset is zero.\n this.scrollFromBottom -= deltaRows;\n this.clampScroll();\n }\n\n handleInput(data: string): boolean {\n const wheelDeltaRows = mouseWheelDeltaRows(data);\n if (wheelDeltaRows !== 0) {\n this.scrollBy(wheelDeltaRows);\n return true;\n }\n if (isMouseSequence(data)) return true;\n if (matchesKey(data, \"pageUp\")) {\n this.scrollBy(-this.pageSize());\n return true;\n }\n if (matchesKey(data, \"pageDown\")) {\n this.scrollBy(this.pageSize());\n return true;\n }\n if (matchesKey(data, \"home\")) {\n this.scrollToTop();\n return true;\n }\n if (matchesKey(data, \"end\")) {\n this.scrollToBottom();\n return true;\n }\n return false;\n }\n\n render(width: number): string[] {\n const componentRows = this.measureComponentRows(width);\n const lineCount = componentRows.reduce((sum, rows) => sum + rows.rowCount, 0);\n const maxScroll = Math.max(0, lineCount - this.visibleRows);\n if (this.scrollFromBottom > 0 && this.lastWidth === width && lineCount > this.lastLineCount) {\n this.scrollFromBottom += lineCount - this.lastLineCount;\n }\n this.lastLineCount = lineCount;\n this.lastWidth = width;\n this.maxScroll = maxScroll;\n this.clampScroll();\n\n const start = Math.max(0, maxScroll - this.scrollFromBottom);\n const visible = this.renderVisibleRows(\n componentRows,\n width,\n start,\n start + this.visibleRows,\n );\n while (visible.length < this.visibleRows) visible.push(\" \".repeat(width));\n return visible;\n }\n\n invalidate(): void {\n for (const component of this.components) component.invalidate();\n }\n\n private measureComponentRows(width: number): ComponentRows[] {\n return this.components.map((component) => {\n if (isRowWindowComponent(component)) {\n return {\n kind: \"windowed\",\n component,\n rowCount: component.rowCount(width),\n };\n }\n const lines = component.render(width);\n return {\n kind: \"static\",\n lines,\n rowCount: lines.length,\n };\n });\n }\n\n private renderVisibleRows(\n componentRows: readonly ComponentRows[],\n width: number,\n startRow: number,\n endRow: number,\n ): string[] {\n const lines: string[] = [];\n let cursor = 0;\n for (const rows of componentRows) {\n const componentStart = cursor;\n const componentEnd = componentStart + rows.rowCount;\n if (componentEnd > startRow && componentStart < endRow) {\n const localStart = Math.max(0, startRow - componentStart);\n const localEnd = Math.min(rows.rowCount, endRow - componentStart);\n if (rows.kind === \"windowed\") {\n lines.push(...rows.component.renderRows(width, localStart, localEnd));\n } else {\n lines.push(...rows.lines.slice(localStart, localEnd));\n }\n }\n cursor = componentEnd;\n if (cursor >= endRow) break;\n }\n return lines;\n }\n\n private pageSize(): number {\n return Math.max(4, this.visibleRows - 2);\n }\n\n private clampScroll(): void {\n this.scrollFromBottom = Math.max(0, Math.min(this.maxScroll, this.scrollFromBottom));\n }\n}\n\nfunction isRowWindowComponent(component: Component): component is RowWindowComponent {\n const candidate = component as Partial<RowWindowComponent>;\n return candidate.supportsRowWindow === true &&\n typeof candidate.rowCount === \"function\" &&\n typeof candidate.renderRows === \"function\";\n}\n\nexport class ScrollableChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly viewport = new ScrollableComponentViewport();\n private readonly transcript: ChatTranscriptComponent<TEntry>;\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n ) {\n this.transcript = new ChatTranscriptComponent(entries, renderEntry);\n this.viewport.setComponents([this.transcript]);\n }\n\n setVisibleRows(rows: number): void {\n this.viewport.setVisibleRows(rows);\n }\n\n handleInput(data: string): boolean {\n return this.viewport.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.viewport.render(width);\n }\n\n invalidate(): void {\n this.viewport.invalidate();\n }\n\n getScrollFromBottom(): number {\n return this.viewport.getScrollFromBottom();\n }\n\n getMaxScroll(): number {\n return this.viewport.getMaxScroll();\n }\n\n scrollToBottom(): void {\n this.viewport.scrollToBottom();\n }\n}\n\nfunction mouseWheelDeltaRows(data: string): number {\n const sgr = data.match(/^\\x1b\\[<(\\d+);\\d+;\\d+M$/);\n if (sgr) return wheelDeltaForButtonCode(Number.parseInt(sgr[1]!, 10));\n if (data.startsWith(\"\\x1b[M\") && data.length >= 6) {\n return wheelDeltaForButtonCode(data.charCodeAt(3) - 32);\n }\n return 0;\n}\n\nfunction wheelDeltaForButtonCode(code: number): number {\n if ((code & 64) === 0) return 0;\n const direction = code & 3;\n if (direction === 0) return -DEFAULT_SCROLL_STEP_ROWS;\n if (direction === 1) return DEFAULT_SCROLL_STEP_ROWS;\n return 0;\n}\n\nfunction isMouseSequence(data: string): boolean {\n return /^\\x1b\\[<\\d+;\\d+;\\d+[mM]$/.test(data) || data.startsWith(\"\\x1b[M\");\n}\n"]}
|
|
@@ -72,10 +72,15 @@ export class ChatTranscriptComponent {
|
|
|
72
72
|
return lines;
|
|
73
73
|
}
|
|
74
74
|
invalidate() {
|
|
75
|
+
for (const block of this.blockCache)
|
|
76
|
+
disposeComponent(block?.component);
|
|
75
77
|
this.blockCache = [];
|
|
76
78
|
}
|
|
77
79
|
ensureBlockCache(width) {
|
|
78
80
|
if (this.blockCache.length > this.entries.length) {
|
|
81
|
+
for (let index = this.entries.length; index < this.blockCache.length; index += 1) {
|
|
82
|
+
disposeComponent(this.blockCache[index]?.component);
|
|
83
|
+
}
|
|
79
84
|
this.blockCache.length = this.entries.length;
|
|
80
85
|
}
|
|
81
86
|
for (let index = 0; index < this.entries.length; index += 1) {
|
|
@@ -90,11 +95,14 @@ export class ChatTranscriptComponent {
|
|
|
90
95
|
cached.width === width) {
|
|
91
96
|
continue;
|
|
92
97
|
}
|
|
98
|
+
disposeComponent(cached?.component);
|
|
99
|
+
const component = this.renderEntry(entry);
|
|
93
100
|
this.blockCache[index] = {
|
|
94
101
|
entry,
|
|
95
102
|
key,
|
|
96
103
|
width,
|
|
97
|
-
|
|
104
|
+
component,
|
|
105
|
+
lines: this.renderEntryBlock(component, entry, index, width),
|
|
98
106
|
};
|
|
99
107
|
}
|
|
100
108
|
}
|
|
@@ -103,18 +111,21 @@ export class ChatTranscriptComponent {
|
|
|
103
111
|
for (let index = 0; index < this.entries.length; index += 1) {
|
|
104
112
|
const entry = this.entries[index];
|
|
105
113
|
if (entry !== undefined)
|
|
106
|
-
lines.push(...this.renderEntryBlock(entry, index, width));
|
|
114
|
+
lines.push(...this.renderEntryBlock(this.renderEntry(entry), entry, index, width));
|
|
107
115
|
}
|
|
108
116
|
return lines;
|
|
109
117
|
}
|
|
110
|
-
renderEntryBlock(entry, index, width) {
|
|
118
|
+
renderEntryBlock(component, entry, index, width) {
|
|
111
119
|
const lines = [];
|
|
112
120
|
if (index > 0 && needsLeadingSpacer(entry.role))
|
|
113
121
|
lines.push("");
|
|
114
|
-
lines.push(...
|
|
122
|
+
lines.push(...component.render(width));
|
|
115
123
|
return lines;
|
|
116
124
|
}
|
|
117
125
|
}
|
|
126
|
+
function disposeComponent(component) {
|
|
127
|
+
component?.dispose?.();
|
|
128
|
+
}
|
|
118
129
|
const DEFAULT_SCROLL_STEP_ROWS = 4;
|
|
119
130
|
/**
|
|
120
131
|
* Sticky-bottom, scrollable viewport for chat-like component stacks.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-transcript.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n matchesKey,\n type Component,\n Container,\n Spacer,\n} from \"@earendil-works/pi-tui\";\n\n/**\n * Roles that participate in pi's chat spacing contract.\n *\n * Assistant turns own their leading whitespace internally, and tool rows attach\n * directly under the assistant/tool-call row they belong to. User-like rows get\n * one blank line when they are not the first row in the transcript.\n */\nexport type ChatTranscriptRole =\n | \"assistant\"\n | \"thinking\"\n | \"tool\"\n | \"user\"\n | \"custom\"\n | \"notice\"\n | \"system\"\n | \"summary\";\n\nexport interface ChatTranscriptEntryLike {\n readonly role: ChatTranscriptRole;\n}\n\nexport type ChatTranscriptRenderer<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n) => Component;\n\nexport type ChatTranscriptCacheKey<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n index: number,\n) => string;\n\ninterface CachedChatTranscriptBlock<TEntry extends ChatTranscriptEntryLike> {\n readonly entry: TEntry;\n readonly key: string;\n readonly width: number;\n readonly lines: readonly string[];\n}\n\ninterface RowWindowComponent extends Component {\n readonly supportsRowWindow: true;\n rowCount(width: number): number;\n renderRows(width: number, startRow: number, endRow: number): string[];\n}\n\ninterface WindowedComponentRows {\n readonly kind: \"windowed\";\n readonly component: RowWindowComponent;\n readonly rowCount: number;\n}\n\ninterface StaticComponentRows {\n readonly kind: \"static\";\n readonly lines: readonly string[];\n readonly rowCount: number;\n}\n\ntype ComponentRows = WindowedComponentRows | StaticComponentRows;\n\nexport function addChatTranscriptEntry(\n container: Container,\n component: Component,\n role: ChatTranscriptRole,\n): void {\n if (needsLeadingSpacer(role) && container.children.length > 0) {\n container.addChild(new Spacer(1));\n }\n container.addChild(component);\n}\n\nfunction needsLeadingSpacer(role: ChatTranscriptRole): boolean {\n return (\n role === \"user\" ||\n role === \"custom\" ||\n role === \"notice\" ||\n role === \"system\" ||\n role === \"summary\"\n );\n}\n\n/**\n * Reusable pi chat transcript scaffold for extension surfaces.\n *\n * This intentionally mirrors InteractiveMode.addMessageToChat spacing without\n * coupling consumers to a full AgentSession. Extension UIs can bring their own\n * message model while still rendering inside the same Container/Spacer rhythm\n * as the main chat.\n */\nexport class ChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly entries: readonly TEntry[];\n private readonly renderEntry: ChatTranscriptRenderer<TEntry>;\n readonly supportsRowWindow: boolean;\n\n private readonly cacheKey: ChatTranscriptCacheKey<TEntry> | undefined;\n private blockCache: Array<CachedChatTranscriptBlock<TEntry> | undefined> = [];\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n cacheKey?: ChatTranscriptCacheKey<TEntry>,\n ) {\n this.entries = entries;\n this.renderEntry = renderEntry;\n this.cacheKey = cacheKey;\n this.supportsRowWindow = cacheKey !== undefined;\n }\n\n render(width: number): string[] {\n if (!this.supportsRowWindow) return this.renderAllRows(width);\n return this.renderRows(width, 0, this.rowCount(width));\n }\n\n rowCount(width: number): number {\n if (!this.supportsRowWindow) return this.renderAllRows(width).length;\n this.ensureBlockCache(width);\n let count = 0;\n for (const block of this.blockCache) {\n if (block !== undefined) count += block.lines.length;\n }\n return count;\n }\n\n renderRows(width: number, startRow: number, endRow: number): string[] {\n const start = Math.max(0, Math.floor(startRow));\n const end = Math.max(start, Math.floor(endRow));\n if (end <= start) return [];\n if (!this.supportsRowWindow) return this.renderAllRows(width).slice(start, end);\n\n this.ensureBlockCache(width);\n const lines: string[] = [];\n let cursor = 0;\n for (let index = 0; index < this.entries.length; index += 1) {\n const block = this.blockCache[index];\n if (block === undefined) continue;\n const blockStart = cursor;\n const blockEnd = blockStart + block.lines.length;\n if (blockEnd > start && blockStart < end) {\n const localStart = Math.max(0, start - blockStart);\n const localEnd = Math.min(block.lines.length, end - blockStart);\n lines.push(...block.lines.slice(localStart, localEnd));\n }\n cursor = blockEnd;\n if (cursor >= end) break;\n }\n return lines;\n }\n\n invalidate(): void {\n this.blockCache = [];\n }\n\n private ensureBlockCache(width: number): void {\n if (this.blockCache.length > this.entries.length) {\n this.blockCache.length = this.entries.length;\n }\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry === undefined) continue;\n const key = this.cacheKey?.(entry, index) ?? `${index}:${entry.role}`;\n const cached = this.blockCache[index];\n if (\n cached !== undefined &&\n cached.entry === entry &&\n cached.key === key &&\n cached.width === width\n ) {\n continue;\n }\n this.blockCache[index] = {\n entry,\n key,\n width,\n lines: this.renderEntryBlock(entry, index, width),\n };\n }\n }\n\n private renderAllRows(width: number): string[] {\n const lines: string[] = [];\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry !== undefined) lines.push(...this.renderEntryBlock(entry, index, width));\n }\n return lines;\n }\n\n private renderEntryBlock(entry: TEntry, index: number, width: number): string[] {\n const lines: string[] = [];\n if (index > 0 && needsLeadingSpacer(entry.role)) lines.push(\"\");\n lines.push(...this.renderEntry(entry).render(width));\n return lines;\n }\n}\n\nconst DEFAULT_SCROLL_STEP_ROWS = 4;\n\n/**\n * Sticky-bottom, scrollable viewport for chat-like component stacks.\n *\n * Pi's main interactive chat gets terminal scrollback for free. Extension\n * overlays render into a fixed rectangle, so they need an explicit viewport\n * with the same sticky-bottom default plus keyboard and mouse history controls.\n */\nexport class ScrollableComponentViewport implements Component {\n private components: readonly Component[] = [];\n private visibleRows = 1;\n private scrollFromBottom = 0;\n private lastLineCount = 0;\n private lastWidth = 0;\n private maxScroll = 0;\n\n setComponents(components: readonly Component[]): void {\n this.components = components;\n }\n\n setVisibleRows(rows: number): void {\n this.visibleRows = Math.max(1, Math.floor(rows));\n this.clampScroll();\n }\n\n getScrollFromBottom(): number {\n return this.scrollFromBottom;\n }\n\n getMaxScroll(): number {\n return this.maxScroll;\n }\n\n scrollToBottom(): void {\n this.scrollFromBottom = 0;\n }\n\n scrollToTop(): void {\n this.scrollFromBottom = this.maxScroll;\n }\n\n scrollBy(deltaRows: number): void {\n // Positive deltas move toward newer content; negative deltas move up\n // into older history. Store the offset from the sticky bottom so new\n // streaming output can keep following when the offset is zero.\n this.scrollFromBottom -= deltaRows;\n this.clampScroll();\n }\n\n handleInput(data: string): boolean {\n const wheelDeltaRows = mouseWheelDeltaRows(data);\n if (wheelDeltaRows !== 0) {\n this.scrollBy(wheelDeltaRows);\n return true;\n }\n if (isMouseSequence(data)) return true;\n if (matchesKey(data, \"pageUp\")) {\n this.scrollBy(-this.pageSize());\n return true;\n }\n if (matchesKey(data, \"pageDown\")) {\n this.scrollBy(this.pageSize());\n return true;\n }\n if (matchesKey(data, \"home\")) {\n this.scrollToTop();\n return true;\n }\n if (matchesKey(data, \"end\")) {\n this.scrollToBottom();\n return true;\n }\n return false;\n }\n\n render(width: number): string[] {\n const componentRows = this.measureComponentRows(width);\n const lineCount = componentRows.reduce((sum, rows) => sum + rows.rowCount, 0);\n const maxScroll = Math.max(0, lineCount - this.visibleRows);\n if (this.scrollFromBottom > 0 && this.lastWidth === width && lineCount > this.lastLineCount) {\n this.scrollFromBottom += lineCount - this.lastLineCount;\n }\n this.lastLineCount = lineCount;\n this.lastWidth = width;\n this.maxScroll = maxScroll;\n this.clampScroll();\n\n const start = Math.max(0, maxScroll - this.scrollFromBottom);\n const visible = this.renderVisibleRows(\n componentRows,\n width,\n start,\n start + this.visibleRows,\n );\n while (visible.length < this.visibleRows) visible.push(\" \".repeat(width));\n return visible;\n }\n\n invalidate(): void {\n for (const component of this.components) component.invalidate();\n }\n\n private measureComponentRows(width: number): ComponentRows[] {\n return this.components.map((component) => {\n if (isRowWindowComponent(component)) {\n return {\n kind: \"windowed\",\n component,\n rowCount: component.rowCount(width),\n };\n }\n const lines = component.render(width);\n return {\n kind: \"static\",\n lines,\n rowCount: lines.length,\n };\n });\n }\n\n private renderVisibleRows(\n componentRows: readonly ComponentRows[],\n width: number,\n startRow: number,\n endRow: number,\n ): string[] {\n const lines: string[] = [];\n let cursor = 0;\n for (const rows of componentRows) {\n const componentStart = cursor;\n const componentEnd = componentStart + rows.rowCount;\n if (componentEnd > startRow && componentStart < endRow) {\n const localStart = Math.max(0, startRow - componentStart);\n const localEnd = Math.min(rows.rowCount, endRow - componentStart);\n if (rows.kind === \"windowed\") {\n lines.push(...rows.component.renderRows(width, localStart, localEnd));\n } else {\n lines.push(...rows.lines.slice(localStart, localEnd));\n }\n }\n cursor = componentEnd;\n if (cursor >= endRow) break;\n }\n return lines;\n }\n\n private pageSize(): number {\n return Math.max(4, this.visibleRows - 2);\n }\n\n private clampScroll(): void {\n this.scrollFromBottom = Math.max(0, Math.min(this.maxScroll, this.scrollFromBottom));\n }\n}\n\nfunction isRowWindowComponent(component: Component): component is RowWindowComponent {\n const candidate = component as Partial<RowWindowComponent>;\n return candidate.supportsRowWindow === true &&\n typeof candidate.rowCount === \"function\" &&\n typeof candidate.renderRows === \"function\";\n}\n\nexport class ScrollableChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly viewport = new ScrollableComponentViewport();\n private readonly transcript: ChatTranscriptComponent<TEntry>;\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n ) {\n this.transcript = new ChatTranscriptComponent(entries, renderEntry);\n this.viewport.setComponents([this.transcript]);\n }\n\n setVisibleRows(rows: number): void {\n this.viewport.setVisibleRows(rows);\n }\n\n handleInput(data: string): boolean {\n return this.viewport.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.viewport.render(width);\n }\n\n invalidate(): void {\n this.viewport.invalidate();\n }\n\n getScrollFromBottom(): number {\n return this.viewport.getScrollFromBottom();\n }\n\n getMaxScroll(): number {\n return this.viewport.getMaxScroll();\n }\n\n scrollToBottom(): void {\n this.viewport.scrollToBottom();\n }\n}\n\nfunction mouseWheelDeltaRows(data: string): number {\n const sgr = data.match(/^\\x1b\\[<(\\d+);\\d+;\\d+M$/);\n if (sgr) return wheelDeltaForButtonCode(Number.parseInt(sgr[1]!, 10));\n if (data.startsWith(\"\\x1b[M\") && data.length >= 6) {\n return wheelDeltaForButtonCode(data.charCodeAt(3) - 32);\n }\n return 0;\n}\n\nfunction wheelDeltaForButtonCode(code: number): number {\n if ((code & 64) === 0) return 0;\n const direction = code & 3;\n if (direction === 0) return -DEFAULT_SCROLL_STEP_ROWS;\n if (direction === 1) return DEFAULT_SCROLL_STEP_ROWS;\n return 0;\n}\n\nfunction isMouseSequence(data: string): boolean {\n return /^\\x1b\\[<\\d+;\\d+;\\d+[mM]$/.test(data) || data.startsWith(\"\\x1b[M\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"chat-transcript.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/chat-transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n matchesKey,\n type Component,\n Container,\n Spacer,\n} from \"@earendil-works/pi-tui\";\n\n/**\n * Roles that participate in pi's chat spacing contract.\n *\n * Assistant turns own their leading whitespace internally, and tool rows attach\n * directly under the assistant/tool-call row they belong to. User-like rows get\n * one blank line when they are not the first row in the transcript.\n */\nexport type ChatTranscriptRole =\n | \"assistant\"\n | \"thinking\"\n | \"tool\"\n | \"user\"\n | \"custom\"\n | \"notice\"\n | \"system\"\n | \"summary\";\n\nexport interface ChatTranscriptEntryLike {\n readonly role: ChatTranscriptRole;\n}\n\nexport type ChatTranscriptRenderer<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n) => Component;\n\nexport type ChatTranscriptCacheKey<TEntry extends ChatTranscriptEntryLike> = (\n entry: TEntry,\n index: number,\n) => string;\n\ninterface CachedChatTranscriptBlock<TEntry extends ChatTranscriptEntryLike> {\n readonly entry: TEntry;\n readonly key: string;\n readonly width: number;\n readonly component: Component;\n readonly lines: readonly string[];\n}\n\ntype DisposableComponent = Component & { dispose?: () => void };\n\ninterface RowWindowComponent extends Component {\n readonly supportsRowWindow: true;\n rowCount(width: number): number;\n renderRows(width: number, startRow: number, endRow: number): string[];\n}\n\ninterface WindowedComponentRows {\n readonly kind: \"windowed\";\n readonly component: RowWindowComponent;\n readonly rowCount: number;\n}\n\ninterface StaticComponentRows {\n readonly kind: \"static\";\n readonly lines: readonly string[];\n readonly rowCount: number;\n}\n\ntype ComponentRows = WindowedComponentRows | StaticComponentRows;\n\nexport function addChatTranscriptEntry(\n container: Container,\n component: Component,\n role: ChatTranscriptRole,\n): void {\n if (needsLeadingSpacer(role) && container.children.length > 0) {\n container.addChild(new Spacer(1));\n }\n container.addChild(component);\n}\n\nfunction needsLeadingSpacer(role: ChatTranscriptRole): boolean {\n return (\n role === \"user\" ||\n role === \"custom\" ||\n role === \"notice\" ||\n role === \"system\" ||\n role === \"summary\"\n );\n}\n\n/**\n * Reusable pi chat transcript scaffold for extension surfaces.\n *\n * This intentionally mirrors InteractiveMode.addMessageToChat spacing without\n * coupling consumers to a full AgentSession. Extension UIs can bring their own\n * message model while still rendering inside the same Container/Spacer rhythm\n * as the main chat.\n */\nexport class ChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly entries: readonly TEntry[];\n private readonly renderEntry: ChatTranscriptRenderer<TEntry>;\n readonly supportsRowWindow: boolean;\n\n private readonly cacheKey: ChatTranscriptCacheKey<TEntry> | undefined;\n private blockCache: Array<CachedChatTranscriptBlock<TEntry> | undefined> = [];\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n cacheKey?: ChatTranscriptCacheKey<TEntry>,\n ) {\n this.entries = entries;\n this.renderEntry = renderEntry;\n this.cacheKey = cacheKey;\n this.supportsRowWindow = cacheKey !== undefined;\n }\n\n render(width: number): string[] {\n if (!this.supportsRowWindow) return this.renderAllRows(width);\n return this.renderRows(width, 0, this.rowCount(width));\n }\n\n rowCount(width: number): number {\n if (!this.supportsRowWindow) return this.renderAllRows(width).length;\n this.ensureBlockCache(width);\n let count = 0;\n for (const block of this.blockCache) {\n if (block !== undefined) count += block.lines.length;\n }\n return count;\n }\n\n renderRows(width: number, startRow: number, endRow: number): string[] {\n const start = Math.max(0, Math.floor(startRow));\n const end = Math.max(start, Math.floor(endRow));\n if (end <= start) return [];\n if (!this.supportsRowWindow) return this.renderAllRows(width).slice(start, end);\n\n this.ensureBlockCache(width);\n const lines: string[] = [];\n let cursor = 0;\n for (let index = 0; index < this.entries.length; index += 1) {\n const block = this.blockCache[index];\n if (block === undefined) continue;\n const blockStart = cursor;\n const blockEnd = blockStart + block.lines.length;\n if (blockEnd > start && blockStart < end) {\n const localStart = Math.max(0, start - blockStart);\n const localEnd = Math.min(block.lines.length, end - blockStart);\n lines.push(...block.lines.slice(localStart, localEnd));\n }\n cursor = blockEnd;\n if (cursor >= end) break;\n }\n return lines;\n }\n\n invalidate(): void {\n for (const block of this.blockCache) disposeComponent(block?.component);\n this.blockCache = [];\n }\n\n private ensureBlockCache(width: number): void {\n if (this.blockCache.length > this.entries.length) {\n for (let index = this.entries.length; index < this.blockCache.length; index += 1) {\n disposeComponent(this.blockCache[index]?.component);\n }\n this.blockCache.length = this.entries.length;\n }\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry === undefined) continue;\n const key = this.cacheKey?.(entry, index) ?? `${index}:${entry.role}`;\n const cached = this.blockCache[index];\n if (\n cached !== undefined &&\n cached.entry === entry &&\n cached.key === key &&\n cached.width === width\n ) {\n continue;\n }\n disposeComponent(cached?.component);\n const component = this.renderEntry(entry);\n this.blockCache[index] = {\n entry,\n key,\n width,\n component,\n lines: this.renderEntryBlock(component, entry, index, width),\n };\n }\n }\n\n private renderAllRows(width: number): string[] {\n const lines: string[] = [];\n for (let index = 0; index < this.entries.length; index += 1) {\n const entry = this.entries[index];\n if (entry !== undefined) lines.push(...this.renderEntryBlock(this.renderEntry(entry), entry, index, width));\n }\n return lines;\n }\n\n private renderEntryBlock(\n component: Component,\n entry: TEntry,\n index: number,\n width: number,\n ): string[] {\n const lines: string[] = [];\n if (index > 0 && needsLeadingSpacer(entry.role)) lines.push(\"\");\n lines.push(...component.render(width));\n return lines;\n }\n}\n\nfunction disposeComponent(component: Component | undefined): void {\n (component as DisposableComponent | undefined)?.dispose?.();\n}\n\nconst DEFAULT_SCROLL_STEP_ROWS = 4;\n\n/**\n * Sticky-bottom, scrollable viewport for chat-like component stacks.\n *\n * Pi's main interactive chat gets terminal scrollback for free. Extension\n * overlays render into a fixed rectangle, so they need an explicit viewport\n * with the same sticky-bottom default plus keyboard and mouse history controls.\n */\nexport class ScrollableComponentViewport implements Component {\n private components: readonly Component[] = [];\n private visibleRows = 1;\n private scrollFromBottom = 0;\n private lastLineCount = 0;\n private lastWidth = 0;\n private maxScroll = 0;\n\n setComponents(components: readonly Component[]): void {\n this.components = components;\n }\n\n setVisibleRows(rows: number): void {\n this.visibleRows = Math.max(1, Math.floor(rows));\n this.clampScroll();\n }\n\n getScrollFromBottom(): number {\n return this.scrollFromBottom;\n }\n\n getMaxScroll(): number {\n return this.maxScroll;\n }\n\n scrollToBottom(): void {\n this.scrollFromBottom = 0;\n }\n\n scrollToTop(): void {\n this.scrollFromBottom = this.maxScroll;\n }\n\n scrollBy(deltaRows: number): void {\n // Positive deltas move toward newer content; negative deltas move up\n // into older history. Store the offset from the sticky bottom so new\n // streaming output can keep following when the offset is zero.\n this.scrollFromBottom -= deltaRows;\n this.clampScroll();\n }\n\n handleInput(data: string): boolean {\n const wheelDeltaRows = mouseWheelDeltaRows(data);\n if (wheelDeltaRows !== 0) {\n this.scrollBy(wheelDeltaRows);\n return true;\n }\n if (isMouseSequence(data)) return true;\n if (matchesKey(data, \"pageUp\")) {\n this.scrollBy(-this.pageSize());\n return true;\n }\n if (matchesKey(data, \"pageDown\")) {\n this.scrollBy(this.pageSize());\n return true;\n }\n if (matchesKey(data, \"home\")) {\n this.scrollToTop();\n return true;\n }\n if (matchesKey(data, \"end\")) {\n this.scrollToBottom();\n return true;\n }\n return false;\n }\n\n render(width: number): string[] {\n const componentRows = this.measureComponentRows(width);\n const lineCount = componentRows.reduce((sum, rows) => sum + rows.rowCount, 0);\n const maxScroll = Math.max(0, lineCount - this.visibleRows);\n if (this.scrollFromBottom > 0 && this.lastWidth === width && lineCount > this.lastLineCount) {\n this.scrollFromBottom += lineCount - this.lastLineCount;\n }\n this.lastLineCount = lineCount;\n this.lastWidth = width;\n this.maxScroll = maxScroll;\n this.clampScroll();\n\n const start = Math.max(0, maxScroll - this.scrollFromBottom);\n const visible = this.renderVisibleRows(\n componentRows,\n width,\n start,\n start + this.visibleRows,\n );\n while (visible.length < this.visibleRows) visible.push(\" \".repeat(width));\n return visible;\n }\n\n invalidate(): void {\n for (const component of this.components) component.invalidate();\n }\n\n private measureComponentRows(width: number): ComponentRows[] {\n return this.components.map((component) => {\n if (isRowWindowComponent(component)) {\n return {\n kind: \"windowed\",\n component,\n rowCount: component.rowCount(width),\n };\n }\n const lines = component.render(width);\n return {\n kind: \"static\",\n lines,\n rowCount: lines.length,\n };\n });\n }\n\n private renderVisibleRows(\n componentRows: readonly ComponentRows[],\n width: number,\n startRow: number,\n endRow: number,\n ): string[] {\n const lines: string[] = [];\n let cursor = 0;\n for (const rows of componentRows) {\n const componentStart = cursor;\n const componentEnd = componentStart + rows.rowCount;\n if (componentEnd > startRow && componentStart < endRow) {\n const localStart = Math.max(0, startRow - componentStart);\n const localEnd = Math.min(rows.rowCount, endRow - componentStart);\n if (rows.kind === \"windowed\") {\n lines.push(...rows.component.renderRows(width, localStart, localEnd));\n } else {\n lines.push(...rows.lines.slice(localStart, localEnd));\n }\n }\n cursor = componentEnd;\n if (cursor >= endRow) break;\n }\n return lines;\n }\n\n private pageSize(): number {\n return Math.max(4, this.visibleRows - 2);\n }\n\n private clampScroll(): void {\n this.scrollFromBottom = Math.max(0, Math.min(this.maxScroll, this.scrollFromBottom));\n }\n}\n\nfunction isRowWindowComponent(component: Component): component is RowWindowComponent {\n const candidate = component as Partial<RowWindowComponent>;\n return candidate.supportsRowWindow === true &&\n typeof candidate.rowCount === \"function\" &&\n typeof candidate.renderRows === \"function\";\n}\n\nexport class ScrollableChatTranscriptComponent<TEntry extends ChatTranscriptEntryLike>\n implements Component\n{\n private readonly viewport = new ScrollableComponentViewport();\n private readonly transcript: ChatTranscriptComponent<TEntry>;\n\n constructor(\n entries: readonly TEntry[],\n renderEntry: ChatTranscriptRenderer<TEntry>,\n ) {\n this.transcript = new ChatTranscriptComponent(entries, renderEntry);\n this.viewport.setComponents([this.transcript]);\n }\n\n setVisibleRows(rows: number): void {\n this.viewport.setVisibleRows(rows);\n }\n\n handleInput(data: string): boolean {\n return this.viewport.handleInput(data);\n }\n\n render(width: number): string[] {\n return this.viewport.render(width);\n }\n\n invalidate(): void {\n this.viewport.invalidate();\n }\n\n getScrollFromBottom(): number {\n return this.viewport.getScrollFromBottom();\n }\n\n getMaxScroll(): number {\n return this.viewport.getMaxScroll();\n }\n\n scrollToBottom(): void {\n this.viewport.scrollToBottom();\n }\n}\n\nfunction mouseWheelDeltaRows(data: string): number {\n const sgr = data.match(/^\\x1b\\[<(\\d+);\\d+;\\d+M$/);\n if (sgr) return wheelDeltaForButtonCode(Number.parseInt(sgr[1]!, 10));\n if (data.startsWith(\"\\x1b[M\") && data.length >= 6) {\n return wheelDeltaForButtonCode(data.charCodeAt(3) - 32);\n }\n return 0;\n}\n\nfunction wheelDeltaForButtonCode(code: number): number {\n if ((code & 64) === 0) return 0;\n const direction = code & 3;\n if (direction === 0) return -DEFAULT_SCROLL_STEP_ROWS;\n if (direction === 1) return DEFAULT_SCROLL_STEP_ROWS;\n return 0;\n}\n\nfunction isMouseSequence(data: string): boolean {\n return /^\\x1b\\[<\\d+;\\d+;\\d+[mM]$/.test(data) || data.startsWith(\"\\x1b[M\");\n}\n"]}
|
|
@@ -20,6 +20,7 @@ export declare class CustomEditor extends Editor {
|
|
|
20
20
|
constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions);
|
|
21
21
|
setPlaceholder(placeholder: string | (() => string) | undefined): void;
|
|
22
22
|
render(width: number): string[];
|
|
23
|
+
private renderPlaceholder;
|
|
23
24
|
private isEditorBorderLine;
|
|
24
25
|
private extendBorderLine;
|
|
25
26
|
private padLine;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"custom-editor.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,GAAG,EAAiC,MAAM,wBAAwB,CAAC;AAC9I,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGtF,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;CACtC;AAKD;;GAEG;AACH,qBAAa,YAAa,SAAQ,MAAM;IACvC,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAsC;IAClD,cAAc,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAa;IAG3D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,2EAA2E;IACpE,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAEvD,YAAY,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAKvG;IAED,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAErE;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC9B;IAED,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAQf;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAEzD;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiD9B;CACD","sourcesContent":["import { CURSOR_MARKER, Editor, type EditorOptions, type EditorTheme, type TUI, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface CustomEditorOptions extends EditorOptions {\n\tpromptPrefix?: string;\n\tplaceholder?: string | (() => string);\n}\n\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-?]*[ -/]*[@-~]|\\x1b\\][^\\x07]*(?:\\x07|\\x1b\\\\)|\\x1b[PX_][\\s\\S]*?\\x1b\\\\/g;\nconst BORDER_LINE_PATTERN = /^[─ ↑↓0-9more]+$/;\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate promptPrefix: string;\n\tprivate placeholder: string | (() => string) | undefined;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.promptPrefix = options?.promptPrefix ?? \"❯ \";\n\t\tthis.placeholder = options?.placeholder;\n\t}\n\n\tsetPlaceholder(placeholder: string | (() => string) | undefined): void {\n\t\tthis.placeholder = placeholder;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst promptWidth = visibleWidth(this.promptPrefix);\n\t\tif (promptWidth <= 0 || width <= promptWidth + 1) {\n\t\t\treturn super.render(width);\n\t\t}\n\n\t\tconst editorWidth = Math.max(1, width - promptWidth);\n\t\tconst lines = super.render(editorWidth);\n\t\tlet borderCount = 0;\n\t\tlet inPromptBox = false;\n\t\tlet promptShown = false;\n\n\t\tconst placeholder = typeof this.placeholder === \"function\" ? this.placeholder() : this.placeholder;\n\n\t\treturn lines.map((line) => {\n\t\t\tif (this.isEditorBorderLine(line)) {\n\t\t\t\tborderCount += 1;\n\t\t\t\tif (borderCount === 1) {\n\t\t\t\t\tinPromptBox = true;\n\t\t\t\t\tpromptShown = false;\n\t\t\t\t} else if (borderCount === 2) {\n\t\t\t\t\tinPromptBox = false;\n\t\t\t\t}\n\t\t\t\treturn this.extendBorderLine(line, width);\n\t\t\t}\n\n\t\t\tconst showPrompt = inPromptBox && !promptShown;\n\t\t\tconst prefix = showPrompt ? this.promptPrefix : \" \".repeat(promptWidth);\n\t\t\tlet content = line;\n\t\t\tif (showPrompt && placeholder && this.getText() === \"\") {\n\t\t\t\tcontent = this.renderPlaceholder(placeholder, editorWidth);\n\t\t\t}\n\t\t\tif (inPromptBox) {\n\t\t\t\tpromptShown = true;\n\t\t\t}\n\t\t\treturn this.padLine(`${prefix}${content}`, width);\n\t\t});\n\t}\n\n\tprivate renderPlaceholder(placeholder: string, editorWidth: number): string {\n\t\tconst cursor = `${this.focused ? CURSOR_MARKER : \"\"}\\x1b[7m \\x1b[0m`;\n\t\tconst placeholderWidth = Math.max(0, editorWidth - 1);\n\t\tconst text = truncateToWidth(placeholder, placeholderWidth, \"...\");\n\t\treturn `${cursor}${theme.fg(\"muted\", text)}`;\n\t}\n\n\tprivate isEditorBorderLine(line: string): boolean {\n\t\tconst plain = line.replace(ANSI_ESCAPE_PATTERN, \"\").trim();\n\t\treturn plain.includes(\"─\") && BORDER_LINE_PATTERN.test(plain);\n\t}\n\n\tprivate extendBorderLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${this.borderColor(\"─\".repeat(remainingWidth))}`;\n\t}\n\n\tprivate padLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${\" \".repeat(remainingWidth)}`;\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for paste image keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Editor, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
1
|
+
import { CURSOR_MARKER, Editor, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { theme } from "../theme/theme.js";
|
|
2
3
|
const ANSI_ESCAPE_PATTERN = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07]*(?:\x07|\x1b\\)|\x1b[PX_][\s\S]*?\x1b\\/g;
|
|
3
4
|
const BORDER_LINE_PATTERN = /^[─ ↑↓0-9more]+$/;
|
|
4
5
|
/**
|
|
@@ -42,7 +43,7 @@ export class CustomEditor extends Editor {
|
|
|
42
43
|
const prefix = showPrompt ? this.promptPrefix : " ".repeat(promptWidth);
|
|
43
44
|
let content = line;
|
|
44
45
|
if (showPrompt && placeholder && this.getText() === "") {
|
|
45
|
-
content =
|
|
46
|
+
content = this.renderPlaceholder(placeholder, editorWidth);
|
|
46
47
|
}
|
|
47
48
|
if (inPromptBox) {
|
|
48
49
|
promptShown = true;
|
|
@@ -50,6 +51,12 @@ export class CustomEditor extends Editor {
|
|
|
50
51
|
return this.padLine(`${prefix}${content}`, width);
|
|
51
52
|
});
|
|
52
53
|
}
|
|
54
|
+
renderPlaceholder(placeholder, editorWidth) {
|
|
55
|
+
const cursor = `${this.focused ? CURSOR_MARKER : ""}\x1b[7m \x1b[0m`;
|
|
56
|
+
const placeholderWidth = Math.max(0, editorWidth - 1);
|
|
57
|
+
const text = truncateToWidth(placeholder, placeholderWidth, "...");
|
|
58
|
+
return `${cursor}${theme.fg("muted", text)}`;
|
|
59
|
+
}
|
|
53
60
|
isEditorBorderLine(line) {
|
|
54
61
|
const plain = line.replace(ANSI_ESCAPE_PATTERN, "").trim();
|
|
55
62
|
return plain.includes("─") && BORDER_LINE_PATTERN.test(plain);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkD,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ/H,MAAM,mBAAmB,GAAG,gFAAgF,CAAC;AAC7G,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAE/C;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,MAAM;IAavC,YAAY,GAAQ,EAAE,KAAkB,EAAE,WAA+B,EAAE,OAA6B;QACvG,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAVrB,mBAAc,GAAmC,IAAI,GAAG,EAAE,CAAC;QAWjE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC;QAClD,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,WAAW,CAAC;IACzC,CAAC;IAED,cAAc,CAAC,WAAgD;QAC9D,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACpD,IAAI,WAAW,IAAI,CAAC,IAAI,KAAK,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YAClD,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,WAAW,GAAG,KAAK,CAAC;QAExB,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;QAEnG,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnC,WAAW,IAAI,CAAC,CAAC;gBACjB,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;oBACvB,WAAW,GAAG,IAAI,CAAC;oBACnB,WAAW,GAAG,KAAK,CAAC;gBACrB,CAAC;qBAAM,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;oBAC9B,WAAW,GAAG,KAAK,CAAC;gBACrB,CAAC;gBACD,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;YAED,MAAM,UAAU,GAAG,WAAW,IAAI,CAAC,WAAW,CAAC;YAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACxE,IAAI,OAAO,GAAG,IAAI,CAAC;YACnB,IAAI,UAAU,IAAI,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;gBACxD,OAAO,GAAG,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,WAAW,EAAE,CAAC;gBACjB,WAAW,GAAG,IAAI,CAAC;YACpB,CAAC;YACD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,kBAAkB,CAAC,IAAY;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC;IAEO,gBAAgB,CAAC,IAAY,EAAE,KAAa;QACnD,MAAM,cAAc,GAAG,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;IACjE,CAAC;IAEO,OAAO,CAAC,IAAY,EAAE,KAAa;QAC1C,MAAM,cAAc,GAAG,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAClD,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,OAAO,GAAG,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,MAAqB,EAAE,OAAmB;QAClD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,WAAW,CAAC,IAAY;QACvB,6CAA6C;QAC7C,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,OAAO;QACR,CAAC;QAED,mCAAmC;QACnC,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,0BAA0B,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACtB,OAAO;QACR,CAAC;QAED,8BAA8B;QAE9B,wDAAwD;QACxD,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;gBACnC,4DAA4D;gBAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBAC1E,IAAI,OAAO,EAAE,CAAC;oBACb,OAAO,EAAE,CAAC;oBACV,OAAO;gBACR,CAAC;YACF,CAAC;YACD,yDAAyD;YACzD,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACxB,OAAO;QACR,CAAC;QAED,4CAA4C;QAC5C,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpE,IAAI,OAAO;oBAAE,OAAO,EAAE,CAAC;gBACvB,OAAO;YACR,CAAC;YACD,yEAAyE;QAC1E,CAAC;QAED,8BAA8B;QAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACrD,IAAI,MAAM,KAAK,eAAe,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;gBACnG,OAAO,EAAE,CAAC;gBACV,OAAO;YACR,CAAC;QACF,CAAC;QAED,qCAAqC;QACrC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CACD","sourcesContent":["import { Editor, type EditorOptions, type EditorTheme, type TUI, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\n\nexport interface CustomEditorOptions extends EditorOptions {\n\tpromptPrefix?: string;\n\tplaceholder?: string | (() => string);\n}\n\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-?]*[ -/]*[@-~]|\\x1b\\][^\\x07]*(?:\\x07|\\x1b\\\\)|\\x1b[PX_][\\s\\S]*?\\x1b\\\\/g;\nconst BORDER_LINE_PATTERN = /^[─ ↑↓0-9more]+$/;\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate promptPrefix: string;\n\tprivate placeholder: string | (() => string) | undefined;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.promptPrefix = options?.promptPrefix ?? \"❯ \";\n\t\tthis.placeholder = options?.placeholder;\n\t}\n\n\tsetPlaceholder(placeholder: string | (() => string) | undefined): void {\n\t\tthis.placeholder = placeholder;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst promptWidth = visibleWidth(this.promptPrefix);\n\t\tif (promptWidth <= 0 || width <= promptWidth + 1) {\n\t\t\treturn super.render(width);\n\t\t}\n\n\t\tconst editorWidth = Math.max(1, width - promptWidth);\n\t\tconst lines = super.render(editorWidth);\n\t\tlet borderCount = 0;\n\t\tlet inPromptBox = false;\n\t\tlet promptShown = false;\n\n\t\tconst placeholder = typeof this.placeholder === \"function\" ? this.placeholder() : this.placeholder;\n\n\t\treturn lines.map((line) => {\n\t\t\tif (this.isEditorBorderLine(line)) {\n\t\t\t\tborderCount += 1;\n\t\t\t\tif (borderCount === 1) {\n\t\t\t\t\tinPromptBox = true;\n\t\t\t\t\tpromptShown = false;\n\t\t\t\t} else if (borderCount === 2) {\n\t\t\t\t\tinPromptBox = false;\n\t\t\t\t}\n\t\t\t\treturn this.extendBorderLine(line, width);\n\t\t\t}\n\n\t\t\tconst showPrompt = inPromptBox && !promptShown;\n\t\t\tconst prefix = showPrompt ? this.promptPrefix : \" \".repeat(promptWidth);\n\t\t\tlet content = line;\n\t\t\tif (showPrompt && placeholder && this.getText() === \"\") {\n\t\t\t\tcontent = truncateToWidth(placeholder, editorWidth, \"...\");\n\t\t\t}\n\t\t\tif (inPromptBox) {\n\t\t\t\tpromptShown = true;\n\t\t\t}\n\t\t\treturn this.padLine(`${prefix}${content}`, width);\n\t\t});\n\t}\n\n\tprivate isEditorBorderLine(line: string): boolean {\n\t\tconst plain = line.replace(ANSI_ESCAPE_PATTERN, \"\").trim();\n\t\treturn plain.includes(\"─\") && BORDER_LINE_PATTERN.test(plain);\n\t}\n\n\tprivate extendBorderLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${this.borderColor(\"─\".repeat(remainingWidth))}`;\n\t}\n\n\tprivate padLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${\" \".repeat(remainingWidth)}`;\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for paste image keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"custom-editor.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/custom-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { CURSOR_MARKER, Editor, type EditorOptions, type EditorTheme, type TUI, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AppKeybinding, KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { theme } from \"../theme/theme.ts\";\n\nexport interface CustomEditorOptions extends EditorOptions {\n\tpromptPrefix?: string;\n\tplaceholder?: string | (() => string);\n}\n\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-?]*[ -/]*[@-~]|\\x1b\\][^\\x07]*(?:\\x07|\\x1b\\\\)|\\x1b[PX_][\\s\\S]*?\\x1b\\\\/g;\nconst BORDER_LINE_PATTERN = /^[─ ↑↓0-9more]+$/;\n\n/**\n * Custom editor that handles app-level keybindings for coding-agent.\n */\nexport class CustomEditor extends Editor {\n\tprivate keybindings: KeybindingsManager;\n\tprivate promptPrefix: string;\n\tprivate placeholder: string | (() => string) | undefined;\n\tpublic actionHandlers: Map<AppKeybinding, () => void> = new Map();\n\n\t// Special handlers that can be dynamically replaced\n\tpublic onEscape?: () => void;\n\tpublic onCtrlD?: () => void;\n\tpublic onPasteImage?: () => void;\n\t/** Handler for extension-registered shortcuts. Returns true if handled. */\n\tpublic onExtensionShortcut?: (data: string) => boolean;\n\n\tconstructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: CustomEditorOptions) {\n\t\tsuper(tui, theme, options);\n\t\tthis.keybindings = keybindings;\n\t\tthis.promptPrefix = options?.promptPrefix ?? \"❯ \";\n\t\tthis.placeholder = options?.placeholder;\n\t}\n\n\tsetPlaceholder(placeholder: string | (() => string) | undefined): void {\n\t\tthis.placeholder = placeholder;\n\t}\n\n\trender(width: number): string[] {\n\t\tconst promptWidth = visibleWidth(this.promptPrefix);\n\t\tif (promptWidth <= 0 || width <= promptWidth + 1) {\n\t\t\treturn super.render(width);\n\t\t}\n\n\t\tconst editorWidth = Math.max(1, width - promptWidth);\n\t\tconst lines = super.render(editorWidth);\n\t\tlet borderCount = 0;\n\t\tlet inPromptBox = false;\n\t\tlet promptShown = false;\n\n\t\tconst placeholder = typeof this.placeholder === \"function\" ? this.placeholder() : this.placeholder;\n\n\t\treturn lines.map((line) => {\n\t\t\tif (this.isEditorBorderLine(line)) {\n\t\t\t\tborderCount += 1;\n\t\t\t\tif (borderCount === 1) {\n\t\t\t\t\tinPromptBox = true;\n\t\t\t\t\tpromptShown = false;\n\t\t\t\t} else if (borderCount === 2) {\n\t\t\t\t\tinPromptBox = false;\n\t\t\t\t}\n\t\t\t\treturn this.extendBorderLine(line, width);\n\t\t\t}\n\n\t\t\tconst showPrompt = inPromptBox && !promptShown;\n\t\t\tconst prefix = showPrompt ? this.promptPrefix : \" \".repeat(promptWidth);\n\t\t\tlet content = line;\n\t\t\tif (showPrompt && placeholder && this.getText() === \"\") {\n\t\t\t\tcontent = this.renderPlaceholder(placeholder, editorWidth);\n\t\t\t}\n\t\t\tif (inPromptBox) {\n\t\t\t\tpromptShown = true;\n\t\t\t}\n\t\t\treturn this.padLine(`${prefix}${content}`, width);\n\t\t});\n\t}\n\n\tprivate renderPlaceholder(placeholder: string, editorWidth: number): string {\n\t\tconst cursor = `${this.focused ? CURSOR_MARKER : \"\"}\\x1b[7m \\x1b[0m`;\n\t\tconst placeholderWidth = Math.max(0, editorWidth - 1);\n\t\tconst text = truncateToWidth(placeholder, placeholderWidth, \"...\");\n\t\treturn `${cursor}${theme.fg(\"muted\", text)}`;\n\t}\n\n\tprivate isEditorBorderLine(line: string): boolean {\n\t\tconst plain = line.replace(ANSI_ESCAPE_PATTERN, \"\").trim();\n\t\treturn plain.includes(\"─\") && BORDER_LINE_PATTERN.test(plain);\n\t}\n\n\tprivate extendBorderLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${this.borderColor(\"─\".repeat(remainingWidth))}`;\n\t}\n\n\tprivate padLine(line: string, width: number): string {\n\t\tconst remainingWidth = width - visibleWidth(line);\n\t\tif (remainingWidth <= 0) {\n\t\t\treturn line;\n\t\t}\n\t\treturn `${line}${\" \".repeat(remainingWidth)}`;\n\t}\n\n\t/**\n\t * Register a handler for an app action.\n\t */\n\tonAction(action: AppKeybinding, handler: () => void): void {\n\t\tthis.actionHandlers.set(action, handler);\n\t}\n\n\thandleInput(data: string): void {\n\t\t// Check extension-registered shortcuts first\n\t\tif (this.onExtensionShortcut?.(data)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check for paste image keybinding\n\t\tif (this.keybindings.matches(data, \"app.clipboard.pasteImage\")) {\n\t\t\tthis.onPasteImage?.();\n\t\t\treturn;\n\t\t}\n\n\t\t// Check app keybindings first\n\n\t\t// Escape/interrupt - only if autocomplete is NOT active\n\t\tif (this.keybindings.matches(data, \"app.interrupt\")) {\n\t\t\tif (!this.isShowingAutocomplete()) {\n\t\t\t\t// Use dynamic onEscape if set, otherwise registered handler\n\t\t\t\tconst handler = this.onEscape ?? this.actionHandlers.get(\"app.interrupt\");\n\t\t\t\tif (handler) {\n\t\t\t\t\thandler();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Let parent handle escape for autocomplete cancellation\n\t\t\tsuper.handleInput(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Exit (Ctrl+D) - only when editor is empty\n\t\tif (this.keybindings.matches(data, \"app.exit\")) {\n\t\t\tif (this.getText().length === 0) {\n\t\t\t\tconst handler = this.onCtrlD ?? this.actionHandlers.get(\"app.exit\");\n\t\t\t\tif (handler) handler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Fall through to editor handling for delete-char-forward when not empty\n\t\t}\n\n\t\t// Check all other app actions\n\t\tfor (const [action, handler] of this.actionHandlers) {\n\t\t\tif (action !== \"app.interrupt\" && action !== \"app.exit\" && this.keybindings.matches(data, action)) {\n\t\t\t\thandler();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Pass to parent for editor handling\n\t\tsuper.handleInput(data);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-selector-handlers.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector-handlers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAyC,iBAAiB,EAAkB,MAAM,8BAA8B,CAAC;AAE7H,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,iBAAiB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"settings-selector-handlers.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector-handlers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAyC,iBAAiB,EAAkB,MAAM,8BAA8B,CAAC;AAE7H,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,iBAAiB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAmFhH","sourcesContent":["import type { Transport } from \"@earendil-works/pi-ai\";\nimport { HTTP_IDLE_TIMEOUT_CHOICES } from \"../../../core/http-dispatcher.ts\";\nimport { DEFAULT_PROJECT_TRUST_BY_LABEL } from \"./settings-selector-options.ts\";\nimport type { DoubleEscapeAction, QueueDeliveryMode, SettingsCallbacks, TreeFilterMode } from \"./settings-selector-types.ts\";\n\nexport function createSettingsChangeHandler(callbacks: SettingsCallbacks): (id: string, newValue: string) => void {\n\treturn (id, newValue) => {\n\t\tswitch (id) {\n\t\t\tcase \"autocompact\":\n\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"show-images\":\n\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"image-width-cells\":\n\t\t\t\tcallbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"auto-resize-images\":\n\t\t\t\tcallbacks.onAutoResizeImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"block-images\":\n\t\t\t\tcallbacks.onBlockImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"skill-commands\":\n\t\t\t\tcallbacks.onEnableSkillCommandsChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"steering-mode\":\n\t\t\t\tcallbacks.onSteeringModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"follow-up-mode\":\n\t\t\t\tcallbacks.onFollowUpModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"transport\":\n\t\t\t\tcallbacks.onTransportChange(newValue as Transport);\n\t\t\t\tbreak;\n\t\t\tcase \"http-idle-timeout\": {\n\t\t\t\tconst selected = HTTP_IDLE_TIMEOUT_CHOICES.find((choice) => choice.label === newValue);\n\t\t\t\tcallbacks.onHttpIdleTimeoutChange(selected?.timeoutMs ?? 300_000);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"bash-interceptor\":\n\t\t\t\tcallbacks.onBashInterceptorEnabledChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"hide-thinking\":\n\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"collapse-changelog\":\n\t\t\t\tcallbacks.onCollapseChangelogChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"quiet-startup\":\n\t\t\t\tcallbacks.onQuietStartupChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"install-telemetry\":\n\t\t\t\tcallbacks.onEnableInstallTelemetryChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"default-project-trust\": {\n\t\t\t\tconst defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n\t\t\t\tif (defaultProjectTrust) {\n\t\t\t\t\tcallbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"double-escape-action\":\n\t\t\t\tcallbacks.onDoubleEscapeActionChange(newValue as DoubleEscapeAction);\n\t\t\t\tbreak;\n\t\t\tcase \"tree-filter-mode\":\n\t\t\t\tcallbacks.onTreeFilterModeChange(newValue as TreeFilterMode);\n\t\t\t\tbreak;\n\t\t\tcase \"show-hardware-cursor\":\n\t\t\t\tcallbacks.onShowHardwareCursorChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"editor-padding\":\n\t\t\t\tcallbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"autocomplete-max-visible\":\n\t\t\t\tcallbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"clear-on-shrink\":\n\t\t\t\tcallbacks.onClearOnShrinkChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"terminal-progress\":\n\t\t\t\tcallbacks.onShowTerminalProgressChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"theme\":\n\t\t\t\tcallbacks.onThemeChange(newValue);\n\t\t\t\tbreak;\n\t\t}\n\t};\n}\n"]}
|
|
@@ -35,6 +35,9 @@ export function createSettingsChangeHandler(callbacks) {
|
|
|
35
35
|
callbacks.onHttpIdleTimeoutChange(selected?.timeoutMs ?? 300_000);
|
|
36
36
|
break;
|
|
37
37
|
}
|
|
38
|
+
case "bash-interceptor":
|
|
39
|
+
callbacks.onBashInterceptorEnabledChange(newValue === "true");
|
|
40
|
+
break;
|
|
38
41
|
case "hide-thinking":
|
|
39
42
|
callbacks.onHideThinkingBlockChange(newValue === "true");
|
|
40
43
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-selector-handlers.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector-handlers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Transport } from \"@earendil-works/pi-ai\";\nimport { HTTP_IDLE_TIMEOUT_CHOICES } from \"../../../core/http-dispatcher.ts\";\nimport { DEFAULT_PROJECT_TRUST_BY_LABEL } from \"./settings-selector-options.ts\";\nimport type { DoubleEscapeAction, QueueDeliveryMode, SettingsCallbacks, TreeFilterMode } from \"./settings-selector-types.ts\";\n\nexport function createSettingsChangeHandler(callbacks: SettingsCallbacks): (id: string, newValue: string) => void {\n\treturn (id, newValue) => {\n\t\tswitch (id) {\n\t\t\tcase \"autocompact\":\n\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"show-images\":\n\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"image-width-cells\":\n\t\t\t\tcallbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"auto-resize-images\":\n\t\t\t\tcallbacks.onAutoResizeImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"block-images\":\n\t\t\t\tcallbacks.onBlockImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"skill-commands\":\n\t\t\t\tcallbacks.onEnableSkillCommandsChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"steering-mode\":\n\t\t\t\tcallbacks.onSteeringModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"follow-up-mode\":\n\t\t\t\tcallbacks.onFollowUpModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"transport\":\n\t\t\t\tcallbacks.onTransportChange(newValue as Transport);\n\t\t\t\tbreak;\n\t\t\tcase \"http-idle-timeout\": {\n\t\t\t\tconst selected = HTTP_IDLE_TIMEOUT_CHOICES.find((choice) => choice.label === newValue);\n\t\t\t\tcallbacks.onHttpIdleTimeoutChange(selected?.timeoutMs ?? 300_000);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"hide-thinking\":\n\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"collapse-changelog\":\n\t\t\t\tcallbacks.onCollapseChangelogChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"quiet-startup\":\n\t\t\t\tcallbacks.onQuietStartupChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"install-telemetry\":\n\t\t\t\tcallbacks.onEnableInstallTelemetryChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"default-project-trust\": {\n\t\t\t\tconst defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n\t\t\t\tif (defaultProjectTrust) {\n\t\t\t\t\tcallbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"double-escape-action\":\n\t\t\t\tcallbacks.onDoubleEscapeActionChange(newValue as DoubleEscapeAction);\n\t\t\t\tbreak;\n\t\t\tcase \"tree-filter-mode\":\n\t\t\t\tcallbacks.onTreeFilterModeChange(newValue as TreeFilterMode);\n\t\t\t\tbreak;\n\t\t\tcase \"show-hardware-cursor\":\n\t\t\t\tcallbacks.onShowHardwareCursorChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"editor-padding\":\n\t\t\t\tcallbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"autocomplete-max-visible\":\n\t\t\t\tcallbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"clear-on-shrink\":\n\t\t\t\tcallbacks.onClearOnShrinkChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"terminal-progress\":\n\t\t\t\tcallbacks.onShowTerminalProgressChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"theme\":\n\t\t\t\tcallbacks.onThemeChange(newValue);\n\t\t\t\tbreak;\n\t\t}\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-selector-handlers.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector-handlers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Transport } from \"@earendil-works/pi-ai\";\nimport { HTTP_IDLE_TIMEOUT_CHOICES } from \"../../../core/http-dispatcher.ts\";\nimport { DEFAULT_PROJECT_TRUST_BY_LABEL } from \"./settings-selector-options.ts\";\nimport type { DoubleEscapeAction, QueueDeliveryMode, SettingsCallbacks, TreeFilterMode } from \"./settings-selector-types.ts\";\n\nexport function createSettingsChangeHandler(callbacks: SettingsCallbacks): (id: string, newValue: string) => void {\n\treturn (id, newValue) => {\n\t\tswitch (id) {\n\t\t\tcase \"autocompact\":\n\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"show-images\":\n\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"image-width-cells\":\n\t\t\t\tcallbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"auto-resize-images\":\n\t\t\t\tcallbacks.onAutoResizeImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"block-images\":\n\t\t\t\tcallbacks.onBlockImagesChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"skill-commands\":\n\t\t\t\tcallbacks.onEnableSkillCommandsChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"steering-mode\":\n\t\t\t\tcallbacks.onSteeringModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"follow-up-mode\":\n\t\t\t\tcallbacks.onFollowUpModeChange(newValue as QueueDeliveryMode);\n\t\t\t\tbreak;\n\t\t\tcase \"transport\":\n\t\t\t\tcallbacks.onTransportChange(newValue as Transport);\n\t\t\t\tbreak;\n\t\t\tcase \"http-idle-timeout\": {\n\t\t\t\tconst selected = HTTP_IDLE_TIMEOUT_CHOICES.find((choice) => choice.label === newValue);\n\t\t\t\tcallbacks.onHttpIdleTimeoutChange(selected?.timeoutMs ?? 300_000);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"bash-interceptor\":\n\t\t\t\tcallbacks.onBashInterceptorEnabledChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"hide-thinking\":\n\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"collapse-changelog\":\n\t\t\t\tcallbacks.onCollapseChangelogChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"quiet-startup\":\n\t\t\t\tcallbacks.onQuietStartupChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"install-telemetry\":\n\t\t\t\tcallbacks.onEnableInstallTelemetryChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"default-project-trust\": {\n\t\t\t\tconst defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n\t\t\t\tif (defaultProjectTrust) {\n\t\t\t\t\tcallbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"double-escape-action\":\n\t\t\t\tcallbacks.onDoubleEscapeActionChange(newValue as DoubleEscapeAction);\n\t\t\t\tbreak;\n\t\t\tcase \"tree-filter-mode\":\n\t\t\t\tcallbacks.onTreeFilterModeChange(newValue as TreeFilterMode);\n\t\t\t\tbreak;\n\t\t\tcase \"show-hardware-cursor\":\n\t\t\t\tcallbacks.onShowHardwareCursorChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"editor-padding\":\n\t\t\t\tcallbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"autocomplete-max-visible\":\n\t\t\t\tcallbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n\t\t\t\tbreak;\n\t\t\tcase \"clear-on-shrink\":\n\t\t\t\tcallbacks.onClearOnShrinkChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"terminal-progress\":\n\t\t\t\tcallbacks.onShowTerminalProgressChange(newValue === \"true\");\n\t\t\t\tbreak;\n\t\t\tcase \"theme\":\n\t\t\t\tcallbacks.onThemeChange(newValue);\n\t\t\t\tbreak;\n\t\t}\n\t};\n}\n"]}
|