@deepseek-harness-tui/dsh-tui 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -256
- 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 +6 -0
- 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/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 +3 -1
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- 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/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 +3 -1
- package/lib/types/components/FileSuggestions.d.ts.map +1 -1
- package/lib/types/components/MessageList.d.ts +3 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +13 -6
- package/lib/types/components/ModelPicker.d.ts +26 -4
- package/lib/types/components/ModelPicker.d.ts.map +1 -1
- package/lib/types/components/ModelPicker.js +26 -6
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +365 -57
- 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/ScrollbarGutter.d.ts.map +1 -1
- package/lib/types/components/ScrollbarGutter.js +55 -4
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +6 -4
- package/lib/types/components/SuggestionCard.d.ts +4 -2
- package/lib/types/components/SuggestionCard.d.ts.map +1 -1
- package/lib/types/components/TimelineRail.d.ts.map +1 -1
- package/lib/types/components/TimelineRail.js +9 -2
- 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/AssistantToolUseMessage.d.ts +8 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +36 -8
- 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 +41 -9
- package/lib/types/dsh-adapter/channel.d.ts +101 -2
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +969 -93
- 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 +10 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +5 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +317 -8
- 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 +604 -176
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +206 -72
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +21 -0
- 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/plugin-spec/registry.d.ts +1 -1
- package/lib/types/plugin-spec/registry.js +1 -1
- 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 +588 -64
- 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/StatusLine.d.ts +0 -9
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +215 -52
- 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/chatOverlay.d.ts +17 -1
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- package/lib/types/screens/chatOverlay.js +3 -1
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +22 -4
- package/lib/types/update.d.ts +159 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +496 -30
- package/lib/types/utils/debug.d.ts +1 -1
- package/lib/types/utils/debug.js +3 -3
- 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/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 +17 -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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Schema from '@deepseek-ai/schemastery';
|
|
2
2
|
import { DEFAULT_STATUS_BAR } from '../tuiDisplayPrefs.js';
|
|
3
|
+
import { SHORTCUT_ACTIONS } from '../utils/keymap.js';
|
|
3
4
|
export const name = 'dsh-tui';
|
|
4
5
|
// `tuiWorkspaces` must stay OUT of this code-level inject (issue #183): the
|
|
5
6
|
// dsh CLI resolves the bundle's cordis.patch.yml from the FIRST copy of this
|
|
@@ -32,6 +33,7 @@ export const Config = Schema.object({
|
|
|
32
33
|
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
33
34
|
toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
|
|
34
35
|
scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
|
|
36
|
+
promptSessionLabel: Schema.boolean().default(false),
|
|
35
37
|
statusBar: Schema.object({
|
|
36
38
|
compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
|
|
37
39
|
model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
|
|
@@ -51,6 +53,9 @@ export const Config = Schema.object({
|
|
|
51
53
|
trajectory: Schema.boolean().default(DEFAULT_STATUS_BAR.trajectory),
|
|
52
54
|
shortcutHint: Schema.boolean().default(DEFAULT_STATUS_BAR.shortcutHint),
|
|
53
55
|
}).default({ ...DEFAULT_STATUS_BAR }),
|
|
56
|
+
// One optional combo string per customizable action (no defaults: unset
|
|
57
|
+
// keeps the built-in binding; see Config.shortcuts).
|
|
58
|
+
shortcuts: Schema.object(Object.fromEntries(SHORTCUT_ACTIONS.map(action => [action.id, Schema.string().required(false)]))).required(false),
|
|
54
59
|
modes: Schema.array(Schema.object({
|
|
55
60
|
id: Schema.string(),
|
|
56
61
|
label: Schema.string().required(false),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAsEnC,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAitCvE;AAsHD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV"}
|
|
@@ -13,17 +13,19 @@ 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
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';
|
|
29
31
|
import { logMouseDebug } from '../utils/debug.js';
|
|
@@ -63,7 +65,65 @@ import { CLEAR_ITERM2_PROGRESS, CLEAR_TAB_STATUS, supportsTabStatus, wrapForMult
|
|
|
63
65
|
*/
|
|
64
66
|
let lastBootedFullscreen;
|
|
65
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
|
+
}
|
|
66
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
|
+
}
|
|
67
127
|
throw new Error('dsh-tui requires an interactive terminal (stdout must be a TTY).');
|
|
68
128
|
}
|
|
69
129
|
// The official profile launcher owns the system preset root and replaces
|
|
@@ -324,6 +384,10 @@ export async function apply(ctx, config) {
|
|
|
324
384
|
// only explicit values so the target session's own record wins.
|
|
325
385
|
configuredModel: config.model,
|
|
326
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,
|
|
327
391
|
effort: config.effort,
|
|
328
392
|
activity: config.activity,
|
|
329
393
|
// Explicit cordis.yml value (static deployment choice) wins over the
|
|
@@ -344,6 +408,7 @@ export async function apply(ctx, config) {
|
|
|
344
408
|
thinkingFold: config.thinkingFold,
|
|
345
409
|
toolBackground: config.toolBackground,
|
|
346
410
|
scrollGutter: config.scrollGutter,
|
|
411
|
+
promptSessionLabel: config.promptSessionLabel,
|
|
347
412
|
statusBar: config.statusBar,
|
|
348
413
|
handle,
|
|
349
414
|
});
|
|
@@ -373,11 +438,13 @@ export async function apply(ctx, config) {
|
|
|
373
438
|
// user layer in settings.yaml wins over cordis.yml's diffLayout, and
|
|
374
439
|
// watch() lands commits on the live channel — no recompose needed.
|
|
375
440
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
376
|
-
const
|
|
441
|
+
const tuiSettingsNs = settingsNamespace('dsh-tui');
|
|
442
|
+
const scope = settingsCtx.settings.register(tuiSettingsNs, Schema.object({
|
|
377
443
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
378
444
|
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
379
445
|
toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
|
|
380
446
|
scrollGutter: Schema.union(['timeline', 'scrollbar', 'hidden']).default('timeline'),
|
|
447
|
+
promptSessionLabel: Schema.boolean().default(false),
|
|
381
448
|
statusBar: Schema.object({
|
|
382
449
|
compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
|
|
383
450
|
model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
|
|
@@ -409,6 +476,10 @@ export async function apply(ctx, config) {
|
|
|
409
476
|
// Same no-default rule: unset keeps cordis.yml's `fullscreen`
|
|
410
477
|
// decisive; set overrides it from the next boot on.
|
|
411
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),
|
|
412
483
|
}));
|
|
413
484
|
const applyLayout = (value) => {
|
|
414
485
|
channel.setDiffLayout(value.diffLayout ?? config.diffLayout ?? 'auto');
|
|
@@ -445,17 +516,57 @@ export async function apply(ctx, config) {
|
|
|
445
516
|
channel.setThinkingFold(value.thinkingFold ?? config.thinkingFold ?? 'preview');
|
|
446
517
|
channel.setToolBackground(normalizeToolBackground(value.toolBackground ?? config.toolBackground));
|
|
447
518
|
channel.setScrollGutter(normalizeScrollGutter(value.scrollGutter ?? config.scrollGutter));
|
|
519
|
+
channel.setPromptSessionLabel(value.promptSessionLabel ?? config.promptSessionLabel ?? false);
|
|
448
520
|
channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
|
|
449
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
|
+
};
|
|
450
541
|
const apply = (next) => {
|
|
451
542
|
applyLayout(next);
|
|
452
543
|
applyWhale(next);
|
|
453
544
|
applyMinimal(next);
|
|
454
545
|
applyLang(next);
|
|
455
546
|
applyDisplay(next);
|
|
547
|
+
applyShortcuts(next);
|
|
456
548
|
applyFullscreen(next);
|
|
457
549
|
};
|
|
458
|
-
|
|
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);
|
|
459
570
|
scope.watch(next => {
|
|
460
571
|
apply(next);
|
|
461
572
|
if (typeof next.fullscreen === 'boolean' && next.fullscreen !== bootedFullscreen) {
|
|
@@ -468,12 +579,109 @@ export async function apply(ctx, config) {
|
|
|
468
579
|
// the settings registration above, and the declared selects write `lang`
|
|
469
580
|
// and `diffLayout` back through the settings service's revision-fenced
|
|
470
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
|
+
});
|
|
471
675
|
const settingsSections = getHostSettingsSections(ctx.get('tuiSettingsSections'));
|
|
472
676
|
if (settingsSections !== undefined) {
|
|
473
677
|
const unregister = settingsSections.register({
|
|
474
678
|
ns: 'dsh-tui',
|
|
475
679
|
title: 'dsh-tui',
|
|
476
|
-
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
|
+
],
|
|
477
685
|
fields: [
|
|
478
686
|
{
|
|
479
687
|
path: ['lang'],
|
|
@@ -560,6 +768,27 @@ export async function apply(ctx, config) {
|
|
|
560
768
|
{ value: 'hidden', label: 'Hidden', descriptions: { zh: '隐藏' } },
|
|
561
769
|
],
|
|
562
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,
|
|
563
792
|
{
|
|
564
793
|
path: ['statusBar', 'compact'],
|
|
565
794
|
label: 'Compact status bar',
|
|
@@ -782,6 +1011,10 @@ export async function apply(ctx, config) {
|
|
|
782
1011
|
let exited = false;
|
|
783
1012
|
let updateRequested = false;
|
|
784
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;
|
|
785
1018
|
// The profile this process was booted with (`dsh --profile <name>`); dsh
|
|
786
1019
|
// exposes it nowhere else, and /update must update the installation the
|
|
787
1020
|
// user is actually running, not a hard-coded one.
|
|
@@ -812,6 +1045,25 @@ export async function apply(ctx, config) {
|
|
|
812
1045
|
void finishExit(ctx, instance, bootedFullscreen, 'Updating @deepseek-harness-tui/dsh-tui and restarting…', undefined, () => runUpdate(ctx, profile, channel.agentId, updateTargetVersion));
|
|
813
1046
|
return;
|
|
814
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));
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
815
1067
|
// Judge against the live session behind the channel (channel.agentId),
|
|
816
1068
|
// not the boot-time agent captured above: /resume, /new and /model swap
|
|
817
1069
|
// the active agent, so the captured reference can go stale (see
|
|
@@ -861,6 +1113,15 @@ export async function apply(ctx, config) {
|
|
|
861
1113
|
// the tree is already wrapped below, so they must not nest.
|
|
862
1114
|
fullscreen: bootedFullscreen,
|
|
863
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
|
+
},
|
|
864
1125
|
// Only a `dsh --profile <name>` launch has a profile installation for
|
|
865
1126
|
// `/update` to act on; source checkouts and `--config` overlays get the
|
|
866
1127
|
// unavailable notice instead.
|
|
@@ -926,6 +1187,12 @@ export async function apply(ctx, config) {
|
|
|
926
1187
|
const isRecompose = lastBootedFullscreen !== undefined;
|
|
927
1188
|
lastBootedFullscreen = bootedFullscreen;
|
|
928
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
|
+
}
|
|
929
1196
|
// Check in the background so registry latency never delays the first frame.
|
|
930
1197
|
// A failed/offline check is intentionally silent; the manual `/update`
|
|
931
1198
|
// command remains available regardless of network access.
|
|
@@ -977,9 +1244,13 @@ export async function apply(ctx, config) {
|
|
|
977
1244
|
async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRoute, meta, configuredPreset) {
|
|
978
1245
|
// Resume override (issue #67): cordis.yml overrides the target session's
|
|
979
1246
|
// recorded route only when it pins BOTH halves; undefined halves let the
|
|
980
|
-
// 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`).
|
|
981
1253
|
const resumeRoute = explicitModelRoute(configuredRoute);
|
|
982
|
-
const resumeOptions = { provider: resumeRoute?.provider, model: resumeRoute?.model };
|
|
983
1254
|
if (requestedSessionId !== undefined) {
|
|
984
1255
|
const resumeId = SessionId(requestedSessionId);
|
|
985
1256
|
const existing = ctx.agents.get(resumeId);
|
|
@@ -996,6 +1267,11 @@ async function resolveAgent(ctx, requestedSessionId, configuredRoute, startupRou
|
|
|
996
1267
|
// caller's current preference.
|
|
997
1268
|
const persisted = await resolvePersistedPreset(ctx, resumeId);
|
|
998
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
|
+
};
|
|
999
1275
|
const resumed = await ctx.agents.resume({
|
|
1000
1276
|
resumeSessionId: resumeId,
|
|
1001
1277
|
agentOptions: resumeOptions,
|
|
@@ -1195,6 +1471,34 @@ function writeStream(stream, data) {
|
|
|
1195
1471
|
}
|
|
1196
1472
|
});
|
|
1197
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
|
+
}
|
|
1198
1502
|
function runUpdate(ctx, profile, sessionId, targetVersion) {
|
|
1199
1503
|
disposeRootAndThen(ctx, () => {
|
|
1200
1504
|
if (profile === undefined) {
|
|
@@ -1243,7 +1547,12 @@ function resumeCommand(profile, sessionId) {
|
|
|
1243
1547
|
* reporting failure on a clean exit would mislead wrapper scripts.
|
|
1244
1548
|
*/
|
|
1245
1549
|
function disposeRootAndThen(ctx, done, fallbackCode = 1) {
|
|
1246
|
-
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);
|
|
1247
1556
|
timer.unref();
|
|
1248
1557
|
void withHostRootCapability(() => ctx.root.fiber.dispose()).then(() => {
|
|
1249
1558
|
clearTimeout(timer);
|
|
@@ -19,6 +19,7 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
19
19
|
import type { AgentSetup } from '@deepseek-ai/dsh-agent';
|
|
20
20
|
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
21
21
|
import type { PromptAssembly } from '@deepseek-ai/dsh-system-prompt';
|
|
22
|
+
import { type ModelRoute } from '../modelRoute.js';
|
|
22
23
|
/** One roster entry, as returned by `agentPresets.list()`/`resolve()`. */
|
|
23
24
|
export interface AgentPresetInfo {
|
|
24
25
|
readonly id: string;
|
|
@@ -94,6 +95,23 @@ export declare function runningPresetOf(session: {
|
|
|
94
95
|
data: unknown;
|
|
95
96
|
}[];
|
|
96
97
|
}): string | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* The route a PERSISTED session actually ran, read from its log: the last
|
|
100
|
+
* `request/header` snapshot. undefined when the log records none (a session
|
|
101
|
+
* that never started a turn) or the artifact is unreadable.
|
|
102
|
+
*
|
|
103
|
+
* Resume feeds this back into `agents.resume({ agentOptions })` so the
|
|
104
|
+
* resumed agent's `options.model` is populated again — a cordis.yml that
|
|
105
|
+
* pins only `provider` (issue #67: a half-pin never merges) leaves
|
|
106
|
+
* agentOptions.model undefined, which breaks the `{{model}}` persona variable
|
|
107
|
+
* for the resumed agent's own assembly AND for every subagent it spawns
|
|
108
|
+
* (dsh-subagent's `resolveChildAgentOptions` inherits `parent.options.model`).
|
|
109
|
+
*
|
|
110
|
+
* @param ctx - The plugin context (persistence lookup).
|
|
111
|
+
* @param sessionId - The persisted session to inspect.
|
|
112
|
+
* @returns The recorded model route, or undefined when unrecorded/unreadable.
|
|
113
|
+
*/
|
|
114
|
+
export declare function resolvePersistedRoute(ctx: Context, sessionId: SessionId): Promise<ModelRoute | undefined>;
|
|
97
115
|
/**
|
|
98
116
|
* Keep the official Minimal preset's model-facing contract at exactly two
|
|
99
117
|
* tools. The TUI mounts ask_user_question at the host layer so every other
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAEpE,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAItE,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,IAAI,IAAI,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAC/D,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IAClE,yEAAyE;IACzE,UAAU,CAAC,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3D;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAEnE;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmBhG;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqB5G;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,MAAM,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,MAAM,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CACnD,GAAG,MAAM,GAAG,SAAS,CAErB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAkB/G;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAM/G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAKpG"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* before presets existed.
|
|
17
17
|
*/
|
|
18
18
|
import { resolveSessionPreset } from '@deepseek-ai/dsh-agent-presets';
|
|
19
|
+
import { recordedModelRoute } from '../modelRoute.js';
|
|
19
20
|
const ASK_USER_TOOL = 'ask_user_question';
|
|
20
21
|
/**
|
|
21
22
|
* The mounted preset roster, or undefined when the composition has no
|
|
@@ -95,6 +96,36 @@ export async function resolvePersistedPreset(ctx, sessionId) {
|
|
|
95
96
|
export function runningPresetOf(session) {
|
|
96
97
|
return resolveSessionPreset(session);
|
|
97
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* The route a PERSISTED session actually ran, read from its log: the last
|
|
101
|
+
* `request/header` snapshot. undefined when the log records none (a session
|
|
102
|
+
* that never started a turn) or the artifact is unreadable.
|
|
103
|
+
*
|
|
104
|
+
* Resume feeds this back into `agents.resume({ agentOptions })` so the
|
|
105
|
+
* resumed agent's `options.model` is populated again — a cordis.yml that
|
|
106
|
+
* pins only `provider` (issue #67: a half-pin never merges) leaves
|
|
107
|
+
* agentOptions.model undefined, which breaks the `{{model}}` persona variable
|
|
108
|
+
* for the resumed agent's own assembly AND for every subagent it spawns
|
|
109
|
+
* (dsh-subagent's `resolveChildAgentOptions` inherits `parent.options.model`).
|
|
110
|
+
*
|
|
111
|
+
* @param ctx - The plugin context (persistence lookup).
|
|
112
|
+
* @param sessionId - The persisted session to inspect.
|
|
113
|
+
* @returns The recorded model route, or undefined when unrecorded/unreadable.
|
|
114
|
+
*/
|
|
115
|
+
export async function resolvePersistedRoute(ctx, sessionId) {
|
|
116
|
+
const persistence = ctx.get('sessionPersistence');
|
|
117
|
+
if (persistence === undefined)
|
|
118
|
+
return undefined;
|
|
119
|
+
try {
|
|
120
|
+
const { events } = await persistence.load(sessionId);
|
|
121
|
+
return recordedModelRoute(events);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// A missing/corrupt artifact leaves resume itself to report the failure;
|
|
125
|
+
// the route lookup must not mask it with a second, misleading error.
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
98
129
|
/**
|
|
99
130
|
* Keep the official Minimal preset's model-facing contract at exactly two
|
|
100
131
|
* tools. The TUI mounts ask_user_question at the host layer so every other
|
|
@@ -31,6 +31,32 @@ export interface CatalogProviderCandidate {
|
|
|
31
31
|
readonly provider: string;
|
|
32
32
|
readonly displayName: string;
|
|
33
33
|
}
|
|
34
|
+
/** One OAuth-capable provider a dsh-auth-style plugin mounts (masked state only). */
|
|
35
|
+
export interface OAuthProviderStatus {
|
|
36
|
+
readonly provider: string;
|
|
37
|
+
readonly label: string;
|
|
38
|
+
readonly oauthLabel: string;
|
|
39
|
+
readonly loginLabel: string | undefined;
|
|
40
|
+
readonly signedIn: boolean;
|
|
41
|
+
readonly expiresAt: number | undefined;
|
|
42
|
+
readonly expired: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** One successful OAuth login. */
|
|
45
|
+
export interface OAuthLoginResult {
|
|
46
|
+
readonly provider: string;
|
|
47
|
+
readonly oauthLabel: string;
|
|
48
|
+
readonly expiresAt: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The `ctx.dshAuth` api, structural so this tree never imports the plugin:
|
|
52
|
+
* mounting dsh-auth (or anything exporting this shape) lights up the wizard's
|
|
53
|
+
* OAuth branch; absent it, the wizard behaves exactly as before.
|
|
54
|
+
*/
|
|
55
|
+
export interface OAuthSetupHost {
|
|
56
|
+
providers(): Promise<readonly OAuthProviderStatus[]>;
|
|
57
|
+
login(provider?: string, signal?: AbortSignal): Promise<OAuthLoginResult>;
|
|
58
|
+
logout(provider: string): Promise<boolean>;
|
|
59
|
+
}
|
|
34
60
|
/**
|
|
35
61
|
* Runtime capabilities the wizard needs, implemented by the channel over
|
|
36
62
|
* `ctx.settings` / `ctx.credentials` / `ctx.llm`. `undefined` from
|
|
@@ -66,6 +92,8 @@ export interface ProviderSetupHost {
|
|
|
66
92
|
* rejects when the adapter's validation deems it unserviceable.
|
|
67
93
|
*/
|
|
68
94
|
writeProfile(route: string, profile: Record<string, unknown>): Promise<void>;
|
|
95
|
+
/** The OAuth sign-in surface; absent when no dsh-auth-style plugin is mounted. */
|
|
96
|
+
readonly oauth?: OAuthSetupHost;
|
|
69
97
|
}
|
|
70
98
|
export interface ProviderWizardDeps {
|
|
71
99
|
readonly host: ProviderSetupHost;
|
|
@@ -81,7 +109,7 @@ export interface ProviderWizardDeps {
|
|
|
81
109
|
readonly working: () => boolean;
|
|
82
110
|
readonly switchModel: (provider: string, model: string) => Promise<boolean>;
|
|
83
111
|
}
|
|
84
|
-
export type ProviderWizardOutcome = 'added' | 'cancelled' | 'failed';
|
|
112
|
+
export type ProviderWizardOutcome = 'added' | 'signed-out' | 'cancelled' | 'failed';
|
|
85
113
|
/**
|
|
86
114
|
* Run the add-provider wizard. Resolves 'cancelled' when the user dismisses
|
|
87
115
|
* any question (Esc) — nothing has been written at that point by design:
|