@deepseek-harness-tui/dsh-tui 0.8.8 → 0.9.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 +60 -238
- package/bin/dsh-tui.js +172 -5
- package/cordis.patch.yml +16 -4
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
- package/dsh-ecosystem-spec/registry/README.md +14 -14
- package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
- package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
- package/lib/types/cc/hyperlink.d.ts +7 -1
- package/lib/types/cc/hyperlink.d.ts.map +1 -1
- package/lib/types/cc/hyperlink.js +3 -2
- package/lib/types/cc/markdown.d.ts.map +1 -1
- package/lib/types/cc/markdown.js +33 -3
- package/lib/types/cc/sessionColors.d.ts +27 -0
- package/lib/types/cc/sessionColors.d.ts.map +1 -0
- package/lib/types/cc/sessionColors.js +39 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +10 -2
- package/lib/types/components/ActivityPicker.d.ts +4 -1
- package/lib/types/components/ActivityPicker.d.ts.map +1 -1
- package/lib/types/components/ActivityPicker.js +2 -2
- package/lib/types/components/AutoRecapRow.d.ts +23 -0
- package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
- package/lib/types/components/AutoRecapRow.js +23 -0
- package/lib/types/components/BtwPanel.d.ts.map +1 -1
- package/lib/types/components/BtwPanel.js +1 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts +2 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
- package/lib/types/components/Chat/SubagentMessage.js +11 -3
- package/lib/types/components/ColorPicker.d.ts +17 -0
- package/lib/types/components/ColorPicker.d.ts.map +1 -0
- package/lib/types/components/ColorPicker.js +20 -0
- package/lib/types/components/CommandSuggestions.d.ts +23 -4
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +41 -14
- package/lib/types/components/ContextBarView.d.ts +33 -0
- package/lib/types/components/ContextBarView.d.ts.map +1 -0
- package/lib/types/components/ContextBarView.js +46 -0
- package/lib/types/components/EffortInputBorder.d.ts +12 -1
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
- package/lib/types/components/EffortInputBorder.js +22 -5
- package/lib/types/components/EffortSlider.d.ts +4 -1
- package/lib/types/components/EffortSlider.d.ts.map +1 -1
- package/lib/types/components/EffortSlider.js +4 -2
- package/lib/types/components/ExtensionDialog.js +6 -2
- package/lib/types/components/FileActionsPanel.d.ts +22 -0
- package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
- package/lib/types/components/FileActionsPanel.js +28 -0
- package/lib/types/components/FileSuggestions.d.ts +26 -7
- package/lib/types/components/FileSuggestions.d.ts.map +1 -1
- package/lib/types/components/FileSuggestions.js +39 -12
- package/lib/types/components/GoalTodoPanel.d.ts +26 -2
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +86 -17
- package/lib/types/components/HelpMenu.d.ts +7 -1
- package/lib/types/components/HelpMenu.d.ts.map +1 -1
- package/lib/types/components/HelpMenu.js +12 -4
- package/lib/types/components/HistorySearchDialog.d.ts +4 -1
- package/lib/types/components/HistorySearchDialog.d.ts.map +1 -1
- package/lib/types/components/HistorySearchDialog.js +2 -2
- package/lib/types/components/LangPicker.d.ts +14 -0
- package/lib/types/components/LangPicker.d.ts.map +1 -0
- package/lib/types/components/LangPicker.js +17 -0
- package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
- package/lib/types/components/LoadedContextPanel.js +3 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +12 -3
- package/lib/types/components/MessageList.d.ts +45 -2
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +560 -41
- package/lib/types/components/ModelPicker.d.ts +27 -2
- package/lib/types/components/ModelPicker.d.ts.map +1 -1
- package/lib/types/components/ModelPicker.js +26 -6
- package/lib/types/components/PermissionsPicker.d.ts +21 -0
- package/lib/types/components/PermissionsPicker.d.ts.map +1 -0
- package/lib/types/components/PermissionsPicker.js +27 -0
- package/lib/types/components/PlanPicker.d.ts +15 -0
- package/lib/types/components/PlanPicker.d.ts.map +1 -0
- package/lib/types/components/PlanPicker.js +18 -0
- package/lib/types/components/PresetPicker.d.ts +4 -1
- package/lib/types/components/PresetPicker.d.ts.map +1 -1
- package/lib/types/components/PresetPicker.js +2 -2
- package/lib/types/components/PromptInput.d.ts +4 -3
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +602 -75
- package/lib/types/components/RecapPanel.d.ts +25 -0
- package/lib/types/components/RecapPanel.d.ts.map +1 -0
- package/lib/types/components/RecapPanel.js +55 -0
- package/lib/types/components/RewindPicker.d.ts +12 -1
- package/lib/types/components/RewindPicker.d.ts.map +1 -1
- package/lib/types/components/RewindPicker.js +6 -4
- package/lib/types/components/ScrollbarGutter.d.ts +28 -0
- package/lib/types/components/ScrollbarGutter.d.ts.map +1 -0
- package/lib/types/components/ScrollbarGutter.js +119 -0
- package/lib/types/components/Select.d.ts +8 -1
- package/lib/types/components/Select.d.ts.map +1 -1
- package/lib/types/components/Select.js +4 -2
- package/lib/types/components/SkillsPicker.d.ts +4 -1
- package/lib/types/components/SkillsPicker.d.ts.map +1 -1
- package/lib/types/components/SkillsPicker.js +2 -2
- package/lib/types/components/SubagentCard.d.ts +2 -1
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +9 -2
- package/lib/types/components/SubagentDashboard.d.ts +4 -0
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +9 -1
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +5 -4
- package/lib/types/components/SuggestionCard.d.ts +65 -0
- package/lib/types/components/SuggestionCard.d.ts.map +1 -0
- package/lib/types/components/SuggestionCard.js +77 -0
- package/lib/types/components/ThemePicker.d.ts +4 -1
- package/lib/types/components/ThemePicker.d.ts.map +1 -1
- package/lib/types/components/ThemePicker.js +2 -2
- package/lib/types/components/ThinkingToggle.d.ts +4 -1
- package/lib/types/components/ThinkingToggle.d.ts.map +1 -1
- package/lib/types/components/ThinkingToggle.js +2 -2
- package/lib/types/components/TimelineRail.d.ts +53 -0
- package/lib/types/components/TimelineRail.d.ts.map +1 -0
- package/lib/types/components/TimelineRail.js +197 -0
- package/lib/types/components/WorkspaceFlowPicker.d.ts +6 -1
- package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
- package/lib/types/components/WorkspaceFlowPicker.js +4 -2
- package/lib/types/components/WorkspaceMenuPicker.d.ts +19 -0
- package/lib/types/components/WorkspaceMenuPicker.d.ts.map +1 -0
- package/lib/types/components/WorkspaceMenuPicker.js +19 -0
- package/lib/types/components/WorkspacePicker.d.ts +4 -1
- package/lib/types/components/WorkspacePicker.d.ts.map +1 -1
- package/lib/types/components/WorkspacePicker.js +2 -2
- package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
- package/lib/types/components/approvals/ApprovalPanel.js +5 -1
- package/lib/types/components/design-system/ListItem.d.ts +8 -1
- package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
- package/lib/types/components/design-system/ListItem.js +8 -3
- package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
- package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemeProvider.js +2 -1
- package/lib/types/components/messages/AssistantTextMessage.d.ts +5 -2
- package/lib/types/components/messages/AssistantTextMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantTextMessage.js +6 -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 +10 -4
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +15 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +37 -7
- package/lib/types/components/messages/UserPromptMessage.d.ts +2 -1
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +75 -11
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +13 -2
- package/lib/types/components/sessions/SessionListRow.d.ts +4 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +4 -2
- package/lib/types/components/trajectory/HotspotView.d.ts +7 -1
- package/lib/types/components/trajectory/HotspotView.d.ts.map +1 -1
- package/lib/types/components/trajectory/HotspotView.js +8 -2
- package/lib/types/components/trajectory/Ledger.d.ts +9 -1
- package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
- package/lib/types/components/trajectory/Ledger.js +23 -5
- package/lib/types/components/trajectory/WaveBand.d.ts +10 -1
- package/lib/types/components/trajectory/WaveBand.d.ts.map +1 -1
- package/lib/types/components/trajectory/WaveBand.js +7 -2
- package/lib/types/dsh-adapter/channel.d.ts +117 -7
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +1301 -122
- package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
- package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/index.js +8 -6
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
- package/lib/types/dsh-adapter/contract.d.ts +1 -1
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +1 -0
- package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
- package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.d.ts +20 -2
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +9 -1
- package/lib/types/dsh-adapter/plugin.d.ts +0 -9
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +453 -14
- package/lib/types/dsh-adapter/presets.d.ts +18 -0
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +31 -0
- package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +89 -5
- package/lib/types/dsh-adapter/questions.d.ts +19 -2
- package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/questions.js +53 -10
- package/lib/types/dsh-adapter/recap.d.ts +49 -0
- package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
- package/lib/types/dsh-adapter/recap.js +121 -0
- package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
- package/lib/types/dsh-adapter/sessionTree.js +954 -0
- package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
- package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
- package/lib/types/dsh-adapter/shortcuts.js +28 -165
- package/lib/types/dsh-adapter/types.d.ts +1 -1
- package/lib/types/dsh-adapter/types.d.ts.map +1 -1
- package/lib/types/herdr.js +1 -1
- package/lib/types/i18n.d.ts +770 -181
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +257 -80
- package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
- package/lib/types/ink/components/AlternateScreen.js +13 -1
- package/lib/types/ink/components/App.d.ts +12 -1
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +101 -4
- package/lib/types/ink/components/ClockContext.d.ts.map +1 -1
- package/lib/types/ink/components/ClockContext.js +2 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +170 -91
- package/lib/types/ink/constants.d.ts +9 -0
- package/lib/types/ink/constants.d.ts.map +1 -1
- package/lib/types/ink/constants.js +9 -0
- package/lib/types/ink/events/click-event.d.ts +7 -16
- package/lib/types/ink/events/click-event.d.ts.map +1 -1
- package/lib/types/ink/events/click-event.js +16 -19
- package/lib/types/ink/events/event-handlers.d.ts +11 -1
- package/lib/types/ink/events/event-handlers.d.ts.map +1 -1
- package/lib/types/ink/events/event-handlers.js +2 -0
- package/lib/types/ink/events/input-event.d.ts +9 -0
- package/lib/types/ink/events/input-event.d.ts.map +1 -1
- package/lib/types/ink/events/input-event.js +4 -0
- package/lib/types/ink/events/pointer-event.d.ts +61 -0
- package/lib/types/ink/events/pointer-event.d.ts.map +1 -0
- package/lib/types/ink/events/pointer-event.js +61 -0
- package/lib/types/ink/events/wheel-event.d.ts +17 -0
- package/lib/types/ink/events/wheel-event.d.ts.map +1 -0
- package/lib/types/ink/events/wheel-event.js +20 -0
- package/lib/types/ink/geometry-trace.d.ts +51 -0
- package/lib/types/ink/geometry-trace.d.ts.map +1 -0
- package/lib/types/ink/geometry-trace.js +83 -0
- package/lib/types/ink/hit-test.d.ts +56 -1
- package/lib/types/ink/hit-test.d.ts.map +1 -1
- package/lib/types/ink/hit-test.js +146 -8
- package/lib/types/ink/ink.d.ts +58 -1
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +230 -29
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +21 -0
- package/lib/types/ink/node-cache.d.ts +5 -0
- package/lib/types/ink/node-cache.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.d.ts +8 -0
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +101 -12
- package/lib/types/ink/render-node-to-output.d.ts +10 -0
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +111 -18
- package/lib/types/ink/timeline-rail.d.ts +138 -0
- package/lib/types/ink/timeline-rail.d.ts.map +1 -0
- package/lib/types/ink/timeline-rail.js +179 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -1
- package/lib/types/ink/wrap-text.js +47 -5
- package/lib/types/migrationPrefs.d.ts +60 -0
- package/lib/types/migrationPrefs.d.ts.map +1 -0
- package/lib/types/migrationPrefs.js +97 -0
- package/lib/types/modelGroups.d.ts +72 -0
- package/lib/types/modelGroups.d.ts.map +1 -0
- package/lib/types/modelGroups.js +97 -0
- package/lib/types/modelRecents.d.ts +39 -0
- package/lib/types/modelRecents.d.ts.map +1 -0
- package/lib/types/modelRecents.js +97 -0
- package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
- package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
- package/lib/types/native-ts/yoga-layout/index.js +31 -1
- package/lib/types/oauth.d.ts +15 -0
- package/lib/types/oauth.d.ts.map +1 -0
- package/lib/types/oauth.js +14 -0
- package/lib/types/reload.d.ts +109 -0
- package/lib/types/reload.d.ts.map +1 -0
- package/lib/types/reload.js +118 -0
- package/lib/types/screens/Chat.d.ts +3 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +1377 -371
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +56 -29
- package/lib/types/screens/SessionTree.d.ts +27 -0
- package/lib/types/screens/SessionTree.d.ts.map +1 -0
- package/lib/types/screens/SessionTree.js +555 -0
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +64 -22
- package/lib/types/screens/StatusLine.d.ts +0 -8
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +224 -45
- package/lib/types/screens/StatusMetrics.d.ts +35 -3
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +63 -8
- package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
- package/lib/types/screens/TrajectoryScene.js +81 -14
- package/lib/types/screens/chatOverlay.d.ts +237 -0
- package/lib/types/screens/chatOverlay.d.ts.map +1 -0
- package/lib/types/screens/chatOverlay.js +116 -0
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +64 -10
- package/lib/types/tuiDisplayPrefs.d.ts +15 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +9 -0
- package/lib/types/update.d.ts +139 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +382 -30
- package/lib/types/utils/debug.d.ts +10 -0
- package/lib/types/utils/debug.d.ts.map +1 -1
- package/lib/types/utils/debug.js +24 -0
- package/lib/types/utils/fileTarget.d.ts +46 -0
- package/lib/types/utils/fileTarget.d.ts.map +1 -0
- package/lib/types/utils/fileTarget.js +178 -0
- package/lib/types/utils/keymap.d.ts +134 -0
- package/lib/types/utils/keymap.d.ts.map +1 -0
- package/lib/types/utils/keymap.js +311 -0
- package/lib/types/utils/mentions.d.ts +25 -2
- package/lib/types/utils/mentions.d.ts.map +1 -1
- package/lib/types/utils/mentions.js +69 -10
- package/lib/types/utils/openExternal.d.ts +50 -0
- package/lib/types/utils/openExternal.d.ts.map +1 -0
- package/lib/types/utils/openExternal.js +170 -0
- package/lib/types/utils/paths.d.ts.map +1 -1
- package/lib/types/utils/paths.js +1 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/command/LICENSE +21 -21
- package/node_modules/@dsh-std/command/README.md +26 -26
- package/node_modules/@dsh-std/command/README.zh.md +28 -28
- package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/command/package.json +22 -22
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/node_modules/@dsh-std/connection/README.md +42 -42
- package/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/node_modules/@dsh-std/connection/package.json +20 -20
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/core/LICENSE +21 -21
- package/node_modules/@dsh-std/core/README.md +13 -13
- package/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/core/package.json +21 -21
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/node_modules/@dsh-std/manifest/README.md +5 -5
- package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/manifest/package.json +20 -20
- package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/messages/LICENSE +21 -21
- package/node_modules/@dsh-std/messages/README.md +5 -5
- package/node_modules/@dsh-std/messages/README.zh.md +7 -7
- package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/messages/package.json +20 -20
- package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/node_modules/@dsh-std/presentation/README.md +27 -27
- package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/presentation/package.json +25 -25
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/storage/LICENSE +21 -21
- package/node_modules/@dsh-std/storage/README.md +5 -5
- package/node_modules/@dsh-std/storage/README.zh.md +7 -7
- package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/storage/package.json +20 -20
- package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
- package/package.json +19 -5
- package/presets/liangshen/.dsh-tui-managed.json +1 -1
- package/presets/liangshen/instruction-hint.mjs +8 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
|
@@ -13,19 +13,22 @@ import { ApprovalStore } from './approvals.js';
|
|
|
13
13
|
import { registerPackagedSkills } from './packaged-skills.js';
|
|
14
14
|
import { registerPromptDebug } from './promptDebug.js';
|
|
15
15
|
import { readActivityFrames } from '../activityPrefs.js';
|
|
16
|
+
import { commitFullscreenFactoryMigration, planFullscreenFactoryMigration, readAppliedMigrations } from '../migrationPrefs.js';
|
|
16
17
|
import { readModelPref } from '../modelPrefs.js';
|
|
17
18
|
import { explicitModelRoute, recordedModelRoute, resolveModelRoute, validateModelRoute } from '../modelRoute.js';
|
|
18
19
|
import { readPresetPref } from '../presetPrefs.js';
|
|
19
|
-
import { composePreset, filterMinimalPresetTools, resolvePersistedPreset, runningPresetOf } from './presets.js';
|
|
20
|
+
import { composePreset, filterMinimalPresetTools, resolvePersistedPreset, resolvePersistedRoute, runningPresetOf } from './presets.js';
|
|
20
21
|
import { ensurePackagedPresets } from './packaged-presets.js';
|
|
21
22
|
import { ensureLegacySessionEventTypes } from './compat/index.js';
|
|
22
23
|
import { clearResumeTarget, writeResumeTarget } from '../sessionHistory.js';
|
|
23
24
|
import { resolveSessionCwd } from '../utils/workspaceRoot.js';
|
|
24
|
-
import { checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isVersionNewer, resolveDshProfileName, resolveTuiUpdateTarget, updateTuiAndRestart } from '../update.js';
|
|
25
|
+
import { beginRestartAttempt, checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isVersionNewer, logRestartEvent, resolveDshProfileName, resolveTuiUpdateTarget, restartTui, updateTuiAndRestart, writeHandoffNotice } from '../update.js';
|
|
25
26
|
import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
|
|
26
|
-
import { DEFAULT_STATUS_BAR, normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
|
|
27
|
+
import { DEFAULT_STATUS_BAR, normalizeScrollGutter, normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
|
|
28
|
+
import { draftComboConflicts, effectiveComboString, parseComboDraft, setKeymapOverrides, SHORTCUT_ACTIONS, } from '../utils/keymap.js';
|
|
27
29
|
import { detectLegacyEnv, migrateLegacyDataDir, RENAMED_ENV } from '../utils/paths.js';
|
|
28
30
|
import { attachHerdrIntegration } from '../herdr.js';
|
|
31
|
+
import { logMouseDebug } from '../utils/debug.js';
|
|
29
32
|
import { Chat } from '../screens/Chat.js';
|
|
30
33
|
import { getHostDialogStore } from './dialogs.js';
|
|
31
34
|
import { getHostStatusStore } from './status.js';
|
|
@@ -48,8 +51,79 @@ import { CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, supportsTabStatus, wrapForMult
|
|
|
48
51
|
* `dsh-jsonrpc`: the surrounding `cordis.yml` supplies the agent spine, the
|
|
49
52
|
* LLM adapter, and the tool plugins.
|
|
50
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* Fullscreen decision latched across host recomposes. The launcher disposes
|
|
56
|
+
* and re-mounts the plugin tree (teardown → apply() runs again) — a fresh
|
|
57
|
+
* apply() re-resolves `bootedFullscreen` from cordis config, and the
|
|
58
|
+
* settings user layer (settings.yaml) can arrive after the 300ms
|
|
59
|
+
* `settingsReady` bound when the recompose is also re-mounting the settings
|
|
60
|
+
* service. The tree would then mount INLINE and `fullscreenFrozen` would
|
|
61
|
+
* swallow the late application — the app lands on the main screen
|
|
62
|
+
* ("exited fullscreen", dead mouse, unpinned input) until restart. A
|
|
63
|
+
* session that already mounted fullscreen must never regress on a
|
|
64
|
+
* recompose: latch the decision.
|
|
65
|
+
*/
|
|
66
|
+
let lastBootedFullscreen;
|
|
51
67
|
export async function apply(ctx, config) {
|
|
68
|
+
// /restart handoff diagnosis: the replacement process is marked by env and
|
|
69
|
+
// logs its boot progress to ~/.dsh-tui/restart.log (ordinary launches stay
|
|
70
|
+
// silent). First line lands before anything in this function can throw.
|
|
71
|
+
if (process.env.DSH_TUI_RESTART_CHILD === '1') {
|
|
72
|
+
logRestartEvent('boot: plugin apply', {
|
|
73
|
+
stdoutTty: process.stdout.isTTY === true,
|
|
74
|
+
stdinTty: process.stdin.isTTY === true,
|
|
75
|
+
stderrTty: process.stderr.isTTY === true,
|
|
76
|
+
});
|
|
77
|
+
// Field evidence (2026-08-24): the restarted TUI mounts but takes no
|
|
78
|
+
// input, and the terminal's DA reply surfaced on PS's prompt line in an
|
|
79
|
+
// earlier attempt — meaning NO process was reading console input. Probe
|
|
80
|
+
// whether THIS process's stdin pump ever sees bytes: wrap read()
|
|
81
|
+
// transparently (delegates; purely observational) and sample the pump
|
|
82
|
+
// state, so the log distinguishes "bytes never arrive" (console-level
|
|
83
|
+
// theft/mode) from "bytes arrive but the UI ignores them".
|
|
84
|
+
const probedStdin = process.stdin;
|
|
85
|
+
const originalRead = probedStdin.read.bind(probedStdin);
|
|
86
|
+
let loggedChunks = 0;
|
|
87
|
+
probedStdin.read = ((...args) => {
|
|
88
|
+
const chunk = originalRead(...args);
|
|
89
|
+
if (chunk !== null && chunk !== '' && loggedChunks < 12) {
|
|
90
|
+
loggedChunks += 1;
|
|
91
|
+
const text = String(chunk);
|
|
92
|
+
logRestartEvent('boot: stdin chunk arrived', {
|
|
93
|
+
bytes: text.length,
|
|
94
|
+
preview: text.slice(0, 24).replace(/[^\x20-\x7e]/g, '.'),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return chunk;
|
|
98
|
+
});
|
|
99
|
+
const sampleStdinState = (label) => {
|
|
100
|
+
logRestartEvent(`boot: ${label}`, {
|
|
101
|
+
isRaw: probedStdin.isRaw === true,
|
|
102
|
+
readableListeners: probedStdin.listenerCount('readable'),
|
|
103
|
+
dataListeners: probedStdin.listenerCount('data'),
|
|
104
|
+
paused: probedStdin.isPaused,
|
|
105
|
+
buffered: probedStdin.readableLength,
|
|
106
|
+
chunksSeen: loggedChunks,
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
sampleStdinState('stdin state at plugin apply');
|
|
110
|
+
let pendingSamples = 0;
|
|
111
|
+
const sampleAt = (delayMs, label) => {
|
|
112
|
+
pendingSamples += 1;
|
|
113
|
+
const timer = setTimeout(() => {
|
|
114
|
+
pendingSamples -= 1;
|
|
115
|
+
sampleStdinState(label);
|
|
116
|
+
}, delayMs);
|
|
117
|
+
timer.unref?.();
|
|
118
|
+
};
|
|
119
|
+
sampleAt(2000, 'stdin state +2s');
|
|
120
|
+
sampleAt(5000, 'stdin state +5s');
|
|
121
|
+
sampleAt(12000, 'stdin state +12s');
|
|
122
|
+
}
|
|
52
123
|
if (!process.stdout.isTTY) {
|
|
124
|
+
if (process.env.DSH_TUI_RESTART_CHILD === '1') {
|
|
125
|
+
logRestartEvent('boot: TTY gate failed - stdout is not a TTY');
|
|
126
|
+
}
|
|
53
127
|
throw new Error('dsh-tui requires an interactive terminal (stdout must be a TTY).');
|
|
54
128
|
}
|
|
55
129
|
// The official profile launcher owns the system preset root and replaces
|
|
@@ -310,6 +384,10 @@ export async function apply(ctx, config) {
|
|
|
310
384
|
// only explicit values so the target session's own record wins.
|
|
311
385
|
configuredModel: config.model,
|
|
312
386
|
configuredProvider: config.provider,
|
|
387
|
+
// Raw cordis.yml `lang` / `activityFrames`: /reload must not override a
|
|
388
|
+
// static deployment choice with the persisted preference.
|
|
389
|
+
configuredLang: config.lang,
|
|
390
|
+
configuredActivityFrames: config.activityFrames,
|
|
313
391
|
effort: config.effort,
|
|
314
392
|
activity: config.activity,
|
|
315
393
|
// Explicit cordis.yml value (static deployment choice) wins over the
|
|
@@ -329,18 +407,44 @@ export async function apply(ctx, config) {
|
|
|
329
407
|
diffLayout: config.diffLayout,
|
|
330
408
|
thinkingFold: config.thinkingFold,
|
|
331
409
|
toolBackground: config.toolBackground,
|
|
410
|
+
scrollGutter: config.scrollGutter,
|
|
411
|
+
promptSessionLabel: config.promptSessionLabel,
|
|
332
412
|
statusBar: config.statusBar,
|
|
333
413
|
handle,
|
|
334
414
|
});
|
|
415
|
+
// Fullscreen layout decision: the settings user layer (edited through the
|
|
416
|
+
// /settings screen) overrides cordis.yml when set. The settings injection
|
|
417
|
+
// below resolves it synchronously when the host settings service is up —
|
|
418
|
+
// i.e. before the tree mounts. `fullscreenFrozen` latches at mount: the
|
|
419
|
+
// exit funnel and the AlternateScreen wrap must keep reading the mode this
|
|
420
|
+
// session ACTUALLY runs, never a mid-session edit meant for the next boot
|
|
421
|
+
// (swapping layouts requires re-mounting the whole tree).
|
|
422
|
+
let bootedFullscreen = config.fullscreen === true;
|
|
423
|
+
let fullscreenFrozen = false;
|
|
424
|
+
// The settings service may come up AFTER this plugin's apply: the cordis
|
|
425
|
+
// inject callback defers until the service registers, so the first
|
|
426
|
+
// `apply(scope.get())` below can land after the mount (field report: the
|
|
427
|
+
// /settings fullscreen toggle never took effect — the frozen latch below
|
|
428
|
+
// swallowed the late callback and bootedFullscreen stayed false). The
|
|
429
|
+
// mount must therefore WAIT for the first settings application (bounded —
|
|
430
|
+
// a bare embedder without a settings service must not deadlock).
|
|
431
|
+
let resolveSettingsReady;
|
|
432
|
+
const settingsReady = new Promise(resolve => {
|
|
433
|
+
resolveSettingsReady = () => resolve();
|
|
434
|
+
setTimeout(resolve, 300);
|
|
435
|
+
});
|
|
335
436
|
// Register the dsh-tui settings namespace so the /settings screen can
|
|
336
437
|
// edit it (the section below was '命名空间未注册' without this): the
|
|
337
438
|
// user layer in settings.yaml wins over cordis.yml's diffLayout, and
|
|
338
439
|
// watch() lands commits on the live channel — no recompose needed.
|
|
339
440
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
340
|
-
const
|
|
441
|
+
const tuiSettingsNs = settingsNamespace('dsh-tui');
|
|
442
|
+
const scope = settingsCtx.settings.register(tuiSettingsNs, Schema.object({
|
|
341
443
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
342
444
|
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
343
445
|
toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
|
|
446
|
+
scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
|
|
447
|
+
promptSessionLabel: Schema.boolean().default(false),
|
|
344
448
|
statusBar: Schema.object({
|
|
345
449
|
compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
|
|
346
450
|
model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
|
|
@@ -352,6 +456,8 @@ export async function apply(ctx, config) {
|
|
|
352
456
|
tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
|
|
353
457
|
gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
|
|
354
458
|
sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
|
|
459
|
+
sessionId: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionId),
|
|
460
|
+
goal: Schema.boolean().default(DEFAULT_STATUS_BAR.goal),
|
|
355
461
|
mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
|
|
356
462
|
contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
|
|
357
463
|
activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
|
|
@@ -367,6 +473,13 @@ export async function apply(ctx, config) {
|
|
|
367
473
|
// the effective language (see the section's format below) and lets
|
|
368
474
|
// cordis.yml / lang.json keep their precedence.
|
|
369
475
|
lang: Schema.union(['zh', 'en']),
|
|
476
|
+
// Same no-default rule: unset keeps cordis.yml's `fullscreen`
|
|
477
|
+
// decisive; set overrides it from the next boot on.
|
|
478
|
+
fullscreen: Schema.boolean(),
|
|
479
|
+
// Built-in action-shortcut overrides, one optional combo string per
|
|
480
|
+
// action (see src/utils/keymap.ts). Unset keeps the default binding
|
|
481
|
+
// and the section's format() shows the effective combos.
|
|
482
|
+
shortcuts: Schema.object(Object.fromEntries(SHORTCUT_ACTIONS.map(action => [action.id, Schema.string().required(false)]))).required(false),
|
|
370
483
|
}));
|
|
371
484
|
const applyLayout = (value) => {
|
|
372
485
|
channel.setDiffLayout(value.diffLayout ?? config.diffLayout ?? 'auto');
|
|
@@ -377,6 +490,15 @@ export async function apply(ctx, config) {
|
|
|
377
490
|
const applyMinimal = (value) => {
|
|
378
491
|
channel.setMinimal(value.minimal ?? false);
|
|
379
492
|
};
|
|
493
|
+
// Fullscreen: only meaningful before the tree mounts (the freeze latch
|
|
494
|
+
// above). A later doc change (mid-session /settings edit) is persisted
|
|
495
|
+
// by the service and picked up on the next boot; the watch below says
|
|
496
|
+
// so with a notify.
|
|
497
|
+
const applyFullscreen = (value) => {
|
|
498
|
+
if (!fullscreenFrozen && typeof value.fullscreen === 'boolean') {
|
|
499
|
+
bootedFullscreen = value.fullscreen;
|
|
500
|
+
}
|
|
501
|
+
};
|
|
380
502
|
// The /settings language field writes `lang` through the settings
|
|
381
503
|
// service (user layer): apply it live and mirror it to lang.json so
|
|
382
504
|
// the /lang command and next-boot resolution agree. DSH_TUI_LANG
|
|
@@ -393,30 +515,173 @@ export async function apply(ctx, config) {
|
|
|
393
515
|
const applyDisplay = (value) => {
|
|
394
516
|
channel.setThinkingFold(value.thinkingFold ?? config.thinkingFold ?? 'preview');
|
|
395
517
|
channel.setToolBackground(normalizeToolBackground(value.toolBackground ?? config.toolBackground));
|
|
518
|
+
channel.setScrollGutter(normalizeScrollGutter(value.scrollGutter ?? config.scrollGutter));
|
|
519
|
+
channel.setPromptSessionLabel(value.promptSessionLabel ?? config.promptSessionLabel ?? false);
|
|
396
520
|
channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
|
|
397
521
|
};
|
|
522
|
+
// Shortcut overrides resolve per action: settings user layer wins over
|
|
523
|
+
// cordis.yml's `shortcuts` (same precedence as every other field);
|
|
524
|
+
// unset everywhere keeps the registry default. Applied live into the
|
|
525
|
+
// keymap module — the very next keypress matches the new combos.
|
|
526
|
+
const applyShortcuts = (value) => {
|
|
527
|
+
const userLayer = value.shortcuts ?? {};
|
|
528
|
+
const configLayer = config.shortcuts ?? {};
|
|
529
|
+
const merged = {};
|
|
530
|
+
for (const action of SHORTCUT_ACTIONS) {
|
|
531
|
+
const user = userLayer[action.id];
|
|
532
|
+
const pinned = configLayer[action.id];
|
|
533
|
+
const chosen = typeof user === 'string' && user.trim() !== ''
|
|
534
|
+
? user
|
|
535
|
+
: (typeof pinned === 'string' && pinned.trim() !== '' ? pinned : undefined);
|
|
536
|
+
if (chosen !== undefined)
|
|
537
|
+
merged[action.id] = chosen;
|
|
538
|
+
}
|
|
539
|
+
setKeymapOverrides(merged);
|
|
540
|
+
};
|
|
398
541
|
const apply = (next) => {
|
|
399
542
|
applyLayout(next);
|
|
400
543
|
applyWhale(next);
|
|
401
544
|
applyMinimal(next);
|
|
402
545
|
applyLang(next);
|
|
403
546
|
applyDisplay(next);
|
|
547
|
+
applyShortcuts(next);
|
|
548
|
+
applyFullscreen(next);
|
|
404
549
|
};
|
|
405
|
-
|
|
550
|
+
// One-time fullscreen factory-default migration (companion to the
|
|
551
|
+
// schema + cordis.patch.yml flip false→true): a `fullscreen: false`
|
|
552
|
+
// pinned in the settings user layer BEFORE the flip keeps overriding
|
|
553
|
+
// the new default on every boot. The first boot past this code clears
|
|
554
|
+
// that stale explicit choice; the migrations.json marker makes it
|
|
555
|
+
// strictly once, so a `false` re-pinned afterwards always stands. The
|
|
556
|
+
// boot decision cannot wait for the async doc write — the stale value
|
|
557
|
+
// is shadowed out of the first apply below (destructuring omission,
|
|
558
|
+
// not an explicit undefined), and the later watch commit (fullscreen
|
|
559
|
+
// back to undefined) is a no-op for applyFullscreen.
|
|
560
|
+
const bootSettings = scope.get();
|
|
561
|
+
const fullscreenMigration = planFullscreenFactoryMigration(bootSettings.fullscreen, readAppliedMigrations());
|
|
562
|
+
void commitFullscreenFactoryMigration(fullscreenMigration, {
|
|
563
|
+
unset: () => settingsCtx.settings.mutate(tuiSettingsNs, [{ op: 'unset', path: ['fullscreen'] }]),
|
|
564
|
+
});
|
|
565
|
+
if (fullscreenMigration === 'unset') {
|
|
566
|
+
channel.notify(t('settings-fullscreen-migrated'), { color: 'warning' });
|
|
567
|
+
}
|
|
568
|
+
const { fullscreen: staleFullscreen, ...migratedSettings } = bootSettings;
|
|
569
|
+
apply(fullscreenMigration === 'unset' ? migratedSettings : bootSettings);
|
|
406
570
|
scope.watch(next => {
|
|
407
571
|
apply(next);
|
|
572
|
+
if (typeof next.fullscreen === 'boolean' && next.fullscreen !== bootedFullscreen) {
|
|
573
|
+
channel.notify(t('settings-fullscreen-restart'), { color: 'warning' });
|
|
574
|
+
}
|
|
408
575
|
});
|
|
576
|
+
resolveSettingsReady?.();
|
|
409
577
|
});
|
|
410
578
|
// The /settings screen's own section: the dsh-tui namespace comes from
|
|
411
579
|
// the settings registration above, and the declared selects write `lang`
|
|
412
580
|
// and `diffLayout` back through the settings service's revision-fenced
|
|
413
581
|
// mutate (the watch applies both live).
|
|
582
|
+
//
|
|
583
|
+
// Shortcut fields: one text field per customizable action. The draft is
|
|
584
|
+
// one or more ctrl+/alt+ combos (comma-separated); blank restores the
|
|
585
|
+
// default, and a combo another action or a fixed editor binding already
|
|
586
|
+
// owns is refused as invalid so remaps can never silently shadow.
|
|
587
|
+
const shortcutFieldMeta = {
|
|
588
|
+
paste: {
|
|
589
|
+
label: 'Paste shortcut',
|
|
590
|
+
zh: '粘贴快捷键',
|
|
591
|
+
hintEn: d => `Clipboard paste (text, file paths, images). Default: ${d}. Alt+V works where the terminal eats Ctrl+V.`,
|
|
592
|
+
hintZh: d => `剪贴板粘贴(文本、文件路径、图片)。默认 ${d}。终端吞掉 Ctrl+V 时可用 Alt+V。`,
|
|
593
|
+
},
|
|
594
|
+
history: {
|
|
595
|
+
label: 'History search shortcut',
|
|
596
|
+
zh: '历史搜索快捷键',
|
|
597
|
+
hintEn: d => `Open the prompt-history search. Default: ${d}.`,
|
|
598
|
+
hintZh: d => `打开输入历史搜索。默认 ${d}。`,
|
|
599
|
+
},
|
|
600
|
+
editor: {
|
|
601
|
+
label: 'External editor shortcut',
|
|
602
|
+
zh: '外部编辑器快捷键',
|
|
603
|
+
hintEn: d => `Edit the draft in $VISUAL/$EDITOR. Default: ${d}.`,
|
|
604
|
+
hintZh: d => `在 $VISUAL/$EDITOR 外部编辑器中编辑草稿。默认 ${d}。`,
|
|
605
|
+
},
|
|
606
|
+
transcript: {
|
|
607
|
+
label: 'Transcript mode shortcut',
|
|
608
|
+
zh: '转录模式快捷键',
|
|
609
|
+
hintEn: d => `Toggle expanded transcript mode. Default: ${d}.`,
|
|
610
|
+
hintZh: d => `切换展开转录模式。默认 ${d}。`,
|
|
611
|
+
},
|
|
612
|
+
trajectory: {
|
|
613
|
+
label: 'Trajectory scene shortcut',
|
|
614
|
+
zh: '轨迹场景快捷键',
|
|
615
|
+
hintEn: d => `Open the trajectory scene. Default: ${d}.`,
|
|
616
|
+
hintZh: d => `打开轨迹场景。默认 ${d}。`,
|
|
617
|
+
},
|
|
618
|
+
dashboard: {
|
|
619
|
+
label: 'Subagent dashboard shortcut',
|
|
620
|
+
zh: '子代理面板快捷键',
|
|
621
|
+
hintEn: d => `Open the subagent dashboard. Default: ${d}.`,
|
|
622
|
+
hintZh: d => `打开子代理面板。默认 ${d}。`,
|
|
623
|
+
},
|
|
624
|
+
contextPanel: {
|
|
625
|
+
label: 'Loaded-context panel shortcut',
|
|
626
|
+
zh: '加载上下文面板快捷键',
|
|
627
|
+
hintEn: d => `Toggle the startup loaded-context panel. Default: ${d}.`,
|
|
628
|
+
hintZh: d => `切换启动时的已加载上下文面板。默认 ${d}。`,
|
|
629
|
+
},
|
|
630
|
+
showAll: {
|
|
631
|
+
label: 'Show-all shortcut',
|
|
632
|
+
zh: '显示全部消息快捷键',
|
|
633
|
+
hintEn: d => `Toggle show-all-messages. Default: ${d}.`,
|
|
634
|
+
hintZh: d => `切换显示全部消息。默认 ${d}。`,
|
|
635
|
+
},
|
|
636
|
+
redraw: {
|
|
637
|
+
label: 'Redraw shortcut',
|
|
638
|
+
zh: '终端重绘快捷键',
|
|
639
|
+
hintEn: d => `Clear and repaint the terminal. Default: ${d}.`,
|
|
640
|
+
hintZh: d => `清空并重绘终端。默认 ${d}。`,
|
|
641
|
+
},
|
|
642
|
+
todoFold: {
|
|
643
|
+
label: 'Todo fold shortcut',
|
|
644
|
+
zh: '待办折叠快捷键',
|
|
645
|
+
hintEn: d => `Fold/unfold the goal/todo panel. Default: ${d}.`,
|
|
646
|
+
hintZh: d => `折叠/展开目标与待办面板。默认 ${d}。`,
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
const shortcutFields = SHORTCUT_ACTIONS.map(action => {
|
|
650
|
+
const meta = shortcutFieldMeta[action.id];
|
|
651
|
+
const defaults = action.defaults.join(', ');
|
|
652
|
+
return {
|
|
653
|
+
path: ['shortcuts', action.id],
|
|
654
|
+
label: meta.label,
|
|
655
|
+
descriptions: { zh: meta.zh },
|
|
656
|
+
hint: meta.hintEn(defaults),
|
|
657
|
+
hintDescriptions: { zh: meta.hintZh(defaults) },
|
|
658
|
+
group: 'shortcuts',
|
|
659
|
+
kind: 'text',
|
|
660
|
+
format(value) {
|
|
661
|
+
return typeof value === 'string' && value.trim() !== '' ? value : effectiveComboString(action.id);
|
|
662
|
+
},
|
|
663
|
+
parse(text) {
|
|
664
|
+
const draft = parseComboDraft(text);
|
|
665
|
+
if (draft === undefined)
|
|
666
|
+
return undefined;
|
|
667
|
+
if (draft.combos.length === 0)
|
|
668
|
+
return { kind: 'clear' };
|
|
669
|
+
if (draftComboConflicts(action.id, draft.combos))
|
|
670
|
+
return undefined;
|
|
671
|
+
return { kind: 'set', value: draft.combos.join(', ') };
|
|
672
|
+
},
|
|
673
|
+
};
|
|
674
|
+
});
|
|
414
675
|
const settingsSections = getHostSettingsSections(ctx.get('tuiSettingsSections'));
|
|
415
676
|
if (settingsSections !== undefined) {
|
|
416
677
|
const unregister = settingsSections.register({
|
|
417
678
|
ns: 'dsh-tui',
|
|
418
679
|
title: 'dsh-tui',
|
|
419
|
-
groups: [
|
|
680
|
+
groups: [
|
|
681
|
+
{ id: 'status-bar', title: 'Status bar', descriptions: { zh: '底栏设置' } },
|
|
682
|
+
{ id: 'shortcuts', title: 'Shortcuts', descriptions: { zh: '快捷键' } },
|
|
683
|
+
{ id: 'session', title: 'Session', descriptions: { zh: '会话' } },
|
|
684
|
+
],
|
|
420
685
|
fields: [
|
|
421
686
|
{
|
|
422
687
|
path: ['lang'],
|
|
@@ -436,6 +701,22 @@ export async function apply(ctx, config) {
|
|
|
436
701
|
return value === undefined || value === null ? getLang() : String(value);
|
|
437
702
|
},
|
|
438
703
|
},
|
|
704
|
+
{
|
|
705
|
+
path: ['fullscreen'],
|
|
706
|
+
label: 'Fullscreen mode',
|
|
707
|
+
descriptions: { zh: '全屏模式' },
|
|
708
|
+
// 故意不用 "alt-screen" 这类终端术语:读者要的是行为差异。鼠标
|
|
709
|
+
// 两种模式都可用(整屏页面自带鼠标跟踪),别让描述暗示关掉就
|
|
710
|
+
// 没有鼠标——最常见的误解。长度对齐既有最长 hint(单行假设)。
|
|
711
|
+
hint: 'On: app takes the whole screen (vim/less style), in-app mouse. Off: native scrollback; full-page screens keep the mouse. Restart to apply.',
|
|
712
|
+
hintDescriptions: { zh: '开启:接管整个终端(同 vim/less),应用内鼠标;关闭:终端原生滚动选择;整屏页两种模式都有鼠标。重启生效。' },
|
|
713
|
+
kind: 'boolean',
|
|
714
|
+
format(value) {
|
|
715
|
+
// Unset in settings.yaml: show what THIS session booted with
|
|
716
|
+
// (the cordis.yml resolution) instead of a misleading false.
|
|
717
|
+
return value === undefined || value === null ? String(bootedFullscreen) : String(value);
|
|
718
|
+
},
|
|
719
|
+
},
|
|
439
720
|
{
|
|
440
721
|
path: ['diffLayout'],
|
|
441
722
|
label: 'Diff layout',
|
|
@@ -474,6 +755,40 @@ export async function apply(ctx, config) {
|
|
|
474
755
|
{ value: 'strong', label: 'Strong', descriptions: { zh: '明显' } },
|
|
475
756
|
],
|
|
476
757
|
},
|
|
758
|
+
{
|
|
759
|
+
path: ['scrollGutter'],
|
|
760
|
+
label: 'Transcript gutter',
|
|
761
|
+
descriptions: { zh: '转录边栏' },
|
|
762
|
+
hint: 'Right gutter of the fullscreen transcript: per-turn timeline ticks, a proportional scrollbar, or nothing.',
|
|
763
|
+
hintDescriptions: { zh: '全屏转录区右侧边栏:按轮次的时间线节点、比例滚动条,或留空。' },
|
|
764
|
+
kind: 'select',
|
|
765
|
+
options: [
|
|
766
|
+
{ value: 'timeline', label: 'Turn timeline', descriptions: { zh: '轮次时间线' } },
|
|
767
|
+
{ value: 'scrollbar', label: 'Scrollbar', descriptions: { zh: '滚动条' } },
|
|
768
|
+
{ value: 'hidden', label: 'Hidden', descriptions: { zh: '隐藏' } },
|
|
769
|
+
],
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
path: ['promptSessionLabel'],
|
|
773
|
+
label: 'Session name chip',
|
|
774
|
+
descriptions: { zh: '会话名标签' },
|
|
775
|
+
hint: 'Show the session name on the prompt top border, right corner. Off by default.',
|
|
776
|
+
hintDescriptions: { zh: '在输入框顶边框右上角显示会话名。默认关闭。' },
|
|
777
|
+
kind: 'boolean',
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
path: ['recapOnOpen'],
|
|
781
|
+
label: 'Auto recap on open',
|
|
782
|
+
descriptions: { zh: '打开会话时自动总结' },
|
|
783
|
+
hint: 'On: opening/resuming a session automatically summarizes its recent activity into a dim line at the bottom of the transcript (hover/click to view or apply the suggested title). Off: use /recap manually.',
|
|
784
|
+
hintDescriptions: { zh: '开启:打开/恢复会话时自动把最近活动总结成一行灰字显示在会话底部(可悬停/点击查看或应用建议标题);关闭:手动使用 /recap。' },
|
|
785
|
+
kind: 'boolean',
|
|
786
|
+
format(value) {
|
|
787
|
+
// Unset in settings.yaml: the default is on.
|
|
788
|
+
return value === undefined || value === null ? 'true' : String(value);
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
...shortcutFields,
|
|
477
792
|
{
|
|
478
793
|
path: ['statusBar', 'compact'],
|
|
479
794
|
label: 'Compact status bar',
|
|
@@ -564,6 +879,24 @@ export async function apply(ctx, config) {
|
|
|
564
879
|
group: 'status-bar',
|
|
565
880
|
kind: 'boolean',
|
|
566
881
|
},
|
|
882
|
+
{
|
|
883
|
+
path: ['statusBar', 'sessionId'],
|
|
884
|
+
label: 'Show session id',
|
|
885
|
+
descriptions: { zh: '显示会话 ID' },
|
|
886
|
+
hint: 'Show the short session id (# + first 8 chars) — it matches the session log filename for --resume.',
|
|
887
|
+
hintDescriptions: { zh: '显示短会话 ID(# + 前 8 位)——与日志文件名对应,方便 --resume 定位。' },
|
|
888
|
+
group: 'status-bar',
|
|
889
|
+
kind: 'boolean',
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
path: ['statusBar', 'goal'],
|
|
893
|
+
label: 'Show goal status',
|
|
894
|
+
descriptions: { zh: '显示 Goal 状态' },
|
|
895
|
+
hint: 'Show a compact goal chip (phase glyph + rounds) in the status footer while a goal exists.',
|
|
896
|
+
hintDescriptions: { zh: '存在 Goal 时,在底部状态栏显示紧凑的 Goal 状态(阶段符号与轮次)。' },
|
|
897
|
+
group: 'status-bar',
|
|
898
|
+
kind: 'boolean',
|
|
899
|
+
},
|
|
567
900
|
{
|
|
568
901
|
path: ['statusBar', 'mode'],
|
|
569
902
|
label: 'Show session mode',
|
|
@@ -678,6 +1011,10 @@ export async function apply(ctx, config) {
|
|
|
678
1011
|
let exited = false;
|
|
679
1012
|
let updateRequested = false;
|
|
680
1013
|
let updateTargetVersion;
|
|
1014
|
+
// `/restart` flag: same exit funnel as `/update` minus the pnpm step —
|
|
1015
|
+
// write the resume target, restore the terminal, respawn the process with
|
|
1016
|
+
// the original argv, and let the fresh boot attach the same session.
|
|
1017
|
+
let restartRequested = false;
|
|
681
1018
|
// The profile this process was booted with (`dsh --profile <name>`); dsh
|
|
682
1019
|
// exposes it nowhere else, and /update must update the installation the
|
|
683
1020
|
// user is actually running, not a hard-coded one.
|
|
@@ -695,7 +1032,7 @@ export async function apply(ctx, config) {
|
|
|
695
1032
|
if (error !== undefined) {
|
|
696
1033
|
const message = error instanceof Error ? error.message : String(error);
|
|
697
1034
|
ctx.logger.error(`dsh-tui: exit after error: ${message}`);
|
|
698
|
-
void finishExit(ctx, instance,
|
|
1035
|
+
void finishExit(ctx, instance, bootedFullscreen, undefined, `dsh-tui crashed: ${message}`, () => disposeRootAndExit(ctx, 1));
|
|
699
1036
|
return;
|
|
700
1037
|
}
|
|
701
1038
|
if (updateRequested) {
|
|
@@ -705,7 +1042,26 @@ export async function apply(ctx, config) {
|
|
|
705
1042
|
catch {
|
|
706
1043
|
// Resume persistence is best effort and must never block an update.
|
|
707
1044
|
}
|
|
708
|
-
void finishExit(ctx, instance,
|
|
1045
|
+
void finishExit(ctx, instance, bootedFullscreen, 'Updating @deepseek-harness-tui/dsh-tui and restarting…', undefined, () => runUpdate(ctx, profile, channel.agentId, updateTargetVersion));
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
// `/restart`: same handoff as the update path, no installation step.
|
|
1049
|
+
// The resume target is written unconditionally — the user asked to
|
|
1050
|
+
// restart THIS session, blank or not (mirrors the update contract).
|
|
1051
|
+
if (restartRequested) {
|
|
1052
|
+
beginRestartAttempt(channel.agentId);
|
|
1053
|
+
logRestartEvent('funnel: /restart branch entered');
|
|
1054
|
+
try {
|
|
1055
|
+
writeResumeTarget(channel.agentId);
|
|
1056
|
+
logRestartEvent('funnel: resume target written');
|
|
1057
|
+
}
|
|
1058
|
+
catch (error) {
|
|
1059
|
+
// Resume persistence is best effort and must never block a restart.
|
|
1060
|
+
logRestartEvent('funnel: resume target write failed', {
|
|
1061
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
void finishExit(ctx, instance, bootedFullscreen, t('restart-starting'), undefined, () => runRestart(ctx, profile, channel.agentId));
|
|
709
1065
|
return;
|
|
710
1066
|
}
|
|
711
1067
|
// Judge against the live session behind the channel (channel.agentId),
|
|
@@ -729,10 +1085,19 @@ export async function apply(ctx, config) {
|
|
|
729
1085
|
const hint = resumable
|
|
730
1086
|
? `Resume with the command below:\n${resumeCommand(profile, channel.agentId)}`
|
|
731
1087
|
: undefined;
|
|
732
|
-
void finishExit(ctx, instance,
|
|
1088
|
+
void finishExit(ctx, instance, bootedFullscreen, hint, undefined, () => disposeRootAndExit(ctx, 0));
|
|
733
1089
|
},
|
|
734
1090
|
});
|
|
735
1091
|
const handleExit = funnel.handleExit;
|
|
1092
|
+
// Chat's `fullscreen` prop must match the root wrap below, or the
|
|
1093
|
+
// full-screen surfaces inside Chat (session browser, settings, trajectory,
|
|
1094
|
+
// subagent pages) would nest a SECOND <AlternateScreen> — whose unmount
|
|
1095
|
+
// writes DEC 1049 exit and drops the whole app back to the main screen
|
|
1096
|
+
// (the stable /resume→Esc "exited fullscreen" repro). The prop is captured
|
|
1097
|
+
// when the element is created, so wait for the settings first-application
|
|
1098
|
+
// BEFORE creating Chat: the element must see the same bootedFullscreen the
|
|
1099
|
+
// root tree resolves after settingsReady below.
|
|
1100
|
+
await settingsReady;
|
|
736
1101
|
const chat = React.createElement(Chat, {
|
|
737
1102
|
channel,
|
|
738
1103
|
questionStore,
|
|
@@ -746,8 +1111,17 @@ export async function apply(ctx, config) {
|
|
|
746
1111
|
// Full-screen surfaces inside Chat — the trajectory scene and the session
|
|
747
1112
|
// browser — enter the alt screen themselves in inline mode; in fullscreen
|
|
748
1113
|
// the tree is already wrapped below, so they must not nest.
|
|
749
|
-
fullscreen:
|
|
1114
|
+
fullscreen: bootedFullscreen,
|
|
750
1115
|
onExit: () => handleExit(),
|
|
1116
|
+
// `/restart`: respawn this process and resume the session, no update.
|
|
1117
|
+
onRestart: () => {
|
|
1118
|
+
if (exited || restartRequested)
|
|
1119
|
+
return;
|
|
1120
|
+
restartRequested = true;
|
|
1121
|
+
logRestartEvent('command: /restart accepted');
|
|
1122
|
+
channel.notify(t('restart-starting'));
|
|
1123
|
+
handleExit();
|
|
1124
|
+
},
|
|
751
1125
|
// Only a `dsh --profile <name>` launch has a profile installation for
|
|
752
1126
|
// `/update` to act on; source checkouts and `--config` overlays get the
|
|
753
1127
|
// unavailable notice instead.
|
|
@@ -791,12 +1165,34 @@ export async function apply(ctx, config) {
|
|
|
791
1165
|
});
|
|
792
1166
|
},
|
|
793
1167
|
});
|
|
1168
|
+
// Freeze the fullscreen decision only NOW, right before the tree mounts:
|
|
1169
|
+
// Chat above was created after the same settingsReady await, so the root
|
|
1170
|
+
// wrap and the `fullscreen` prop share one value; a mid-session /settings
|
|
1171
|
+
// edit from here on is persisted for the next boot (the watch notifies),
|
|
1172
|
+
// never applied live (swapping layouts requires re-mounting the tree).
|
|
1173
|
+
// Host recompose hardening: never regress a fullscreen session to inline
|
|
1174
|
+
// on a re-mount whose settings application arrived late (see the module
|
|
1175
|
+
// latch note). A fresh process still resolves from config + settings
|
|
1176
|
+
// normally — the latch is undefined there.
|
|
1177
|
+
if (bootedFullscreen === false && lastBootedFullscreen === true) {
|
|
1178
|
+
bootedFullscreen = true;
|
|
1179
|
+
}
|
|
1180
|
+
fullscreenFrozen = true;
|
|
794
1181
|
// fullscreen: wrap the tree in <AlternateScreen> (DEC 1049 + SGR mouse
|
|
795
1182
|
// tracking), which turns on in-app text selection (copy-on-select via
|
|
796
1183
|
// useCopyOnSelect), wheel scroll, and click/hover hit-testing. Inline
|
|
797
1184
|
// mode leaves the mouse to the terminal emulator's native selection.
|
|
798
|
-
const tree = React.createElement(ThemeProvider, null,
|
|
1185
|
+
const tree = React.createElement(ThemeProvider, null, bootedFullscreen ? React.createElement(AlternateScreen, null, chat) : chat);
|
|
799
1186
|
instance = await render(tree, { exitOnCtrlC: false });
|
|
1187
|
+
const isRecompose = lastBootedFullscreen !== undefined;
|
|
1188
|
+
lastBootedFullscreen = bootedFullscreen;
|
|
1189
|
+
logMouseDebug('apply mount', { bootedFullscreen, isRecompose });
|
|
1190
|
+
// /restart handoff diagnosis: the replacement got all the way to a mounted
|
|
1191
|
+
// UI, so any later death is post-boot (and its stderr keeps flowing to the
|
|
1192
|
+
// parent only within the survival window — this line is the durable mark).
|
|
1193
|
+
if (process.env.DSH_TUI_RESTART_CHILD === '1') {
|
|
1194
|
+
logRestartEvent('boot: UI mounted', { fullscreen: bootedFullscreen, isRecompose });
|
|
1195
|
+
}
|
|
800
1196
|
// Check in the background so registry latency never delays the first frame.
|
|
801
1197
|
// A failed/offline check is intentionally silent; the manual `/update`
|
|
802
1198
|
// command remains available regardless of network access.
|
|
@@ -814,6 +1210,7 @@ export async function apply(ctx, config) {
|
|
|
814
1210
|
// skill commands (issue #86) would survive this exact recompose and the
|
|
815
1211
|
// re-mounted channel would find the names taken, freezing its menu.
|
|
816
1212
|
ctx.effect(() => () => {
|
|
1213
|
+
logMouseDebug('apply teardown');
|
|
817
1214
|
funnel.markTeardown();
|
|
818
1215
|
channel.releaseContributions();
|
|
819
1216
|
instance?.unmount();
|
|
@@ -847,9 +1244,13 @@ export async function apply(ctx, config) {
|
|
|
847
1244
|
async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRoute, meta, configuredPreset) {
|
|
848
1245
|
// Resume override (issue #67): cordis.yml overrides the target session's
|
|
849
1246
|
// recorded route only when it pins BOTH halves; undefined halves let the
|
|
850
|
-
// session's own request/header records win (issue #30).
|
|
1247
|
+
// session's own request/header records win (issue #30). The recorded route
|
|
1248
|
+
// is ALSO fed back into agentOptions (not just the status line): a resume
|
|
1249
|
+
// whose cordis.yml pins only `provider` would otherwise leave
|
|
1250
|
+
// agentOptions.model undefined, which breaks the `{{model}}` persona
|
|
1251
|
+
// variable for the resumed agent's own assembly and for every subagent it
|
|
1252
|
+
// spawns (dsh-subagent inherits `parent.options.model`).
|
|
851
1253
|
const resumeRoute = explicitModelRoute(configuredRoute);
|
|
852
|
-
const resumeOptions = { provider: resumeRoute?.provider, model: resumeRoute?.model };
|
|
853
1254
|
if (requestedSessionId !== undefined) {
|
|
854
1255
|
const resumeId = SessionId(requestedSessionId);
|
|
855
1256
|
const existing = ctx.agents.get(resumeId);
|
|
@@ -866,6 +1267,11 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
|
|
|
866
1267
|
// caller's current preference.
|
|
867
1268
|
const persisted = await resolvePersistedPreset(ctx, resumeId);
|
|
868
1269
|
const composed = await composePreset(ctx, persisted);
|
|
1270
|
+
const recorded = await resolvePersistedRoute(ctx, resumeId);
|
|
1271
|
+
const resumeOptions = {
|
|
1272
|
+
provider: resumeRoute?.provider ?? recorded?.provider,
|
|
1273
|
+
model: resumeRoute?.model ?? recorded?.model,
|
|
1274
|
+
};
|
|
869
1275
|
const resumed = await ctx.agents.resume({
|
|
870
1276
|
resumeSessionId: resumeId,
|
|
871
1277
|
agentOptions: resumeOptions,
|
|
@@ -1065,6 +1471,34 @@ function writeStream(stream, data) {
|
|
|
1065
1471
|
}
|
|
1066
1472
|
});
|
|
1067
1473
|
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Restart the TUI in place and resume the same session — the `/restart`
|
|
1476
|
+
* tail of `/reload`: the soft reload cannot re-read boot-time-only state
|
|
1477
|
+
* (cordis.yml root config, frozen fullscreen layout, newly built code), so
|
|
1478
|
+
* /restart respawns the process with the original argv through the same
|
|
1479
|
+
* terminal handoff the /update path uses, minus the installation step.
|
|
1480
|
+
* The resume contract is dual-written (env + resume.txt) before this runs.
|
|
1481
|
+
*/
|
|
1482
|
+
function runRestart(ctx, profile, sessionId) {
|
|
1483
|
+
logRestartEvent('runRestart: entered, disposing cordis root');
|
|
1484
|
+
disposeRootAndThen(ctx, () => {
|
|
1485
|
+
logRestartEvent('runRestart: root disposed, starting restartTui');
|
|
1486
|
+
void restartTui(sessionId).then(restartCode => {
|
|
1487
|
+
logRestartEvent('runRestart: restartTui resolved', { restartCode });
|
|
1488
|
+
if (restartCode !== 0) {
|
|
1489
|
+
writeHandoffNotice(`\ndsh-tui restart failed to spawn (exit ${restartCode}). Your session is preserved — resume with:\n` +
|
|
1490
|
+
`${resumeCommand(profile, sessionId)}\n\n`);
|
|
1491
|
+
}
|
|
1492
|
+
process.exit(restartCode);
|
|
1493
|
+
}, restartError => {
|
|
1494
|
+
const message = restartError instanceof Error ? restartError.message : String(restartError);
|
|
1495
|
+
logRestartEvent('runRestart: restartTui rejected', { message });
|
|
1496
|
+
writeHandoffNotice(`\ndsh-tui restart failed: ${message}. Your session is preserved — resume with:\n` +
|
|
1497
|
+
`${resumeCommand(profile, sessionId)}\n\n`);
|
|
1498
|
+
process.exit(1);
|
|
1499
|
+
});
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1068
1502
|
function runUpdate(ctx, profile, sessionId, targetVersion) {
|
|
1069
1503
|
disposeRootAndThen(ctx, () => {
|
|
1070
1504
|
if (profile === undefined) {
|
|
@@ -1113,7 +1547,12 @@ function resumeCommand(profile, sessionId) {
|
|
|
1113
1547
|
* reporting failure on a clean exit would mislead wrapper scripts.
|
|
1114
1548
|
*/
|
|
1115
1549
|
function disposeRootAndThen(ctx, done, fallbackCode = 1) {
|
|
1116
|
-
const timer = setTimeout(() =>
|
|
1550
|
+
const timer = setTimeout(() => {
|
|
1551
|
+
// Diagnosis for a stalled disposal: without this line the fallback exit
|
|
1552
|
+
// is indistinguishable from a successful handoff in the field.
|
|
1553
|
+
logRestartEvent('dispose: timeout, taking fallback exit', { fallbackCode });
|
|
1554
|
+
process.exit(fallbackCode);
|
|
1555
|
+
}, 5000);
|
|
1117
1556
|
timer.unref();
|
|
1118
1557
|
void withHostRootCapability(() => ctx.root.fiber.dispose()).then(() => {
|
|
1119
1558
|
clearTimeout(timer);
|