@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.1
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/README.md +175 -123
- package/bin/dsh-tui.js +748 -22
- package/cordis.patch.yml +42 -13
- package/cordis.yml +5 -2
- package/lib/types/activityPrefs.d.ts +24 -0
- package/lib/types/activityPrefs.d.ts.map +1 -1
- package/lib/types/activityPrefs.js +50 -1
- package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/session-projection.js +2 -0
- package/lib/types/adapter/channel/state.d.ts.map +1 -1
- package/lib/types/adapter/channel/state.js +3 -1
- package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +6 -2
- package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
- package/lib/types/adapter/kernel/host-facade.js +1 -0
- package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
- package/lib/types/adapter/kernel/replay.js +3 -0
- package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
- package/lib/types/adapter/kernel/runtime.js +2 -0
- package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
- package/lib/types/adapter/kernel/slices/workspace.js +1 -0
- package/lib/types/adapter/ports/channel-ui.d.ts +29 -5
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +66 -12
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
- package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel.d.ts +4 -1
- package/lib/types/adapter/ports/channel.d.ts.map +1 -1
- package/lib/types/adapter/ports/workspace.d.ts +2 -0
- package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.js +10 -2
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +1 -0
- package/lib/types/components/ActivityLine.d.ts +7 -2
- package/lib/types/components/ActivityLine.d.ts.map +1 -1
- package/lib/types/components/ActivityLine.js +0 -8
- package/lib/types/components/ContextBarView.d.ts +15 -7
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +26 -22
- package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
- package/lib/types/components/ImagePreviewOverlay.js +11 -5
- package/lib/types/components/Markdown.d.ts +11 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +20 -2
- package/lib/types/components/MermaidDiagram.d.ts +13 -0
- package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
- package/lib/types/components/MermaidDiagram.js +61 -0
- package/lib/types/components/MessageList.d.ts +26 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +74 -8
- package/lib/types/components/PageMargin.d.ts +1 -1
- package/lib/types/components/PromptInput.d.ts +37 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +291 -30
- package/lib/types/components/ScrollbarGutter.d.ts +20 -5
- package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
- package/lib/types/components/ScrollbarGutter.js +88 -10
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +2 -1
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +30 -28
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +12 -6
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +8 -3
- package/lib/types/components/Tooltip.d.ts.map +1 -1
- package/lib/types/components/Tooltip.js +45 -7
- package/lib/types/components/design-system/HintLine.d.ts +1 -2
- package/lib/types/components/design-system/HintLine.d.ts.map +1 -1
- package/lib/types/components/design-system/HintLine.js +1 -2
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +2 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +2 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +2 -2
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +30 -26
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +5 -7
- package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
- package/lib/types/components/messages/useImageInspection.js +19 -9
- package/lib/types/components/promptDraftCache.d.ts +102 -0
- package/lib/types/components/promptDraftCache.d.ts.map +1 -0
- package/lib/types/components/promptDraftCache.js +76 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
- package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
- package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +52 -5
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
- package/lib/types/dsh-adapter/activity-store.d.ts +221 -0
- package/lib/types/dsh-adapter/activity-store.d.ts.map +1 -0
- package/lib/types/dsh-adapter/activity-store.js +359 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
- package/lib/types/dsh-adapter/bundled-presets.js +80 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +53 -29
- package/lib/types/dsh-adapter/channel/binding-events.d.ts +8 -6
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +5 -4
- package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
- package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding.js +78 -18
- package/lib/types/dsh-adapter/channel/compaction.d.ts +0 -1
- package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/compaction.js +0 -2
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
- package/lib/types/dsh-adapter/channel/model-switch.d.ts +1 -2
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
- package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +29 -19
- package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/reports.js +4 -12
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-adoption.js +1 -0
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.js +2 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +6 -4
- package/lib/types/dsh-adapter/channel/session-reset.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.js +0 -1
- package/lib/types/dsh-adapter/channel/session-resume.d.ts +12 -3
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +292 -94
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
- package/lib/types/dsh-adapter/channel/state.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +3 -3
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +21 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +173 -6
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +6 -12
- package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
- package/lib/types/dsh-adapter/channel.d.ts +1 -1
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +82 -20
- package/lib/types/dsh-adapter/compat/index.d.ts +1 -1
- package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/index.js +1 -1
- package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
- package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/messages.js +15 -0
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts +18 -0
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/sessionLog.js +18 -3
- package/lib/types/dsh-adapter/compat/settings.d.ts +35 -0
- package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/settings.js +57 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/shell.js +11 -0
- package/lib/types/dsh-adapter/contract.d.ts +5 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +17 -6
- package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
- package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
- package/lib/types/dsh-adapter/ide-channel.js +556 -0
- package/lib/types/dsh-adapter/index.d.ts +18 -3
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +32 -5
- package/lib/types/dsh-adapter/plugin.d.ts +4 -1
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +197 -49
- package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
- package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/preset-resolution.js +10 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessionTree.js +3 -2
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +7 -4
- package/lib/types/dsh-adapter/subagents.d.ts +16 -3
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +92 -29
- package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
- package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
- package/lib/types/dsh-adapter/workspaces.js +116 -0
- package/lib/types/effortPrefs.d.ts +15 -3
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +37 -3
- package/lib/types/history.d.ts +13 -1
- package/lib/types/history.d.ts.map +1 -1
- package/lib/types/history.js +15 -2
- package/lib/types/homePrefs.d.ts +15 -0
- package/lib/types/homePrefs.d.ts.map +1 -0
- package/lib/types/homePrefs.js +53 -0
- package/lib/types/i18n.d.ts +347 -297
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +133 -85
- package/lib/types/ink/colorize.d.ts +10 -0
- package/lib/types/ink/colorize.d.ts.map +1 -1
- package/lib/types/ink/colorize.js +21 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +12 -1
- package/lib/types/ink/dom.d.ts +1 -0
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +36 -1
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +19 -1
- package/lib/types/ink/output.d.ts +10 -1
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +109 -17
- package/lib/types/ink/render-border.d.ts +6 -1
- package/lib/types/ink/render-border.d.ts.map +1 -1
- package/lib/types/ink/render-border.js +25 -9
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +48 -6
- package/lib/types/ink/renderer.d.ts +6 -0
- package/lib/types/ink/renderer.d.ts.map +1 -1
- package/lib/types/ink/renderer.js +2 -1
- package/lib/types/ink/selection.d.ts +88 -0
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +164 -0
- package/lib/types/ink/sixel-graphics.d.ts +19 -1
- package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
- package/lib/types/ink/sixel-graphics.js +124 -12
- package/lib/types/ink/terminal-image.d.ts +18 -1
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal.d.ts +17 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +20 -1
- package/lib/types/screens/Chat.d.ts +20 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +296 -76
- package/lib/types/screens/SessionSupervisor.d.ts +84 -0
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/SessionSupervisor.js +350 -0
- package/lib/types/screens/SessionTree.js +2 -2
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +32 -9
- package/lib/types/screens/StatusLine.d.ts +18 -1
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +38 -19
- package/lib/types/screens/StatusMetrics.d.ts +79 -22
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +153 -88
- package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
- package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/model.js +69 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
- package/lib/types/sessionMounts.d.ts +272 -0
- package/lib/types/sessionMounts.d.ts.map +1 -0
- package/lib/types/sessionMounts.js +706 -0
- package/lib/types/sessions/format.d.ts.map +1 -1
- package/lib/types/sessions/format.js +4 -1
- package/lib/types/sessions/resumeFailure.d.ts +38 -0
- package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
- package/lib/types/sessions/resumeFailure.js +58 -0
- package/lib/types/terminal-utils/mermaid.d.ts +44 -0
- package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
- package/lib/types/terminal-utils/mermaid.js +83 -0
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +175 -19
- package/lib/types/tuiDisplayPrefs.d.ts +7 -9
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +31 -28
- package/lib/types/update.d.ts +61 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +194 -0
- package/lib/types/utils/fold-long-lines.d.ts +1 -1
- package/lib/types/utils/fold-long-lines.js +1 -1
- package/lib/types/utils/imageResize.d.ts +90 -0
- package/lib/types/utils/imageResize.d.ts.map +1 -0
- package/lib/types/utils/imageResize.js +272 -0
- package/lib/types/utils/keymap.d.ts +5 -1
- package/lib/types/utils/keymap.d.ts.map +1 -1
- package/lib/types/utils/keymap.js +23 -0
- package/lib/types/working-activity.d.ts +10 -9
- package/lib/types/working-activity.d.ts.map +1 -1
- package/lib/types/working-activity.js +17 -10
- package/lib/types/workspaces.d.ts +2 -1
- package/lib/types/workspaces.d.ts.map +1 -1
- package/lib/types/workspaces.js +1 -1
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
- package/package.json +126 -105
- package/presets/liangshen/.dsh-tui-managed.json +1 -1
- package/presets/liangshen/agent.cordis.yml +15 -0
- package/lib/types/components/design-system/KeyboardShortcutHint.d.ts +0 -19
- package/lib/types/components/design-system/KeyboardShortcutHint.d.ts.map +0 -1
- package/lib/types/components/design-system/KeyboardShortcutHint.js +0 -14
- package/lib/types/dsh-adapter/channel/activity.d.ts +0 -20
- package/lib/types/dsh-adapter/channel/activity.d.ts.map +0 -1
- package/lib/types/dsh-adapter/channel/activity.js +0 -113
- package/lib/types/screens/AgentView.d.ts +0 -23
- package/lib/types/screens/AgentView.d.ts.map +0 -1
- package/lib/types/screens/AgentView.js +0 -546
- package/lib/types/screens/SessionBrowser.d.ts +0 -42
- package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
- package/lib/types/screens/SessionBrowser.js +0 -911
- package/lib/types/terminal-utils/terminal.d.ts +0 -18
- package/lib/types/terminal-utils/terminal.d.ts.map +0 -1
- package/lib/types/terminal-utils/terminal.js +0 -96
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SpinnerGlyph } from '../components/Spinner/SpinnerGlyph.js';
|
|
3
|
+
import type { ApprovalSnapshot } from '../dsh-adapter/approvals.js';
|
|
4
|
+
import type { TuiWorkspaceTarget } from '../workspaces.js';
|
|
5
|
+
import type { ChannelUi as Channel } from '../adapter/channel/ui-policy.js';
|
|
6
|
+
import { SupervisorLiveState, sessionMatchesQuery } from './sessionSupervisor/model.js';
|
|
7
|
+
export { sessionMatchesQuery };
|
|
8
|
+
/**
|
|
9
|
+
* The unified session screen — `/resume`, `/agentview`, `/home` and the 🏠
|
|
10
|
+
* button all land here.
|
|
11
|
+
*
|
|
12
|
+
* Those were three screens over one domain, which is why they kept needing
|
|
13
|
+
* patches to agree with each other. This is the single surface: the workspace
|
|
14
|
+
* rail on the left (the durable ledger a person manages — add, rename,
|
|
15
|
+
* remove), the sessions of the selected workspace on the right, and every
|
|
16
|
+
* session's LIVE state on its own row.
|
|
17
|
+
*
|
|
18
|
+
* The runtime it presents is a single model, and the screen is where that
|
|
19
|
+
* model becomes visible:
|
|
20
|
+
*
|
|
21
|
+
* - This terminal hosts many sessions at once. A row that is `working` keeps
|
|
22
|
+
* working when you leave it — switching changes what you are looking at, it
|
|
23
|
+
* does not stop anything. The parked rows stay in the list with a live
|
|
24
|
+
* glyph, so "where did my other session go" has an answer on screen.
|
|
25
|
+
* - A session held by another TUI terminal is shown as OCCUPIED (red, with the
|
|
26
|
+
* holder's pid) and cannot be entered. Two processes driving one
|
|
27
|
+
* append-only session log would interleave its events, so the screen refuses
|
|
28
|
+
* rather than races; the entry becomes available on its own once that
|
|
29
|
+
* process exits, because occupancy is proven by liveness rather than by a
|
|
30
|
+
* flag someone has to remember to clear.
|
|
31
|
+
*
|
|
32
|
+
* @param props - Channel, home directory, the opening/新 actions, and the live
|
|
33
|
+
* state + occupancy lookups the screen renders from.
|
|
34
|
+
* @returns The screen, or null while the host has no channel to read.
|
|
35
|
+
*/
|
|
36
|
+
export declare function SessionSupervisor({ channel, home, onClose, onOpenSession, onNewSession, onStopSession, approval, onApprove, liveStateOf, }: {
|
|
37
|
+
channel: Channel;
|
|
38
|
+
/** Home directory, for collapsing paths to `~`. */
|
|
39
|
+
home: string;
|
|
40
|
+
/** Leave the screen and show the conversation. */
|
|
41
|
+
onClose(): void;
|
|
42
|
+
/** Mount a persisted session (the channel's unified resume path). */
|
|
43
|
+
onOpenSession(sessionId: string): Promise<boolean>;
|
|
44
|
+
/** Start a fresh session in the workspace at `path`. */
|
|
45
|
+
onNewSession(target: TuiWorkspaceTarget): Promise<boolean>;
|
|
46
|
+
/** Stop a background session of this terminal; false when it is not ours. */
|
|
47
|
+
onStopSession(sessionId: string): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* The parked approval ask (any session's), so a background session's
|
|
50
|
+
* permission prompt is answerable without leaving this screen — the one
|
|
51
|
+
* thing a parked session cannot wait indefinitely for.
|
|
52
|
+
*/
|
|
53
|
+
approval: ApprovalSnapshot | null;
|
|
54
|
+
onApprove(outcome: 'allowed-once' | 'rejected'): void;
|
|
55
|
+
/**
|
|
56
|
+
* This terminal's live state for a session, or undefined when it has none.
|
|
57
|
+
* Read from the channel's agent-view projection so the list agrees with the
|
|
58
|
+
* overview's own rows by construction.
|
|
59
|
+
*/
|
|
60
|
+
liveStateOf(sessionId: string): SupervisorLiveState | undefined;
|
|
61
|
+
}): React.ReactNode;
|
|
62
|
+
/**
|
|
63
|
+
* Scroll anchor for the rail: the first entry index to show.
|
|
64
|
+
*
|
|
65
|
+
* A pure helper (exported for the headless regression) because the rail's
|
|
66
|
+
* window has to hold the focused row without re-shuffling under a stationary
|
|
67
|
+
* cursor — the same anchoring rule the session list uses.
|
|
68
|
+
*
|
|
69
|
+
* `focus` is a plain entry index: the rail's rows ARE the ledger, so the cursor
|
|
70
|
+
* and the selection are one position and the window math takes that position
|
|
71
|
+
* directly. It used to be offset by the `+` row that led the rail, which is
|
|
72
|
+
* gone — a workspace joins the ledger by being a terminal's launch directory.
|
|
73
|
+
*
|
|
74
|
+
* `capacity` is a count of ENTRIES, not of terminal rows. It used to be handed
|
|
75
|
+
* the row count, which is wrong for this list in a way that hides the cursor:
|
|
76
|
+
* each entry is {@link WORKSPACE_ROW_LINES} rows tall, so treating rows as
|
|
77
|
+
* entries made the window believe it could show twice as many workspaces as it
|
|
78
|
+
* can, and the focused entry was simply clipped away by `overflow="hidden"`
|
|
79
|
+
* while the user navigated it blind.
|
|
80
|
+
*/
|
|
81
|
+
export declare function railWindowTop(focus: number, entryCount: number, capacity: number): number;
|
|
82
|
+
/** Re-exported so a regression can drive the spinner without importing ink. */
|
|
83
|
+
export { SpinnerGlyph };
|
|
84
|
+
//# sourceMappingURL=SessionSupervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionSupervisor.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionSupervisor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAarE,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAA;AAEpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AASnE,OAAO,KAAK,EAAqB,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC7E,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAE3E,OAAO,EAAkN,mBAAmB,EAAsD,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAC3V,OAAO,EAAE,mBAAmB,EAAE,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,IAAI,EACJ,OAAO,EACP,aAAa,EACb,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,SAAS,EACT,WAAW,GACZ,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,OAAO,IAAI,IAAI,CAAA;IACf,qEAAqE;IACrE,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,wDAAwD;IACxD,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,6EAA6E;IAC7E,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD;;;;OAIG;IACH,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACjC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,IAAI,CAAA;IACrD;;;;OAIG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAAA;CAChE,GAAG,KAAK,CAAC,SAAS,CA8hBlB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOzF;AAED,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text, useInput, useTerminalSize } from '../ui.js';
|
|
4
|
+
import { t } from '../i18n.js';
|
|
5
|
+
import { Divider } from '../components/design-system/Divider.js';
|
|
6
|
+
import { HintLine } from '../components/design-system/HintLine.js';
|
|
7
|
+
import { SearchBox } from '../components/SearchBox.js';
|
|
8
|
+
import { PageInsetContext } from '../components/PageMargin.js';
|
|
9
|
+
import { HomeWorkspaceRow } from '../components/workspaces/HomeWorkspaceRow.js';
|
|
10
|
+
import { SessionListRow } from '../components/sessions/SessionListRow.js';
|
|
11
|
+
import { SpinnerGlyph } from '../components/Spinner/SpinnerGlyph.js';
|
|
12
|
+
import { ApprovalPanel } from '../components/approvals/ApprovalPanel.js';
|
|
13
|
+
import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
|
|
14
|
+
import { useAnimationFrame } from '../ink/hooks/use-animation-frame.js';
|
|
15
|
+
import { isPlainReturn, isMod } from '../utils/modifiers.js';
|
|
16
|
+
import { truncateWidth } from '../sessions/format.js';
|
|
17
|
+
import { useSessionSupervisor } from './sessionSupervisor/useSessionSupervisor.js';
|
|
18
|
+
import { SESSION_ROW_LINES, MENU_ACTIONS, MENU_WIDTH, MENU_HEIGHT, MENU_LABEL_KEYS, samePath, sessionMatchesQuery } from './sessionSupervisor/model.js';
|
|
19
|
+
export { sessionMatchesQuery };
|
|
20
|
+
/**
|
|
21
|
+
* The unified session screen — `/resume`, `/agentview`, `/home` and the 🏠
|
|
22
|
+
* button all land here.
|
|
23
|
+
*
|
|
24
|
+
* Those were three screens over one domain, which is why they kept needing
|
|
25
|
+
* patches to agree with each other. This is the single surface: the workspace
|
|
26
|
+
* rail on the left (the durable ledger a person manages — add, rename,
|
|
27
|
+
* remove), the sessions of the selected workspace on the right, and every
|
|
28
|
+
* session's LIVE state on its own row.
|
|
29
|
+
*
|
|
30
|
+
* The runtime it presents is a single model, and the screen is where that
|
|
31
|
+
* model becomes visible:
|
|
32
|
+
*
|
|
33
|
+
* - This terminal hosts many sessions at once. A row that is `working` keeps
|
|
34
|
+
* working when you leave it — switching changes what you are looking at, it
|
|
35
|
+
* does not stop anything. The parked rows stay in the list with a live
|
|
36
|
+
* glyph, so "where did my other session go" has an answer on screen.
|
|
37
|
+
* - A session held by another TUI terminal is shown as OCCUPIED (red, with the
|
|
38
|
+
* holder's pid) and cannot be entered. Two processes driving one
|
|
39
|
+
* append-only session log would interleave its events, so the screen refuses
|
|
40
|
+
* rather than races; the entry becomes available on its own once that
|
|
41
|
+
* process exits, because occupancy is proven by liveness rather than by a
|
|
42
|
+
* flag someone has to remember to clear.
|
|
43
|
+
*
|
|
44
|
+
* @param props - Channel, home directory, the opening/新 actions, and the live
|
|
45
|
+
* state + occupancy lookups the screen renders from.
|
|
46
|
+
* @returns The screen, or null while the host has no channel to read.
|
|
47
|
+
*/
|
|
48
|
+
export function SessionSupervisor({ channel, home, onClose, onOpenSession, onNewSession, onStopSession, approval, onApprove, liveStateOf, }) {
|
|
49
|
+
const { columns, rows } = useTerminalSize();
|
|
50
|
+
const inset = React.useContext(PageInsetContext);
|
|
51
|
+
const isTerminalFocused = useTerminalFocus();
|
|
52
|
+
const { entries, sessions, loading, notice, setNotice, query, setQuery, holderOf, listedSessions, railEntries, countOf, railFocus, setRailFocus, setFocusSessionId, activePane, pins, menu, setMenu, rename, setRename, confirmRemove, setConfirmRemove, railRef, menuRef, queryRef, now, reload, selected, visibleSessions, sessionIndex, cardFocused, sessionAt, activateList, activateRail, railWidth, railVisible, sessionWidth, railEntryCapacity, sessionListHeight, persistPin, selectEntry, openSession, newSessionIn, renameEntry, removeEntry, stopSession, closeMenu, activateMenu, moveRail, moveSession, focusedSession, } = useSessionSupervisor({ channel, home, onOpenSession, onNewSession, onStopSession, liveStateOf, columns, rows });
|
|
53
|
+
useInput((input, key) => {
|
|
54
|
+
// Modal layers own the keyboard, in the same order they render.
|
|
55
|
+
if (rename !== undefined) {
|
|
56
|
+
if (key.escape) {
|
|
57
|
+
setRename(undefined);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (isPlainReturn(key)) {
|
|
61
|
+
const current = rename;
|
|
62
|
+
setRename(undefined);
|
|
63
|
+
renameEntry(current.path, current.draft);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (key.backspace || key.delete) {
|
|
67
|
+
setRename(current => (current === undefined ? current : { ...current, draft: current.draft.slice(0, -1) }));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!isMod(key) && !key.meta && input && !key.return) {
|
|
71
|
+
const typed = input.replace(/[\r\n]+/gu, '');
|
|
72
|
+
if (typed !== '')
|
|
73
|
+
setRename(current => (current === undefined ? current : { ...current, draft: current.draft + typed }));
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (confirmRemove !== undefined) {
|
|
78
|
+
if (isPlainReturn(key)) {
|
|
79
|
+
const path = confirmRemove;
|
|
80
|
+
setConfirmRemove(undefined);
|
|
81
|
+
removeEntry(path);
|
|
82
|
+
}
|
|
83
|
+
else if (key.escape) {
|
|
84
|
+
setConfirmRemove(undefined);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (menuRef.current !== undefined) {
|
|
89
|
+
if (key.upArrow) {
|
|
90
|
+
const current = menuRef.current;
|
|
91
|
+
const next = { ...current, item: (current.item + MENU_ACTIONS.length - 1) % MENU_ACTIONS.length };
|
|
92
|
+
menuRef.current = next;
|
|
93
|
+
setMenu(next);
|
|
94
|
+
}
|
|
95
|
+
else if (key.downArrow) {
|
|
96
|
+
const current = menuRef.current;
|
|
97
|
+
const next = { ...current, item: (current.item + 1) % MENU_ACTIONS.length };
|
|
98
|
+
menuRef.current = next;
|
|
99
|
+
setMenu(next);
|
|
100
|
+
}
|
|
101
|
+
else if (isPlainReturn(key)) {
|
|
102
|
+
const current = menuRef.current;
|
|
103
|
+
const entry = railEntries.find(candidate => samePath(candidate.path, current.path));
|
|
104
|
+
if (entry !== undefined)
|
|
105
|
+
activateMenu(entry, current.item);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
closeMenu();
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (key.escape) {
|
|
113
|
+
if (notice !== undefined) {
|
|
114
|
+
setNotice(undefined);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (queryRef.current.length > 0) {
|
|
118
|
+
setQuery('');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
onClose();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (key.tab) {
|
|
125
|
+
// Shift+Tab keeps the keyboard route to the focused workspace's action
|
|
126
|
+
// menu. Plain Tab does nothing here: panes are chosen with ←/→ now, and
|
|
127
|
+
// Tab is the composer's business.
|
|
128
|
+
if (key.shift && activePane === 'rail') {
|
|
129
|
+
const entry = railEntries[railRef.current];
|
|
130
|
+
if (entry !== undefined) {
|
|
131
|
+
const next = { path: entry.path, ...keyboardMenuAnchor, item: 0 };
|
|
132
|
+
menuRef.current = next;
|
|
133
|
+
setMenu(next);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// ←/→ choose the column. There is exactly one `❯` on screen because exactly
|
|
139
|
+
// one column owns the keyboard, and this is what moves that ownership.
|
|
140
|
+
if (key.leftArrow) {
|
|
141
|
+
activateRail();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (key.rightArrow) {
|
|
145
|
+
activateList();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (key.upArrow || key.wheelUp) {
|
|
149
|
+
if (activePane === 'rail')
|
|
150
|
+
moveRail(-1);
|
|
151
|
+
else
|
|
152
|
+
moveSession(-1);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (key.downArrow || key.wheelDown) {
|
|
156
|
+
if (activePane === 'rail')
|
|
157
|
+
moveRail(1);
|
|
158
|
+
else
|
|
159
|
+
moveSession(1);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (key.pageUp || key.pageDown) {
|
|
163
|
+
if (activePane === 'list')
|
|
164
|
+
moveSession(key.pageDown ? 1 : -1);
|
|
165
|
+
else
|
|
166
|
+
moveRail(key.pageDown ? 1 : -1);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
// The filter is a LIVE query, not a mode you enter: this screen has no
|
|
170
|
+
// second cursor for a text seat, and the rail/list already own the arrows
|
|
171
|
+
// (a seat would have to relearn them). So printable input goes straight to
|
|
172
|
+
// the query — without this branch the box rendered, focused, and could never
|
|
173
|
+
// be typed into.
|
|
174
|
+
if (key.backspace || key.delete) {
|
|
175
|
+
setQuery(text => text.slice(0, -1));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (isMod(key) && input === 'n') {
|
|
179
|
+
const entry = railEntries[railRef.current];
|
|
180
|
+
if (entry !== undefined)
|
|
181
|
+
newSessionIn(entry);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (isMod(key) && input === 'l') {
|
|
185
|
+
void reload();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (isMod(key) && input === 'x') {
|
|
189
|
+
if (focusedSession !== undefined)
|
|
190
|
+
stopSession(focusedSession);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (isPlainReturn(key)) {
|
|
194
|
+
// Enter means "the thing the active column is showing": its action menu
|
|
195
|
+
// for a workspace, that session for the session list. Ctrl/Cmd+Enter keeps
|
|
196
|
+
// the old "start a session in this workspace" shortcut from either column.
|
|
197
|
+
// Row 0 of the list is the new-session card, so it starts a session
|
|
198
|
+
// instead of opening one.
|
|
199
|
+
if (activePane === 'list') {
|
|
200
|
+
if (sessionIndex === 0) {
|
|
201
|
+
if (selected !== undefined)
|
|
202
|
+
newSessionIn(selected);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
// `sessionIndex` is derived from the SAME focus fact the render draws
|
|
206
|
+
// `❯` from, so Enter can only ever open the row the user is looking at.
|
|
207
|
+
const session = sessionAt(sessionIndex);
|
|
208
|
+
if (session !== undefined)
|
|
209
|
+
openSession(session);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const entry = railEntries[railRef.current];
|
|
213
|
+
if (entry === undefined)
|
|
214
|
+
return;
|
|
215
|
+
if (key.ctrl || key.meta) {
|
|
216
|
+
newSessionIn(entry);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const next = { path: entry.path, ...keyboardMenuAnchor, item: 0 };
|
|
220
|
+
menuRef.current = next;
|
|
221
|
+
setMenu(next);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// Reached only when nothing above claimed the key: printable characters
|
|
225
|
+
// refine the filter. Control bytes are dropped so a terminal reporting an
|
|
226
|
+
// unknown key cannot type an invisible glyph into the query.
|
|
227
|
+
if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
|
|
228
|
+
const typed = input.replace(/\p{Cc}/gu, '');
|
|
229
|
+
if (typed.length > 0)
|
|
230
|
+
setQuery(text => text + typed);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
// Working rows animate their glyph. The shared clock only runs while at
|
|
234
|
+
// least one row is working, so an idle screen costs no extra ticks.
|
|
235
|
+
const workingCount = listedSessions.filter(session => liveStateOf(session.id)?.status === 'working').length;
|
|
236
|
+
const [, spinnerTime] = useAnimationFrame(workingCount > 0 ? 120 : null);
|
|
237
|
+
const spinnerFrame = Math.floor(spinnerTime / 120);
|
|
238
|
+
const railHint = rename !== undefined
|
|
239
|
+
? t('home-hint-rename')
|
|
240
|
+
: confirmRemove !== undefined
|
|
241
|
+
? t('home-hint-confirm-remove')
|
|
242
|
+
: menu !== undefined
|
|
243
|
+
? t('home-hint-menu')
|
|
244
|
+
: activePane === 'rail'
|
|
245
|
+
? t('home-hint-list')
|
|
246
|
+
: t('supervisor-hint-list');
|
|
247
|
+
const railWindowTopIndex = railWindowTop(railFocus, railEntries.length, railEntryCapacity);
|
|
248
|
+
const visibleRailRows = railEntries.slice(railWindowTopIndex, railWindowTopIndex + railEntryCapacity);
|
|
249
|
+
/** Content-local anchor for a keyboard-opened menu (screen coords minus inset). */
|
|
250
|
+
const keyboardMenuAnchor = { col: inset.x + 2, row: inset.y + 3 };
|
|
251
|
+
const filtered = query.trim().length > 0;
|
|
252
|
+
// Scroll window over the session rows, keeping the focused row visible
|
|
253
|
+
// without re-shuffling the list under a stationary cursor.
|
|
254
|
+
//
|
|
255
|
+
// The new-session card is a permanent row above this window, so the window is
|
|
256
|
+
// one card shorter and the cursor is expressed in the FULL list's space (card =
|
|
257
|
+
// 0): without that offset the window kept its old height and the cursor could
|
|
258
|
+
// land on a row that never made it on screen — a `❯` on an invisible row.
|
|
259
|
+
const capacity = Math.max(1, Math.floor(sessionListHeight / SESSION_ROW_LINES));
|
|
260
|
+
const sessionCapacity = Math.max(1, capacity - 1);
|
|
261
|
+
let sessionTop = Math.min(Math.max(0, sessionIndex - 1 - sessionCapacity + 1), Math.max(0, visibleSessions.length - sessionCapacity));
|
|
262
|
+
if (sessionIndex - 1 < sessionTop)
|
|
263
|
+
sessionTop = Math.max(0, sessionIndex - 1);
|
|
264
|
+
const visibleSessionRows = visibleSessions.slice(sessionTop, sessionTop + sessionCapacity);
|
|
265
|
+
const liveCount = listedSessions.filter(session => liveStateOf(session.id)?.live === true).length;
|
|
266
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, onClick: menu !== undefined ? closeMenu : undefined, children: [_jsxs(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: [_jsx(Text, { color: "remember", bold: true, children: ` ▣ ${t('supervisor-title')}` }), _jsx(Text, { dimColor: true, children: ` ${t('supervisor-subtitle')}` })] }), _jsx(Divider, { bleed: true }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: [railVisible && (_jsxs("ink-box", { style: { flexDirection: 'column', width: railWidth, height: '100%', flexShrink: 0, overflow: 'hidden' }, onClick: activateRail, onMouseEnter: activateRail, onWheel: (event) => {
|
|
267
|
+
moveRail(event.deltaY >= 0 ? 1 : -1);
|
|
268
|
+
}, children: [_jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", paddingX: 1, children: _jsx(Text, { dimColor: true, children: truncateWidth(t('home-section-workspaces', { n: railEntries.length }), railWidth - 2) }) }), !loading && railEntries.length === 0 && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, italic: true, wrap: "truncate-end", children: truncateWidth(t('home-no-workspaces'), railWidth - 2) }) })), visibleRailRows.map((entry) => {
|
|
269
|
+
const absolute = railEntries.indexOf(entry);
|
|
270
|
+
return (_jsx(HomeWorkspaceRow, { title: entry.title, path: entry.path, home: home, sessionCount: countOf(entry), present: entry.present, selected: selected !== undefined && selected.id === entry.id, focused: activePane === 'rail' && railFocus === absolute, width: railWidth, onSelect: (event) => {
|
|
271
|
+
event.stopImmediatePropagation();
|
|
272
|
+
railRef.current = absolute;
|
|
273
|
+
setRailFocus(absolute);
|
|
274
|
+
selectEntry(entry);
|
|
275
|
+
}, onMenu: (event) => {
|
|
276
|
+
event.stopImmediatePropagation();
|
|
277
|
+
railRef.current = absolute;
|
|
278
|
+
setRailFocus(absolute);
|
|
279
|
+
const next = { path: entry.path, col: event.col, row: event.row, item: 0 };
|
|
280
|
+
menuRef.current = next;
|
|
281
|
+
setMenu(next);
|
|
282
|
+
} }, entry.id));
|
|
283
|
+
}), _jsx(Box, { flexGrow: 1 }), _jsx(Box, { flexShrink: 0, paddingX: 1, children: _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: railHint }) }) })] })), railVisible && (_jsx(Box, { width: 1, flexShrink: 0, flexDirection: "column", children: _jsx(Text, { dimColor: true, children: '│' }) })), _jsxs(Box, { flexDirection: "column", width: sessionWidth, height: "100%", flexShrink: 0, overflow: "hidden", onClick: activateList, onMouseEnter: activateList, children: [_jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: _jsxs(Box, { flexShrink: 1, overflow: "hidden", children: [_jsx(Text, { color: "remember", bold: true, children: truncateWidth(` ${t('home-sessions-title', { name: selected?.title ?? t('supervisor-title') })}`, Math.max(4, sessionWidth - 3)) }), _jsx(Text, { dimColor: true, children: ` ${truncateWidth(t('supervisor-counts', { working: workingCount, live: liveCount, total: visibleSessions.length }), Math.max(4, sessionWidth - 3))}` })] }) }), _jsx(Box, { height: 1, flexShrink: 0, paddingX: 1, children: _jsx(SearchBox, { query: query, isFocused: activePane === 'list', isTerminalFocused: isTerminalFocused, placeholder: truncateWidth(t('supervisor-filter-placeholder'), Math.max(8, sessionWidth - 6)), prefix: "/", borderless: true, width: Math.max(8, sessionWidth - 2) }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, onClick: (event) => {
|
|
284
|
+
event.stopImmediatePropagation();
|
|
285
|
+
if (selected !== undefined)
|
|
286
|
+
newSessionIn(selected);
|
|
287
|
+
}, children: [_jsxs(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: [_jsx(Text, { color: cardFocused ? 'success' : 'subtle', children: cardFocused ? '❯ ' : ' ' }), _jsx(Text, { color: cardFocused ? 'success' : undefined, bold: cardFocused, children: t('supervisor-new-session') })] }), _jsx(Box, { height: 1, flexShrink: 0, overflow: "hidden", children: _jsx(Text, { dimColor: true, children: ` ${truncateWidth(t('supervisor-new-session-hint', { name: selected?.title ?? t('supervisor-title') }), Math.max(8, sessionWidth - 3))}` }) })] }), _jsxs("ink-box", { style: { flexDirection: 'column', flexGrow: 1, flexShrink: 1, overflow: 'hidden' }, onWheel: (event) => {
|
|
288
|
+
moveSession(event.deltaY >= 0 ? 1 : -1);
|
|
289
|
+
}, children: [loading && _jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(t('home-sessions-loading'), sessionWidth - 2)}` }), !loading && visibleSessions.length === 0 && (_jsx(Text, { dimColor: true, italic: true, children: ` ${truncateWidth(filtered ? t('supervisor-no-matches') : t('home-no-sessions'), sessionWidth - 2)}` })), visibleSessionRows.map((session, index) => {
|
|
290
|
+
const state = liveStateOf(session.id);
|
|
291
|
+
const holder = holderOf(session.id);
|
|
292
|
+
return (_jsx(SessionListRow, { session: session, width: sessionWidth, depth: 0, focused: activePane === 'list' && sessionTop + index + 1 === sessionIndex, pinned: pins.has(session.id), now: now, liveStatus: state?.live === true ? state.status : undefined, current: state?.current === true, occupiedPid: holder, spinner: { frame: spinnerFrame, time: spinnerTime }, onClick: (event) => {
|
|
293
|
+
event.stopImmediatePropagation();
|
|
294
|
+
setFocusSessionId(session.id);
|
|
295
|
+
openSession(session);
|
|
296
|
+
}, onTogglePin: () => {
|
|
297
|
+
setFocusSessionId(session.id);
|
|
298
|
+
persistPin(session.id, !pins.has(session.id));
|
|
299
|
+
}, onContextMenu: (event) => {
|
|
300
|
+
setFocusSessionId(session.id);
|
|
301
|
+
const entry = selected;
|
|
302
|
+
if (entry === undefined)
|
|
303
|
+
return;
|
|
304
|
+
const next = { path: entry.path, col: event.col, row: event.row, item: 0 };
|
|
305
|
+
menuRef.current = next;
|
|
306
|
+
setMenu(next);
|
|
307
|
+
} }, session.id));
|
|
308
|
+
})] }), _jsx(Box, { flexShrink: 0, height: 1, overflow: "hidden", children: _jsx(Text, { color: notice?.tone === 'error' ? 'error' : 'success', children: notice === undefined ? ' ' : ` ${truncateWidth(notice.text, Math.max(0, sessionWidth - 3))}` }) }), _jsx(Box, { flexShrink: 0, children: _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: filtered ? t('supervisor-hint-filter') : t('supervisor-hint-list') }) }) })] })] }), rename !== undefined && (_jsx(Box, { height: 1, flexShrink: 0, children: _jsx(SearchBox, { query: rename.draft, isFocused: true, isTerminalFocused: isTerminalFocused, placeholder: t('home-rename-placeholder'), prefix: "\u270E", borderless: true, width: "100%" }) })), confirmRemove !== undefined && (_jsx(Box, { flexShrink: 0, paddingX: 1, onClick: () => {
|
|
309
|
+
const path = confirmRemove;
|
|
310
|
+
setConfirmRemove(undefined);
|
|
311
|
+
removeEntry(path);
|
|
312
|
+
}, children: _jsx(Text, { color: "error", children: truncateWidth(` ${t('home-remove-title', { name: railEntries.find(entry => samePath(entry.path, confirmRemove))?.title ?? confirmRemove })} · ${t('home-remove-detail')}`, columns - 3) }) })), menu !== undefined && (_jsx(Box, { position: "absolute", left: Math.max(0, Math.min(menu.col - inset.x + 1, Math.max(0, columns - MENU_WIDTH))), top: Math.max(0, Math.min(menu.row - inset.y + 1, Math.max(0, rows - MENU_HEIGHT))), width: MENU_WIDTH, height: MENU_HEIGHT, flexDirection: "column", flexShrink: 0, borderStyle: "round", borderColor: "permission", backgroundColor: "toolCardBackground", children: MENU_ACTIONS.map((action, index) => (_jsx(Box, { height: 1, flexShrink: 0, backgroundColor: index === menu.item ? 'userMessageBackgroundHover' : undefined, onMouseEnter: () => setMenu(current => (current === undefined ? current : { ...current, item: index })), onClick: (event) => {
|
|
313
|
+
event.stopImmediatePropagation();
|
|
314
|
+
const entry = railEntries.find(candidate => samePath(candidate.path, menu.path));
|
|
315
|
+
if (entry !== undefined)
|
|
316
|
+
activateMenu(entry, index);
|
|
317
|
+
}, children: _jsx(Text, { color: action === 'remove' ? 'error' : undefined, children: ` ${index === menu.item ? '❯' : ' '} ${t(MENU_LABEL_KEYS[action])}` }) }, action))) })), approval !== null && (_jsx(Box, { flexShrink: 0, flexDirection: "column", position: "absolute", bottom: 1, left: 0, width: columns, children: _jsx(ApprovalPanel, { approval: approval, background: approval.agentId !== channel.agentId, onDecide: onApprove }) }))] }));
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Scroll anchor for the rail: the first entry index to show.
|
|
321
|
+
*
|
|
322
|
+
* A pure helper (exported for the headless regression) because the rail's
|
|
323
|
+
* window has to hold the focused row without re-shuffling under a stationary
|
|
324
|
+
* cursor — the same anchoring rule the session list uses.
|
|
325
|
+
*
|
|
326
|
+
* `focus` is a plain entry index: the rail's rows ARE the ledger, so the cursor
|
|
327
|
+
* and the selection are one position and the window math takes that position
|
|
328
|
+
* directly. It used to be offset by the `+` row that led the rail, which is
|
|
329
|
+
* gone — a workspace joins the ledger by being a terminal's launch directory.
|
|
330
|
+
*
|
|
331
|
+
* `capacity` is a count of ENTRIES, not of terminal rows. It used to be handed
|
|
332
|
+
* the row count, which is wrong for this list in a way that hides the cursor:
|
|
333
|
+
* each entry is {@link WORKSPACE_ROW_LINES} rows tall, so treating rows as
|
|
334
|
+
* entries made the window believe it could show twice as many workspaces as it
|
|
335
|
+
* can, and the focused entry was simply clipped away by `overflow="hidden"`
|
|
336
|
+
* while the user navigated it blind.
|
|
337
|
+
*/
|
|
338
|
+
export function railWindowTop(focus, entryCount, capacity) {
|
|
339
|
+
const entries = Math.max(1, capacity);
|
|
340
|
+
if (focus < 0)
|
|
341
|
+
return 0;
|
|
342
|
+
let top = Math.max(0, focus - entries + 1);
|
|
343
|
+
if (focus < top)
|
|
344
|
+
top = focus;
|
|
345
|
+
if (focus >= top + entries)
|
|
346
|
+
top = focus - entries + 1;
|
|
347
|
+
return Math.min(top, Math.max(0, entryCount - entries));
|
|
348
|
+
}
|
|
349
|
+
/** Re-exported so a regression can drive the spinner without importing ink. */
|
|
350
|
+
export { SpinnerGlyph };
|
|
@@ -335,8 +335,8 @@ export function SessionTree({ channel, currentSessionId, onClose, onRestoreText,
|
|
|
335
335
|
askAdopt(entry);
|
|
336
336
|
};
|
|
337
337
|
// ── Keyboard ────────────────────────────────────────────────────────────
|
|
338
|
-
// Keys are read through refs for the same reason
|
|
339
|
-
// several key events can arrive in one stdin chunk before React re-renders.
|
|
338
|
+
// Keys are read through refs for the same reason the other keyed screens do
|
|
339
|
+
// it: several key events can arrive in one stdin chunk before React re-renders.
|
|
340
340
|
const focusIndexRef = React.useRef(focusIndex);
|
|
341
341
|
focusIndexRef.current = focusIndex;
|
|
342
342
|
const visibleRef = React.useRef(visible);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../../src/screens/Settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAuP3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"Settings.d.ts","sourceRoot":"","sources":["../../../src/screens/Settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAczB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAuP3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAojBlB"}
|
|
@@ -96,8 +96,8 @@ function CardRow({ children, highlight, color = CARD_BORDER, }) {
|
|
|
96
96
|
* their `*` / badge feedback.
|
|
97
97
|
*/
|
|
98
98
|
export function Settings({ channel, onClose, }) {
|
|
99
|
-
// Explicit terminal size (not flexGrow) — the same rule
|
|
100
|
-
//
|
|
99
|
+
// Explicit terminal size (not flexGrow) — the same rule the full-screen
|
|
100
|
+
// session views follow inside the alternate screen's fixed-height box.
|
|
101
101
|
const { columns, rows } = useTerminalSize();
|
|
102
102
|
// channel caches the host — a fresh object per call would re-fire the
|
|
103
103
|
// host-keyed effects below on every render (an endless render loop).
|
|
@@ -308,7 +308,7 @@ export function Settings({ channel, onClose, }) {
|
|
|
308
308
|
setEditing(state => state === null ? null : { ...state, draft: state.draft.slice(0, -1) });
|
|
309
309
|
}
|
|
310
310
|
else if (!isMod(key) && !key.meta && !key.super && input && !key.return) {
|
|
311
|
-
// Only real characters reach the draft (see
|
|
311
|
+
// Only real characters reach the draft (see the supervisor's filter).
|
|
312
312
|
const typed = input.replace(/\p{Cc}/gu, '');
|
|
313
313
|
if (typed.length > 0) {
|
|
314
314
|
setEditing(state => state === null ? null : { ...state, draft: state.draft + typed });
|
|
@@ -504,10 +504,22 @@ export function Settings({ channel, onClose, }) {
|
|
|
504
504
|
}
|
|
505
505
|
}
|
|
506
506
|
// Focus-follow window: keep the focused entry fully inside the viewport.
|
|
507
|
+
// The card chrome rows (top border + title, bottom border, section gaps)
|
|
508
|
+
// carry no focus, so the follow rules alone can push them out of the window
|
|
509
|
+
// at the ends of the scroll range — the clamp below keeps the window inside
|
|
510
|
+
// the list's physical bounds, and pins it there while the focus sits at
|
|
511
|
+
// either end of the focus order.
|
|
507
512
|
let totalLines = 0;
|
|
508
513
|
let focusedOffset = 0;
|
|
509
514
|
let focusedLines = 1;
|
|
515
|
+
let firstFocusOffset;
|
|
516
|
+
let lastFocusOffset;
|
|
510
517
|
for (const entry of entries) {
|
|
518
|
+
if (entry.focus !== undefined) {
|
|
519
|
+
if (firstFocusOffset === undefined)
|
|
520
|
+
firstFocusOffset = totalLines;
|
|
521
|
+
lastFocusOffset = totalLines;
|
|
522
|
+
}
|
|
511
523
|
if (entry.focus === effFocus) {
|
|
512
524
|
focusedOffset = totalLines;
|
|
513
525
|
focusedLines = entry.lines;
|
|
@@ -518,15 +530,26 @@ export function Settings({ channel, onClose, }) {
|
|
|
518
530
|
// permanent (blank while quiet) so a save/discard toast never shifts the
|
|
519
531
|
// list above it.
|
|
520
532
|
const viewport = Math.max(1, rows - 4);
|
|
533
|
+
const maxStart = Math.max(0, totalLines - viewport);
|
|
521
534
|
React.useEffect(() => {
|
|
522
535
|
setWindowStart(start => {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
536
|
+
let next = Math.min(Math.max(0, start), maxStart);
|
|
537
|
+
if (focusedOffset < next)
|
|
538
|
+
next = focusedOffset;
|
|
539
|
+
if (focusedOffset + focusedLines > next + viewport)
|
|
540
|
+
next = focusedOffset + focusedLines - viewport;
|
|
541
|
+
// Focus at either end of the focus order pins the window to the list's
|
|
542
|
+
// edge (the card title / bottom border stay visible once the scroll
|
|
543
|
+
// bottoms out) — but only while the focused row stays inside the pinned
|
|
544
|
+
// window: a viewport too small for the edge must keep hiding chrome
|
|
545
|
+
// rather than ever hiding the focus.
|
|
546
|
+
if (firstFocusOffset !== undefined && focusedOffset <= firstFocusOffset && focusedOffset + focusedLines <= viewport)
|
|
547
|
+
return 0;
|
|
548
|
+
if (lastFocusOffset !== undefined && focusedOffset >= lastFocusOffset && focusedOffset >= maxStart)
|
|
549
|
+
return maxStart;
|
|
550
|
+
return next;
|
|
528
551
|
});
|
|
529
|
-
}, [focusedOffset, focusedLines, viewport]);
|
|
552
|
+
}, [focusedOffset, focusedLines, viewport, maxStart, firstFocusOffset, lastFocusOffset]);
|
|
530
553
|
let entryOffset = 0;
|
|
531
554
|
const visible = entries.filter(entry => {
|
|
532
555
|
const start = entryOffset;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { type ActivityLineValue } from '../components/ActivityLine.js';
|
|
2
3
|
import type { ChannelUi as Channel } from '../adapter/channel/ui-policy.js';
|
|
3
4
|
import type { WaveBand } from '../dsh-adapter/types.js';
|
|
4
|
-
export declare function StatusLine({ channel, selectionActive, helpOpen, wake, }: {
|
|
5
|
+
export declare function StatusLine({ channel, selectionActive, helpOpen, wake, activity: projectedActivity, }: {
|
|
5
6
|
channel: Channel;
|
|
6
7
|
selectionActive?: boolean;
|
|
7
8
|
helpOpen?: boolean;
|
|
9
|
+
/** Activity value published by the working-activity plugin for this session.
|
|
10
|
+
* Preferred over the channel's own copy when the composition provides it. */
|
|
11
|
+
activity?: ActivityLineValue;
|
|
8
12
|
/**
|
|
9
13
|
* The session projected onto the status line's few columns, plus the
|
|
10
14
|
* animation tick and the self-retiring key hint.
|
|
@@ -27,5 +31,18 @@ type UsageSnapshot = {
|
|
|
27
31
|
};
|
|
28
32
|
/** Return the prompt-cache hit rate, or nothing when usage is unavailable. */
|
|
29
33
|
export declare function formatCacheHitRate(usage: UsageSnapshot | undefined): string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* The prompt footer's live IDE-selection badge (T-FIX-02), mirroring Claude
|
|
36
|
+
* Code's `⧉ N lines selected`: English only (like every other footer field),
|
|
37
|
+
* singular/plural aware, line count from the snapshot's 0-based inclusive
|
|
38
|
+
* range. `undefined` (no IDE yet / cleared by an isEmpty notification)
|
|
39
|
+
* renders no field at all — a manually launched session never shows a
|
|
40
|
+
* placeholder. Exported for scripts/verify-ide-channel.tsx.
|
|
41
|
+
*/
|
|
42
|
+
export declare function formatSelectionBadge(selection: {
|
|
43
|
+
startLine: number;
|
|
44
|
+
endLine: number;
|
|
45
|
+
isEmpty?: boolean;
|
|
46
|
+
} | undefined): string | undefined;
|
|
30
47
|
export {};
|
|
31
48
|
//# sourceMappingURL=StatusLine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../../src/screens/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,EAAoC,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAOxG,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAkB3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAqHvD,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAuB,EACvB,QAAgB,EAChB,IAAI,EACJ,QAAQ,EAAE,iBAAiB,GAC5B,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACvD,qBA8ZA;AAED,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AA4KD,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKvF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EACL;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,SAAS,GACZ,MAAM,GAAG,SAAS,CAIpB"}
|