@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
|
@@ -14,25 +14,29 @@ import { foldLongLines } from '../../utils/fold-long-lines.js';
|
|
|
14
14
|
import { getLang, t } from '../../i18n.js';
|
|
15
15
|
import { revealLinesOf, snapReveal } from '../smoothReveal.js';
|
|
16
16
|
import { useRevealVersion } from '../../hooks/useRevealVersion.js';
|
|
17
|
-
/** Tool display names
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
/** Tool display names localize through the `tool-name-*` dictionary family
|
|
18
|
+
* (i18n.ts): DSH emits lowercase tool ids (`bash`), display names resolve
|
|
19
|
+
* per language — proper nouns (Bash, PowerShell) stay identical in zh.
|
|
20
|
+
* Unmapped ids (plugins, new upstream tools) fall back to the id with its
|
|
21
|
+
* first letter uppercased: that is a name, not copy — there is nothing to
|
|
22
|
+
* translate. Keys appear as literals here, so verify-i18n's dead-key scan
|
|
23
|
+
* sees them without a DYNAMIC_PREFIXES entry. */
|
|
24
|
+
const TOOL_NAME_KEYS = {
|
|
25
|
+
bash: 'tool-name-bash',
|
|
26
|
+
powershell: 'tool-name-powershell',
|
|
27
|
+
read: 'tool-name-read',
|
|
28
|
+
glob: 'tool-name-glob',
|
|
29
|
+
grep: 'tool-name-grep',
|
|
30
|
+
write: 'tool-name-write',
|
|
31
|
+
edit: 'tool-name-edit',
|
|
32
|
+
todo_write: 'tool-name-todo_write',
|
|
33
|
+
subagent: 'tool-name-subagent',
|
|
34
|
+
web_search: 'tool-name-web_search',
|
|
35
|
+
};
|
|
20
36
|
function displayName(name) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
read: 'Read',
|
|
25
|
-
glob: 'Glob',
|
|
26
|
-
grep: 'Grep',
|
|
27
|
-
write: 'Write',
|
|
28
|
-
edit: 'Edit',
|
|
29
|
-
todo_write: 'TodoWrite',
|
|
30
|
-
subagent: 'Task',
|
|
31
|
-
web_search: 'WebSearch',
|
|
32
|
-
};
|
|
33
|
-
const mapped = KNOWN[name];
|
|
34
|
-
if (mapped)
|
|
35
|
-
return mapped;
|
|
37
|
+
const key = TOOL_NAME_KEYS[name];
|
|
38
|
+
if (key !== undefined)
|
|
39
|
+
return t(key);
|
|
36
40
|
if (name.length === 0)
|
|
37
41
|
return name;
|
|
38
42
|
return name[0].toUpperCase() + name.slice(1);
|
|
@@ -145,10 +149,10 @@ function viewLines(view) {
|
|
|
145
149
|
const out = (('output' in view ? view.output : undefined) ?? '').trimEnd();
|
|
146
150
|
const lines = out === '' ? [] : out.split('\n').map(plain);
|
|
147
151
|
if ('exitCode' in view && view.exitCode !== undefined && view.exitCode !== 0) {
|
|
148
|
-
lines.push({ text:
|
|
152
|
+
lines.push({ text: t('tool-exit-code', { code: view.exitCode }), tone: 'error' });
|
|
149
153
|
}
|
|
150
154
|
if ('signal' in view && view.signal !== undefined) {
|
|
151
|
-
lines.push({ text:
|
|
155
|
+
lines.push({ text: t('tool-killed-signal', { name: String(view.signal) }), tone: 'error' });
|
|
152
156
|
}
|
|
153
157
|
return lines;
|
|
154
158
|
}
|
|
@@ -160,7 +164,7 @@ function viewLines(view) {
|
|
|
160
164
|
if (view.shape === 'paths') {
|
|
161
165
|
const lines = view.paths.map(plain);
|
|
162
166
|
if (view.truncated)
|
|
163
|
-
lines.push(dim(
|
|
167
|
+
lines.push(dim(t('search-results-total', { n: view.total })));
|
|
164
168
|
return lines;
|
|
165
169
|
}
|
|
166
170
|
const lines = [];
|
|
@@ -187,7 +191,7 @@ function capLines(lines, max, verbose) {
|
|
|
187
191
|
return lines;
|
|
188
192
|
return [
|
|
189
193
|
...lines.slice(0, max),
|
|
190
|
-
{ ...dim(
|
|
194
|
+
{ ...dim(t('lines-folded-expand', { n: lines.length - max })), revealOnHover: true },
|
|
191
195
|
];
|
|
192
196
|
}
|
|
193
197
|
/** Long-line clip for the body rows (utils/fold-long-lines.ts): the line cap
|
|
@@ -326,7 +330,7 @@ function HeaderTitle({ name, title, isTerminal, folded, displayArgs, argsLanguag
|
|
|
326
330
|
return (_jsxs(_Fragment, { children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { bold: true, color: nameColor, wrap: "truncate-end", children: name }) }), displayArgs !== '' && (_jsxs(Box, { flexWrap: "nowrap", ...headerTooltip, children: [_jsx(Text, { children: "(" }), _jsx(SyntaxText, { text: clipHeaderArgs(displayArgs), sourceText: displayArgs, language: argsLanguage }), _jsx(Text, { children: ")" })] }))] }));
|
|
327
331
|
}
|
|
328
332
|
if (isTerminal) {
|
|
329
|
-
return (_jsxs(_Fragment, { children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { bold: true, color: nameColor, wrap: "truncate-end", children: name }) }), _jsx(Box, { flexWrap: "nowrap", ...headerTooltip, children: folded === undefined ? (_jsxs(Text, { children: ["(", title, ")"] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["(", folded.first, ")"] }), folded.hiddenLines > 0 && (_jsx(Text, { dimColor: true, children: `
|
|
333
|
+
return (_jsxs(_Fragment, { children: [_jsx(Box, { flexShrink: 0, children: _jsx(Text, { bold: true, color: nameColor, wrap: "truncate-end", children: name }) }), _jsx(Box, { flexWrap: "nowrap", ...headerTooltip, children: folded === undefined ? (_jsxs(Text, { children: ["(", title, ")"] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["(", folded.first, ")"] }), folded.hiddenLines > 0 && (_jsx(Text, { dimColor: true, children: ` ${t('lines-folded-expand', { n: folded.hiddenLines })}` }))] })) })] }));
|
|
330
334
|
}
|
|
331
335
|
const trimmed = title.trim();
|
|
332
336
|
if (trimmed === '') {
|
|
@@ -439,7 +443,7 @@ export function AssistantToolUseMessage({ tool, marginTopOnTurn, verbose, isSele
|
|
|
439
443
|
body = result.trimEnd().split('\n').map(plain);
|
|
440
444
|
}
|
|
441
445
|
if (isRunning && body.length === 0) {
|
|
442
|
-
body = [dim(
|
|
446
|
+
body = [dim(t('tool-running-elapsed', { duration: formatDuration(Math.max(0, Date.now() - (tool.startedAt ?? Date.now()))) }))];
|
|
443
447
|
}
|
|
444
448
|
}
|
|
445
449
|
const cap = view?.card === 'diff' ? DIFF_BODY_MAX_LINES : TEXT_BODY_MAX_LINES;
|
|
@@ -479,8 +483,8 @@ export function AssistantToolUseMessage({ tool, marginTopOnTurn, verbose, isSele
|
|
|
479
483
|
// Hover affordance for the click-to-toggle row: the theme's tool-card blue
|
|
480
484
|
// face marks the call's content area while the pointer dwells (the
|
|
481
485
|
// toolBackground treatment steps up one level to the strong card face), the
|
|
482
|
-
// collapsed
|
|
483
|
-
// clock stops dimming, and a ▾/▴ discloses the row is a toggle.
|
|
486
|
+
// collapsed fold hint (lines-folded-expand) steps from dim to text, the
|
|
487
|
+
// elapsed clock stops dimming, and a ▾/▴ discloses the row is a toggle.
|
|
484
488
|
// No layout change: the indicator is a fixed column on the header line, the
|
|
485
489
|
// body never moves.
|
|
486
490
|
const [hovered, setHovered] = React.useState(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserPromptMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/UserPromptMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"UserPromptMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/UserPromptMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAEjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,eAAe,EAAE,OAAO,CAAA;IACxB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,eAAe,EACf,UAAkB,EAClB,OAAO,GACR,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAiCzB"}
|
|
@@ -3,7 +3,6 @@ import { Box, Text, useTerminalSize } from '../../ui.js';
|
|
|
3
3
|
import { POINTER } from '../../terminal-utils/figures.js';
|
|
4
4
|
import { stringWidth } from '../../ink/stringWidth.js';
|
|
5
5
|
import { wrapWidth } from '../../sessions/format.js';
|
|
6
|
-
import { useTooltip } from '../Tooltip.js';
|
|
7
6
|
/**
|
|
8
7
|
* User prompt bubble: `❯ text` in bold userPromptLabel gold with no background
|
|
9
8
|
* fill (Kimi Code style: the user turn gets a distinct bold tint so it reads
|
|
@@ -21,10 +20,9 @@ export function UserPromptMessage({ text, marginTopOnTurn, isSelected = false, o
|
|
|
21
20
|
// Ink; a second wrap would move the continuation back to column zero.
|
|
22
21
|
const lines = wrapWidth(text, Math.max(1, columns - prefixWidth - 3));
|
|
23
22
|
const continuationIndent = ' '.repeat(prefixWidth);
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return (_jsx(Box, { flexDirection: "column", marginTop: marginTopOnTurn ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, paddingRight: 1, onClick: onClick, ...(tooltipActive ? promptTooltip : {}), children: lines.map((line, index) => (_jsxs(Text, { color: "userPromptLabel", bold: true, wrap: "truncate-end", children: [index === 0 ? `${POINTER} ` : continuationIndent, line] }, index))) }));
|
|
23
|
+
// No hover tooltip here, deliberately: the message is pre-wrapped so every
|
|
24
|
+
// visual line is already on screen — a float would only repeat visible
|
|
25
|
+
// text, and worse, the card REPLACES the cells it covers, so a drag-copy
|
|
26
|
+
// crossing it yields the tooltip fragment instead of the message.
|
|
27
|
+
return (_jsx(Box, { flexDirection: "column", marginTop: marginTopOnTurn ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, paddingRight: 1, onClick: onClick, children: lines.map((line, index) => (_jsxs(Text, { color: "userPromptLabel", bold: true, wrap: "truncate-end", children: [index === 0 ? `${POINTER} ` : continuationIndent, line] }, index))) }));
|
|
30
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useImageInspection.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/useImageInspection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACxF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"useImageInspection.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/useImageInspection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACxF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAQ/D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAC1G,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM;;;aA4ErC,MAAM,KAAK,MAAM,KAAG,IAAI;kBAfI,SAAS;EAmBjD"}
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ImageInspectionSession, inspectionRegion } from './imageInspection.js';
|
|
3
3
|
import { loadTranscriptImageFull } from './TranscriptImages.js';
|
|
4
|
+
// The attachment is identified by `image.id` (a content hash), never by the
|
|
5
|
+
// facade object: callers may hand a fresh facade for the same attachment on
|
|
6
|
+
// every render, and keying effects or memos on the object would then restart
|
|
7
|
+
// the session and re-request pixels each commit — a render loop (#885).
|
|
4
8
|
export function useImageInspection(image, available, columns, rows, cell, zoom) {
|
|
9
|
+
const imageId = image.id;
|
|
10
|
+
// Committed facade for the loaders below. Written in a layout effect, not
|
|
11
|
+
// during render: an interrupted render must not leak its facade into a
|
|
12
|
+
// timer that an earlier commit already scheduled.
|
|
13
|
+
const latestImage = React.useRef(image);
|
|
14
|
+
React.useLayoutEffect(() => { latestImage.current = image; }, [image]);
|
|
5
15
|
const session = React.useRef(null);
|
|
6
16
|
const [position, setPosition] = React.useState(null);
|
|
7
|
-
const center = position?.
|
|
17
|
+
const center = position?.imageId === imageId ? position.center : undefined;
|
|
8
18
|
const dimensions = React.useRef(null);
|
|
9
19
|
React.useEffect(() => {
|
|
10
|
-
const current = new ImageInspectionSession(
|
|
20
|
+
const current = new ImageInspectionSession(latestImage.current);
|
|
11
21
|
session.current = current;
|
|
12
22
|
dimensions.current = null;
|
|
13
23
|
setPosition(null);
|
|
14
24
|
return () => { current.dispose(); session.current = null; };
|
|
15
|
-
}, [
|
|
16
|
-
const request = React.useMemo(() => ({
|
|
25
|
+
}, [imageId]);
|
|
26
|
+
const request = React.useMemo(() => ({ imageId, available, columns, rows, cell, zoom, center }), [imageId, available, columns, rows, cell, zoom, center]);
|
|
17
27
|
const [result, setResult] = React.useState(null);
|
|
18
28
|
React.useEffect(() => {
|
|
19
29
|
if (!available || (zoom > 0 && !cell))
|
|
@@ -25,7 +35,7 @@ export function useImageInspection(image, available, columns, rows, cell, zoom)
|
|
|
25
35
|
const timer = setTimeout(() => {
|
|
26
36
|
void (async () => {
|
|
27
37
|
if (zoom === 0)
|
|
28
|
-
return loadTranscriptImageFull(
|
|
38
|
+
return loadTranscriptImageFull(latestImage.current, controller.signal);
|
|
29
39
|
const size = await current.metadata();
|
|
30
40
|
controller.signal.throwIfAborted();
|
|
31
41
|
dimensions.current = size;
|
|
@@ -53,9 +63,9 @@ export function useImageInspection(image, available, columns, rows, cell, zoom)
|
|
|
53
63
|
return;
|
|
54
64
|
const next = clampedCenter({ x: previous.x + x, y: previous.y + y });
|
|
55
65
|
if (next)
|
|
56
|
-
setPosition(old => old?.
|
|
57
|
-
? old : {
|
|
58
|
-
}, [clampedCenter,
|
|
66
|
+
setPosition(old => old?.imageId === imageId && old.center.x === next.x && old.center.y === next.y
|
|
67
|
+
? old : { imageId, center: next });
|
|
68
|
+
}, [clampedCenter, imageId]);
|
|
59
69
|
const dragOrigin = React.useRef(undefined);
|
|
60
70
|
const drag = React.useCallback((event) => {
|
|
61
71
|
event.stopImmediatePropagation();
|
|
@@ -70,7 +80,7 @@ export function useImageInspection(image, available, columns, rows, cell, zoom)
|
|
|
70
80
|
}, [cell, zoom, clampedCenter, move]);
|
|
71
81
|
// Preserve the previous pixels while panning, but never stretch stale pixels
|
|
72
82
|
// across a new geometry, zoom, terminal cell size, or attachment.
|
|
73
|
-
const reusable = result?.request.
|
|
83
|
+
const reusable = result?.request.imageId === imageId && result.request.zoom === zoom &&
|
|
74
84
|
result.request.columns === columns && result.request.rows === rows && result.request.cell === cell;
|
|
75
85
|
return {
|
|
76
86
|
source: available && reusable ? result?.source : undefined,
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composer draft that a screen hands to its owner on the way out.
|
|
3
|
+
*
|
|
4
|
+
* Every screen that REPLACES the conversation (`/resume`'s session screen, the
|
|
5
|
+
* session tree, `/settings`, the jobs panel, the trajectory scene) is an early
|
|
6
|
+
* return in `Chat`, so `PromptInput` is unmounted while the user is away and
|
|
7
|
+
* its text, caret and staged-image bindings live in component state. The owner
|
|
8
|
+
* therefore holds one slot of this type and the composer fills it as it
|
|
9
|
+
* unmounts; on the way back it is read, checked and consumed.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately dependency-free (it does not import `PromptInput`, which would
|
|
12
|
+
* be a cycle), so the component and the headless regressions can both assert
|
|
13
|
+
* against the same rules.
|
|
14
|
+
*
|
|
15
|
+
* The snapshot shape, the image-liveness rule and the carried edit state
|
|
16
|
+
* (fold block, fullscreen editor, vim mode) are taken from PR #847
|
|
17
|
+
* (`promptDraftCache.ts`, branch `fix/composer-draft-retention`); the owner
|
|
18
|
+
* check here adds the agent id, because a generation alone cannot tell two
|
|
19
|
+
* channels with a fixed generation apart.
|
|
20
|
+
*/
|
|
21
|
+
/** One token → staged-image capability pair, in visible order. */
|
|
22
|
+
export type PromptDraftImage = readonly [token: string, stageId: string];
|
|
23
|
+
/**
|
|
24
|
+
* Everything the composer needs to put a draft back exactly as it was left.
|
|
25
|
+
*
|
|
26
|
+
* Transient interaction state — mouse selection, drag anchor, suggestion menu,
|
|
27
|
+
* history position, editor scroll, the vim undo stack — is NOT here: it
|
|
28
|
+
* describes a composer that was on screen, not the draft that outlives it.
|
|
29
|
+
*/
|
|
30
|
+
export interface PromptDraftSnapshot {
|
|
31
|
+
/** Agent the draft was typed into; a different one means "not this draft". */
|
|
32
|
+
readonly ownerAgentId: string;
|
|
33
|
+
/** Binding generation at capture time; see {@link resolveBindingGeneration}. */
|
|
34
|
+
readonly bindingGeneration: number;
|
|
35
|
+
readonly value: string;
|
|
36
|
+
readonly cursor: number;
|
|
37
|
+
/**
|
|
38
|
+
* Fold block [start, end) rendering as a one-line chip, or null. Edit
|
|
39
|
+
* state, not transient chrome: coming back with the text unfolded loses
|
|
40
|
+
* exactly what the user folded.
|
|
41
|
+
*/
|
|
42
|
+
readonly foldBlock: {
|
|
43
|
+
readonly start: number;
|
|
44
|
+
readonly end: number;
|
|
45
|
+
} | null;
|
|
46
|
+
/** Fullscreen draft editor open at capture time. */
|
|
47
|
+
readonly expanded: boolean;
|
|
48
|
+
/** vim mode on (`/vim`), and whether it is in INSERT (vs NORMAL) submode. */
|
|
49
|
+
readonly vimEnabled: boolean;
|
|
50
|
+
readonly vimInsert: boolean;
|
|
51
|
+
/** Visible `[Image #N]` token → staged stageId, so images survive the trip. */
|
|
52
|
+
readonly images: readonly PromptDraftImage[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The single slot an owner (today: `Chat`) keeps for the composer draft.
|
|
56
|
+
*
|
|
57
|
+
* A mutable ref-shaped cell rather than React state: it is written from an
|
|
58
|
+
* unmount cleanup and read from a mount effect, and neither may trigger a
|
|
59
|
+
* render — a draft that changed the first frame would move the transcript's
|
|
60
|
+
* restored scroll position.
|
|
61
|
+
*/
|
|
62
|
+
export interface PromptDraftCache {
|
|
63
|
+
current: PromptDraftSnapshot | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The current binding generation, mirroring the channel expression: the agent
|
|
67
|
+
* binding generation advances on every agent replacement (`/resume` to another
|
|
68
|
+
* session, `/new`, `/bg`, attach, rewind) and wins; a simplified or embedded
|
|
69
|
+
* channel without it falls back to the staged-image generation, and 0 when it
|
|
70
|
+
* has neither.
|
|
71
|
+
* @param source - The channel, or anything carrying the same two members.
|
|
72
|
+
* @returns The generation the snapshot is fenced against.
|
|
73
|
+
*/
|
|
74
|
+
export declare function resolveBindingGeneration(source: {
|
|
75
|
+
readonly agentBindingGeneration?: number;
|
|
76
|
+
readonly stagedImageGeneration?: () => number;
|
|
77
|
+
}): number;
|
|
78
|
+
/**
|
|
79
|
+
* Whether a stored draft belongs to the conversation in front of us now.
|
|
80
|
+
*
|
|
81
|
+
* Both halves are required. The generation catches a replaced binding; the
|
|
82
|
+
* agent id catches the case a generation cannot describe — a test or embedded
|
|
83
|
+
* channel whose generation is a constant, where a stale draft would otherwise
|
|
84
|
+
* be adopted by a different conversation.
|
|
85
|
+
* @param snapshot - The stored draft, if any.
|
|
86
|
+
* @param ownerAgentId - Agent id of the composer that would restore it.
|
|
87
|
+
* @param generation - Current binding generation.
|
|
88
|
+
*/
|
|
89
|
+
export declare function isUsableDraftSnapshot(snapshot: PromptDraftSnapshot | null | undefined, ownerAgentId: string, generation: number): snapshot is PromptDraftSnapshot;
|
|
90
|
+
/**
|
|
91
|
+
* Drop the image bindings whose capability is gone.
|
|
92
|
+
*
|
|
93
|
+
* A visible `[Image #N]` is only a label; what makes it an attachment is the
|
|
94
|
+
* stageId behind it. A session switch (or a discard) revokes the capability and
|
|
95
|
+
* the label must not be re-bound by reading the number back out of the text.
|
|
96
|
+
* Entries that fail the check are dropped silently and the caller keeps the
|
|
97
|
+
* visible token as ordinary text, which is the behaviour an edit already has.
|
|
98
|
+
* @param images - Stored pairs.
|
|
99
|
+
* @param hasStagedImage - Channel capability probe; absent means "none live".
|
|
100
|
+
*/
|
|
101
|
+
export declare function filterLiveImageBindings(images: readonly PromptDraftImage[] | null | undefined, hasStagedImage?: (stageId: string) => boolean): readonly PromptDraftImage[];
|
|
102
|
+
//# sourceMappingURL=promptDraftCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promptDraftCache.d.ts","sourceRoot":"","sources":["../../../src/components/promptDraftCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,kEAAkE;AAClE,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;AAExE;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC3E,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAC7C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;IACxC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,MAAM,CAAA;CAC9C,GAAG,MAAM,CAET;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EAChD,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,QAAQ,IAAI,mBAAmB,CAKjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,IAAI,GAAG,SAAS,EACtD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GAC5C,SAAS,gBAAgB,EAAE,CAW7B"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The composer draft that a screen hands to its owner on the way out.
|
|
3
|
+
*
|
|
4
|
+
* Every screen that REPLACES the conversation (`/resume`'s session screen, the
|
|
5
|
+
* session tree, `/settings`, the jobs panel, the trajectory scene) is an early
|
|
6
|
+
* return in `Chat`, so `PromptInput` is unmounted while the user is away and
|
|
7
|
+
* its text, caret and staged-image bindings live in component state. The owner
|
|
8
|
+
* therefore holds one slot of this type and the composer fills it as it
|
|
9
|
+
* unmounts; on the way back it is read, checked and consumed.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately dependency-free (it does not import `PromptInput`, which would
|
|
12
|
+
* be a cycle), so the component and the headless regressions can both assert
|
|
13
|
+
* against the same rules.
|
|
14
|
+
*
|
|
15
|
+
* The snapshot shape, the image-liveness rule and the carried edit state
|
|
16
|
+
* (fold block, fullscreen editor, vim mode) are taken from PR #847
|
|
17
|
+
* (`promptDraftCache.ts`, branch `fix/composer-draft-retention`); the owner
|
|
18
|
+
* check here adds the agent id, because a generation alone cannot tell two
|
|
19
|
+
* channels with a fixed generation apart.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The current binding generation, mirroring the channel expression: the agent
|
|
23
|
+
* binding generation advances on every agent replacement (`/resume` to another
|
|
24
|
+
* session, `/new`, `/bg`, attach, rewind) and wins; a simplified or embedded
|
|
25
|
+
* channel without it falls back to the staged-image generation, and 0 when it
|
|
26
|
+
* has neither.
|
|
27
|
+
* @param source - The channel, or anything carrying the same two members.
|
|
28
|
+
* @returns The generation the snapshot is fenced against.
|
|
29
|
+
*/
|
|
30
|
+
export function resolveBindingGeneration(source) {
|
|
31
|
+
return source.agentBindingGeneration ?? source.stagedImageGeneration?.() ?? 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether a stored draft belongs to the conversation in front of us now.
|
|
35
|
+
*
|
|
36
|
+
* Both halves are required. The generation catches a replaced binding; the
|
|
37
|
+
* agent id catches the case a generation cannot describe — a test or embedded
|
|
38
|
+
* channel whose generation is a constant, where a stale draft would otherwise
|
|
39
|
+
* be adopted by a different conversation.
|
|
40
|
+
* @param snapshot - The stored draft, if any.
|
|
41
|
+
* @param ownerAgentId - Agent id of the composer that would restore it.
|
|
42
|
+
* @param generation - Current binding generation.
|
|
43
|
+
*/
|
|
44
|
+
export function isUsableDraftSnapshot(snapshot, ownerAgentId, generation) {
|
|
45
|
+
return snapshot !== null
|
|
46
|
+
&& snapshot !== undefined
|
|
47
|
+
&& snapshot.ownerAgentId === ownerAgentId
|
|
48
|
+
&& snapshot.bindingGeneration === generation;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Drop the image bindings whose capability is gone.
|
|
52
|
+
*
|
|
53
|
+
* A visible `[Image #N]` is only a label; what makes it an attachment is the
|
|
54
|
+
* stageId behind it. A session switch (or a discard) revokes the capability and
|
|
55
|
+
* the label must not be re-bound by reading the number back out of the text.
|
|
56
|
+
* Entries that fail the check are dropped silently and the caller keeps the
|
|
57
|
+
* visible token as ordinary text, which is the behaviour an edit already has.
|
|
58
|
+
* @param images - Stored pairs.
|
|
59
|
+
* @param hasStagedImage - Channel capability probe; absent means "none live".
|
|
60
|
+
*/
|
|
61
|
+
export function filterLiveImageBindings(images, hasStagedImage) {
|
|
62
|
+
if (images === null || images === undefined)
|
|
63
|
+
return [];
|
|
64
|
+
const live = [];
|
|
65
|
+
for (const entry of images) {
|
|
66
|
+
if (!Array.isArray(entry) || entry.length !== 2)
|
|
67
|
+
continue;
|
|
68
|
+
const [token, stageId] = entry;
|
|
69
|
+
if (typeof token !== 'string' || typeof stageId !== 'string')
|
|
70
|
+
continue;
|
|
71
|
+
if (hasStagedImage?.(stageId) !== true)
|
|
72
|
+
continue;
|
|
73
|
+
live.push([token, stageId]);
|
|
74
|
+
}
|
|
75
|
+
return live;
|
|
76
|
+
}
|
|
@@ -72,6 +72,22 @@ export type AskUserQuestionPanelProps = {
|
|
|
72
72
|
* verification injects a fake so paste outcomes are deterministic.
|
|
73
73
|
*/
|
|
74
74
|
readonly readClipboardOverride?: () => Promise<ClipboardRead>;
|
|
75
|
+
/**
|
|
76
|
+
* Manual collapse (question panel fold, default Ctrl+K): while
|
|
77
|
+
* collapsed the panel STAYS MOUNTED — draft refs survive, the fold
|
|
78
|
+
* branch sits after every hook — and renders the two-line minimized
|
|
79
|
+
* bar instead, with editing/caret layers gated off. Its own input
|
|
80
|
+
* handler keeps Esc/Ctrl+C as "expand", never cancel, while folded.
|
|
81
|
+
*/
|
|
82
|
+
readonly collapsed?: boolean;
|
|
83
|
+
/** Expand back from the minimized bar (fold key / Esc / mouse click). */
|
|
84
|
+
readonly onExpand?: () => void;
|
|
85
|
+
/** Fold from the expanded panel (fold key / header-row click). */
|
|
86
|
+
readonly onToggleFold?: () => void;
|
|
87
|
+
/** True when mouse tracking is on: mouse-only affordances (the
|
|
88
|
+
* multi-select submit row) render only then — inline hosts have no
|
|
89
|
+
* pointer, so an unclickable row would just eat a line. */
|
|
90
|
+
readonly fullscreen?: boolean;
|
|
75
91
|
};
|
|
76
|
-
export declare function AskUserQuestionPanel({ question, position, total, answered, initialDraft, onAnswer, onCancel, onBack, readClipboardOverride, }: AskUserQuestionPanelProps): React.ReactNode;
|
|
92
|
+
export declare function AskUserQuestionPanel({ question, position, total, answered, initialDraft, onAnswer, onCancel, onBack, readClipboardOverride, collapsed, onExpand, onToggleFold, fullscreen, }: AskUserQuestionPanelProps): React.ReactNode;
|
|
77
93
|
//# sourceMappingURL=AskUserQuestionPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AskUserQuestionPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/AskUserQuestionPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"AskUserQuestionPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/AskUserQuestionPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAMtF,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAkB5E,MAAM,MAAM,yBAAyB,GAAG;IACtC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAC3F,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;QAC9B;;oEAE4D;QAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;QAClC;;qEAE6D;QAC7D,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC5C;0EACkE;QAClE,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;YAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAA;KAC7E,CAAA;IACD,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACzD,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAChD;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IAC7D;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IAClC;;gEAE4D;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,qBAAqB,EACrB,SAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,UAAkB,GACnB,EAAE,yBAAyB,GAAG,KAAK,CAAC,SAAS,CAsmB7C"}
|
|
@@ -32,8 +32,9 @@ import { useDeclaredCursor } from '../../ink/hooks/use-declared-cursor.js';
|
|
|
32
32
|
import { Divider } from '../design-system/Divider.js';
|
|
33
33
|
import { POINTER } from '../../terminal-utils/figures.js';
|
|
34
34
|
import { PlanReviewPanel } from './PlanReviewPanel.js';
|
|
35
|
+
import { QuestionMinimizedBar } from './QuestionMinimizedBar.js';
|
|
35
36
|
import { isPlainReturnInput } from '../../utils/modifiers.js';
|
|
36
|
-
import { actionMatches } from '../../utils/keymap.js';
|
|
37
|
+
import { actionMatches, effectiveComboDisplay } from '../../utils/keymap.js';
|
|
37
38
|
import { flattenPasteInline } from '../../dsh-adapter/sanitize.js';
|
|
38
39
|
import { readClipboard } from '../../utils/clipboard.js';
|
|
39
40
|
import { listWindow } from '../listWindow.js';
|
|
@@ -50,7 +51,7 @@ const PENCIL = '✎';
|
|
|
50
51
|
* PlanReviewPanel (the two panels share the same input contract).
|
|
51
52
|
*/
|
|
52
53
|
const ANSWER_PASTE_MAX_POINTS = 8000;
|
|
53
|
-
export function AskUserQuestionPanel({ question, position, total, answered, initialDraft, onAnswer, onCancel, onBack, readClipboardOverride, }) {
|
|
54
|
+
export function AskUserQuestionPanel({ question, position, total, answered, initialDraft, onAnswer, onCancel, onBack, readClipboardOverride, collapsed = false, onExpand, onToggleFold, fullscreen = false, }) {
|
|
54
55
|
// Plan-mode's exit_plan_mode ask carries a presentation intent: render
|
|
55
56
|
// the plan decision card instead of the generic questionnaire. The
|
|
56
57
|
// branch precedes every hook so hook order stays stable per remount key.
|
|
@@ -134,7 +135,7 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
134
135
|
// three visual variants): its nodeCache rect IS the caret cell, so (0, 0)
|
|
135
136
|
// stays exact under CJK widths and line wrapping without any
|
|
136
137
|
// layout-affecting wrapper Box.
|
|
137
|
-
const caretRef = useDeclaredCursor({ line: 0, column: 0, active: !hideCustomInput });
|
|
138
|
+
const caretRef = useDeclaredCursor({ line: 0, column: 0, active: !hideCustomInput && !collapsed });
|
|
138
139
|
const moveFocus = (delta) => {
|
|
139
140
|
if (rowCount <= 1)
|
|
140
141
|
return;
|
|
@@ -277,7 +278,22 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
277
278
|
...(textRef.current !== '' ? { custom: textRef.current } : {}),
|
|
278
279
|
};
|
|
279
280
|
};
|
|
280
|
-
useInput((input, key) => {
|
|
281
|
+
useInput((input, key, event) => {
|
|
282
|
+
// The mounted panel owns folding, just like answering: hidden asks
|
|
283
|
+
// cannot steal approval/dialog keys, and an interrupting questionnaire
|
|
284
|
+
// still works when Chat yields to an underlying screen's open flag.
|
|
285
|
+
if (onToggleFold !== undefined && actionMatches('questionFold', input, key)) {
|
|
286
|
+
onToggleFold();
|
|
287
|
+
event.stopImmediatePropagation();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (collapsed) {
|
|
291
|
+
if (key.escape || (key.ctrl && input === 'c')) {
|
|
292
|
+
onExpand?.();
|
|
293
|
+
event.stopImmediatePropagation();
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
281
297
|
if (key.ctrl && input === 'c') {
|
|
282
298
|
onCancel();
|
|
283
299
|
return;
|
|
@@ -410,9 +426,14 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
410
426
|
if (!multiSelect)
|
|
411
427
|
setAttached(options[focusIndex]?.label ?? null);
|
|
412
428
|
}
|
|
413
|
-
}
|
|
429
|
+
});
|
|
414
430
|
const remaining = total - answered;
|
|
431
|
+
/** Fold shortcut label for the hint row (follows /settings remaps). */
|
|
432
|
+
const foldCombo = effectiveComboDisplay('questionFold');
|
|
415
433
|
const headerTitle = ` ${t('question-header-progress', { position, total, remaining: remaining > 1 ? t('question-remaining-more', { n: remaining }) : '' })} `;
|
|
434
|
+
/** First line of the question body for the minimized bar (whitespace
|
|
435
|
+
* flattened the same way windowedOptions flattens labels). */
|
|
436
|
+
const questionText = question.question.split('\n')[0]?.replace(/\s+/gu, ' ').trim() ?? '';
|
|
416
437
|
// The caret counts code points (see the module header), so the caret
|
|
417
438
|
// char and the visual split index into the point array — never raw
|
|
418
439
|
// UTF-16 offsets, which could land inside a surrogate pair.
|
|
@@ -450,6 +471,10 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
450
471
|
onAnswer({ selected: [label], ...(text !== '' ? { custom: text } : {}) });
|
|
451
472
|
};
|
|
452
473
|
const [hoverIndex, setHoverIndex] = React.useState(-1);
|
|
474
|
+
/** Header row hover — the row doubles as the mouse fold/unfold affordance. */
|
|
475
|
+
const [headerHovered, setHeaderHovered] = React.useState(false);
|
|
476
|
+
/** Mouse submit row hover (multi-select: clicking submits the checked set). */
|
|
477
|
+
const [submitHovered, setSubmitHovered] = React.useState(false);
|
|
453
478
|
const renderInputRow = () => (_jsxs(Box, { flexDirection: "row", marginTop: inputFocused ? 1 : 0, onClick: focusInputRow, onMouseEnter: () => setHoverIndex(options.length), onMouseLeave: () => setHoverIndex(current => (current === options.length ? -1 : current)), backgroundColor: hoverIndex === options.length && !inputFocused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'accent' : undefined, bold: inputFocused, children: inputFocused ? POINTER : ' ' }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: inputFocused ? 'accent' : 'suggestion', children: PENCIL }) }), _jsxs(Box, { flexDirection: "row", marginLeft: 1, children: [_jsx(Text, { bold: inputFocused, color: inputFocused ? 'accent' : 'suggestion', children: t('question-custom-tab') }), attached !== null && (_jsx(Text, { color: "suggestion", children: t('question-attached-label', { label: attached }) })), _jsx(Text, { dimColor: true, children: "\uFF1A" }), customText === '' && !inputFocused ? (_jsx(Text, { ref: caretRef, dimColor: true, children: t('question-direct-input') })) : (_jsxs(_Fragment, { children: [_jsx(Text, { wrap: "wrap", children: textPoints.slice(0, customCursor).join('') }), inputFocused
|
|
454
479
|
? _jsx(Text, { ref: caretRef, inverse: true, children: cursorChar })
|
|
455
480
|
: _jsx(Text, { ref: caretRef, color: "suggestion", children: "\u258F" }), _jsx(Text, { wrap: "wrap", children: textPoints.slice(inputFocused ? customCursor + 1 : customCursor).join('') })] }))] })] }));
|
|
@@ -469,7 +494,7 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
469
494
|
? option.description?.replace(/\s+/gu, ' ').trim()
|
|
470
495
|
: option.description;
|
|
471
496
|
return (_jsxs(Box, { flexDirection: "row", marginTop: !windowedOptions && focused ? 1 : 0, onClick: () => clickOption(absoluteIndex), onMouseEnter: () => setHoverIndex(absoluteIndex), onMouseLeave: () => setHoverIndex(current => (current === absoluteIndex ? -1 : current)), backgroundColor: hoverIndex === absoluteIndex && !focused ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'accent' : undefined, bold: focused, children: pointer }) }), _jsx(Box, { width: 1, flexShrink: 0, children: _jsx(Text, { color: focused ? 'accent' : undefined, bold: selected, children: selected ? (multiSelect ? CHECKED : '●') : UNCHECKED }) }), _jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsx(Text, { bold: focused || selected, color: focused ? 'accent' : undefined, wrap: windowedOptions ? 'truncate' : 'wrap', children: label }), description !== undefined && (_jsx(Text, { dimColor: true, wrap: windowedOptions ? 'truncate' : 'wrap', children: description }))] })] }, `${absoluteIndex}:${option.label}`));
|
|
472
|
-
}), hideCustomInput ? null : renderInputRow()] }));
|
|
497
|
+
}), hideCustomInput ? null : renderInputRow(), multiSelect && fullscreen && (checked.size > 0 || textRef.current !== '') && (_jsxs(Box, { flexDirection: "row", height: 1, marginTop: 1, onClick: submitOptions, onMouseEnter: () => setSubmitHovered(true), onMouseLeave: () => setSubmitHovered(false), backgroundColor: submitHovered ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { color: "accent", children: "\u2713 " }), _jsx(Text, { dimColor: true, children: t('question-submit-selection') })] }))] }));
|
|
473
498
|
const hintParts = inputFocused
|
|
474
499
|
? [
|
|
475
500
|
t('question-hint-type'),
|
|
@@ -479,6 +504,7 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
479
504
|
onBack === undefined ? t('question-hint-esc') : t('question-hint-previous'),
|
|
480
505
|
...(onBack === undefined ? [] : [t('question-hint-cancel')]),
|
|
481
506
|
...(multiSelect && checked.size > 0 ? [t('question-hint-selected', { n: checked.size })] : []),
|
|
507
|
+
t('question-fold-hint', { combo: foldCombo }),
|
|
482
508
|
]
|
|
483
509
|
: [
|
|
484
510
|
t('question-hint-select'),
|
|
@@ -488,6 +514,13 @@ export function AskUserQuestionPanel({ question, position, total, answered, init
|
|
|
488
514
|
onBack === undefined ? t('question-hint-esc') : t('question-hint-previous'),
|
|
489
515
|
...(onBack === undefined ? [] : [t('question-hint-cancel')]),
|
|
490
516
|
...(multiSelect && checked.size > 0 ? [t('question-hint-selected', { n: checked.size })] : []),
|
|
517
|
+
t('question-fold-hint', { combo: foldCombo }),
|
|
491
518
|
];
|
|
492
|
-
|
|
519
|
+
// Folded: render only the minimized bar. This branch sits AFTER every
|
|
520
|
+
// hook (and after the intent early-return), so folding never reorders
|
|
521
|
+
// hooks and the draft refs above stay alive for the expand.
|
|
522
|
+
if (collapsed) {
|
|
523
|
+
return _jsx(QuestionMinimizedBar, { progress: headerTitle, questionText: questionText, onExpand: onExpand ?? (() => { }) });
|
|
524
|
+
}
|
|
525
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, paddingRight: 2, width: "100%", children: [_jsx(Box, { flexDirection: "column", onClick: onToggleFold, onMouseEnter: () => setHeaderHovered(true), onMouseLeave: () => setHeaderHovered(false), backgroundColor: headerHovered ? 'userMessageBackgroundHover' : undefined, children: _jsx(Divider, { color: "permission", title: `▾${headerTitle}` }) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [question.header !== undefined && (_jsxs(Text, { color: "suggestion", bold: true, children: ["\u25C8 ", question.header] })), _jsx(Text, { bold: true, wrap: "wrap", children: question.question }), question.detail !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: question.detail.split('\n').map((line, index) => (_jsx(Text, { dimColor: true, italic: true, wrap: "wrap", children: line }, index))) }))] }), renderOptions(), error !== null && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "error", children: error }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: hintParts.join(' · ') }) })] }));
|
|
493
526
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type QuestionMinimizedBarProps = {
|
|
3
|
+
/** Progress title, same text as the expanded panel's Divider header
|
|
4
|
+
* (e.g. ` 📋 提问 · 第 2/5 题 · 还剩 3 题 `). */
|
|
5
|
+
readonly progress: string;
|
|
6
|
+
/** First line of the question body, truncated by the layout. */
|
|
7
|
+
readonly questionText: string;
|
|
8
|
+
/** Expand back to the full panel (Ctrl+K / Esc / click). */
|
|
9
|
+
readonly onExpand: () => void;
|
|
10
|
+
};
|
|
11
|
+
export declare function QuestionMinimizedBar({ progress, questionText, onExpand, }: QuestionMinimizedBarProps): React.ReactNode;
|
|
12
|
+
//# sourceMappingURL=QuestionMinimizedBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuestionMinimizedBar.d.ts","sourceRoot":"","sources":["../../../../src/components/questions/QuestionMinimizedBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AA0BzB,MAAM,MAAM,yBAAyB,GAAG;IACtC;+CAC2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,EAAE,yBAAyB,GAAG,KAAK,CAAC,SAAS,CAwC7C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from '../../ui.js';
|
|
4
|
+
import { t } from '../../i18n.js';
|
|
5
|
+
import { effectiveComboDisplay } from '../../utils/keymap.js';
|
|
6
|
+
/**
|
|
7
|
+
* 提问面板挂起条 — the two-line stand-in for a folded questionnaire
|
|
8
|
+
* (manual collapse; the ask stays parked and the panel stays mounted, so
|
|
9
|
+
* drafts survive).
|
|
10
|
+
*
|
|
11
|
+
* Line 1 mirrors the GoalTodoPanel fold-header language: a dim `▸` (folded
|
|
12
|
+
* state), the same progress title as the expanded header, then the first
|
|
13
|
+
* line of the question truncated to whatever width remains. The whole row
|
|
14
|
+
* is clickable (fullscreen mouse) and hover-highlighted to expand.
|
|
15
|
+
*
|
|
16
|
+
* Line 2 is the permanent "answer pending" affordance — a blinking pause
|
|
17
|
+
* glyph (`⏸` toggled dim/bright on a local interval that lives only while
|
|
18
|
+
* the bar is mounted) plus the waiting text and the fold key hint. The key
|
|
19
|
+
* label follows keymap remaps via effectiveComboString, like the /settings
|
|
20
|
+
* shortcut rows.
|
|
21
|
+
*
|
|
22
|
+
* The component is deliberately dumb: the parent formats the strings, so
|
|
23
|
+
* the bar owns only its local hover/blink state.
|
|
24
|
+
*/
|
|
25
|
+
const BLINK_MS = 500;
|
|
26
|
+
export function QuestionMinimizedBar({ progress, questionText, onExpand, }) {
|
|
27
|
+
const [blinkOn, setBlinkOn] = React.useState(true);
|
|
28
|
+
const [hovered, setHovered] = React.useState(false);
|
|
29
|
+
// The pause glyph blinks by APPEARING and DISAPPEARING (a visible→gone
|
|
30
|
+
// beat reads as a true blink; dim↔normal is too subtle). The off phase
|
|
31
|
+
// must occupy exactly the glyph's width or the waiting text shifts left
|
|
32
|
+
// and right every beat: '⏸ ' measures 2 columns (⏸ is a narrow 1-col
|
|
33
|
+
// glyph here), so it is replaced by two spaces. Blink only while the
|
|
34
|
+
// bar exists; unmounting clears the interval.
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
const id = setInterval(() => setBlinkOn(previous => !previous), BLINK_MS);
|
|
37
|
+
return () => clearInterval(id);
|
|
38
|
+
}, []);
|
|
39
|
+
const waiting = `${t('question-fold-waiting')} — ${t('question-fold-expand', {
|
|
40
|
+
combo: effectiveComboDisplay('questionFold'),
|
|
41
|
+
})}`;
|
|
42
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, paddingLeft: 2, paddingRight: 2, width: "100%", children: [_jsxs(Box, { flexDirection: "row", height: 1, onClick: onExpand, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), backgroundColor: hovered ? 'userMessageBackgroundHover' : undefined, children: [_jsx(Text, { dimColor: true, children: '▸ ' }), _jsx(Text, { dimColor: true, children: progress }), _jsx(Box, { flexGrow: 1, flexShrink: 1, marginLeft: 1, children: _jsx(Text, { wrap: "truncate", children: questionText }) })] }), _jsxs(Box, { flexDirection: "row", height: 1, children: [_jsx(Text, { children: blinkOn ? '⏸ ' : ' ' }), _jsx(Text, { dimColor: true, wrap: "truncate", children: waiting })] })] }));
|
|
43
|
+
}
|