@deepseek-harness-tui/dsh-tui 0.14.1 → 0.16.0
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 +163 -17
- package/bin/dsh-tui.js +200 -34
- package/cordis.patch.yml +16 -52
- package/cordis.yml +6 -2
- package/guide/dsh-tui-guide/claude-backend.en.md +44 -7
- package/guide/dsh-tui-guide/claude-backend.md +28 -6
- package/guide/dsh-tui-guide/codex-backend.en.md +47 -10
- package/guide/dsh-tui-guide/codex-backend.md +26 -4
- package/guide/dsh-tui-guide/configuration.en.md +168 -18
- package/guide/dsh-tui-guide/configuration.md +144 -16
- package/guide/dsh-tui-guide/getting-started.en.md +15 -0
- package/guide/dsh-tui-guide/getting-started.md +15 -0
- package/guide/dsh-tui-guide/interaction.en.md +64 -24
- package/guide/dsh-tui-guide/interaction.md +49 -19
- package/guide/dsh-tui-guide/plugins.en.md +97 -3
- package/guide/dsh-tui-guide/plugins.md +55 -2
- package/guide/dsh-tui-guide/themes.en.md +23 -14
- package/guide/dsh-tui-guide/themes.md +19 -12
- package/guide/dsh-tui-guide/user-guide.en.md +53 -21
- package/guide/dsh-tui-guide/user-guide.md +43 -22
- package/lib/settings.json +103 -9
- package/lib/types/adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/projection.js +1 -0
- package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +4 -0
- package/lib/types/adapter/channel/ui.d.ts +2 -0
- package/lib/types/adapter/channel/ui.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui.js +6 -2
- package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
- package/lib/types/adapter/kernel/runtime.js +2 -0
- package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
- package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-settings.d.ts +14 -3
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +56 -12
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +68 -0
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel.d.ts +2 -0
- package/lib/types/adapter/ports/channel.d.ts.map +1 -1
- package/lib/types/adapter/spec/backend-capabilities.d.ts +22 -0
- package/lib/types/adapter/spec/backend-capabilities.d.ts.map +1 -0
- package/lib/types/adapter/spec/backend-capabilities.js +49 -0
- package/lib/types/adapter/spec/protocol-constants.d.ts.map +1 -1
- package/lib/types/adapter/spec/protocol-constants.js +10 -3
- package/lib/types/adapter/spec/tui-contributions.d.ts +3 -0
- package/lib/types/adapter/spec/tui-contributions.d.ts.map +1 -1
- package/lib/types/adapter/spec/tui-contributions.js +7 -0
- package/lib/types/adapter/standard/registry.d.ts +6 -0
- package/lib/types/adapter/standard/registry.d.ts.map +1 -1
- package/lib/types/adapter/standard/registry.js +65 -15
- package/lib/types/adapter/standard/tui-extension.d.ts.map +1 -1
- package/lib/types/adapter/standard/tui-extension.js +7 -1
- package/lib/types/adapter/standard/types.d.ts +10 -1
- package/lib/types/adapter/standard/types.d.ts.map +1 -1
- package/lib/types/adapter/upstream/host-descriptor-driver.d.ts.map +1 -1
- package/lib/types/adapter/upstream/host-descriptor-driver.js +52 -0
- package/lib/types/agent/backend-manifest.d.ts +152 -0
- package/lib/types/agent/backend-manifest.d.ts.map +1 -0
- package/lib/types/agent/backend-manifest.js +14 -0
- package/lib/types/agent/backend.d.ts +71 -5
- package/lib/types/agent/backend.d.ts.map +1 -1
- package/lib/types/agent/capabilities.d.ts +6 -0
- package/lib/types/agent/capabilities.d.ts.map +1 -1
- package/lib/types/agent/events.d.ts +3 -2
- package/lib/types/agent/events.d.ts.map +1 -1
- package/lib/types/agent/index.d.ts +2 -0
- package/lib/types/agent/index.d.ts.map +1 -1
- package/lib/types/agent/refs.d.ts +11 -1
- package/lib/types/agent/refs.d.ts.map +1 -1
- package/lib/types/agent/starting-session.d.ts +4 -0
- package/lib/types/agent/starting-session.d.ts.map +1 -0
- package/lib/types/agent/starting-session.js +19 -0
- package/lib/types/backends/claude/activity.d.ts +1 -1
- package/lib/types/backends/claude/activity.d.ts.map +1 -1
- package/lib/types/backends/claude/activity.js +5 -5
- package/lib/types/backends/claude/auth.d.ts.map +1 -1
- package/lib/types/backends/claude/auth.js +10 -3
- package/lib/types/backends/claude/backend.d.ts.map +1 -1
- package/lib/types/backends/claude/backend.js +103 -29
- package/lib/types/backends/claude/catalog.d.ts +2 -1
- package/lib/types/backends/claude/catalog.d.ts.map +1 -1
- package/lib/types/backends/claude/catalog.js +15 -5
- package/lib/types/backends/claude/channels.d.ts +5 -3
- package/lib/types/backends/claude/channels.d.ts.map +1 -1
- package/lib/types/backends/claude/channels.js +5 -4
- package/lib/types/backends/claude/contract.d.ts +4 -0
- package/lib/types/backends/claude/contract.d.ts.map +1 -1
- package/lib/types/backends/claude/contract.js +4 -0
- package/lib/types/backends/claude/controls.d.ts +4 -0
- package/lib/types/backends/claude/controls.d.ts.map +1 -1
- package/lib/types/backends/claude/controls.js +34 -42
- package/lib/types/backends/claude/dialogs.d.ts +8 -2
- package/lib/types/backends/claude/dialogs.d.ts.map +1 -1
- package/lib/types/backends/claude/dialogs.js +24 -16
- package/lib/types/backends/claude/images.d.ts +1 -1
- package/lib/types/backends/claude/images.d.ts.map +1 -1
- package/lib/types/backends/claude/images.js +7 -7
- package/lib/types/backends/claude/manifest.d.ts +21 -0
- package/lib/types/backends/claude/manifest.d.ts.map +1 -0
- package/lib/types/backends/claude/manifest.js +29 -0
- package/lib/types/backends/claude/older-history.js +2 -2
- package/lib/types/backends/claude/permissions.js +11 -11
- package/lib/types/backends/claude/prefs.d.ts +4 -2
- package/lib/types/backends/claude/prefs.d.ts.map +1 -1
- package/lib/types/backends/claude/prefs.js +4 -3
- package/lib/types/backends/claude/process.d.ts +16 -4
- package/lib/types/backends/claude/process.d.ts.map +1 -1
- package/lib/types/backends/claude/process.js +100 -37
- package/lib/types/backends/claude/send-message.d.ts +1 -1
- package/lib/types/backends/claude/send-message.d.ts.map +1 -1
- package/lib/types/backends/claude/session/auth.js +22 -22
- package/lib/types/backends/claude/session/channels.d.ts +4 -0
- package/lib/types/backends/claude/session/channels.d.ts.map +1 -1
- package/lib/types/backends/claude/session/channels.js +5 -3
- package/lib/types/backends/claude/session/lifecycle.d.ts.map +1 -1
- package/lib/types/backends/claude/session/lifecycle.js +31 -23
- package/lib/types/backends/claude/session/store.js +8 -8
- package/lib/types/backends/claude/session/subagents.js +2 -2
- package/lib/types/backends/claude/session/types.d.ts +7 -0
- package/lib/types/backends/claude/session/types.d.ts.map +1 -1
- package/lib/types/backends/claude/side-query.js +3 -3
- package/lib/types/backends/claude/task-output.js +5 -5
- package/lib/types/backends/claude/text.d.ts +778 -0
- package/lib/types/backends/claude/text.d.ts.map +1 -0
- package/lib/types/backends/claude/text.js +298 -0
- package/lib/types/backends/claude/transcript-file.d.ts +1 -1
- package/lib/types/backends/claude/transcript-file.d.ts.map +1 -1
- package/lib/types/backends/claude/transcript-file.js +4 -4
- package/lib/types/backends/claude/translate/attempts.js +2 -2
- package/lib/types/backends/claude/translate/core.js +3 -3
- package/lib/types/backends/claude/translate/messages.js +4 -4
- package/lib/types/backends/claude/translate/system.js +14 -14
- package/lib/types/backends/claude/translate/tasks.js +2 -2
- package/lib/types/backends/claude/translate/types.d.ts +1 -1
- package/lib/types/backends/claude/translate/types.d.ts.map +1 -1
- package/lib/types/backends/codex/auth/external-tokens.js +16 -16
- package/lib/types/backends/codex/auth/status.js +14 -14
- package/lib/types/backends/codex/backend.d.ts +4 -19
- package/lib/types/backends/codex/backend.d.ts.map +1 -1
- package/lib/types/backends/codex/backend.js +118 -25
- package/lib/types/backends/codex/catalog.d.ts +2 -1
- package/lib/types/backends/codex/catalog.d.ts.map +1 -1
- package/lib/types/backends/codex/catalog.js +63 -18
- package/lib/types/backends/codex/channels.d.ts +6 -3
- package/lib/types/backends/codex/channels.d.ts.map +1 -1
- package/lib/types/backends/codex/channels.js +15 -13
- package/lib/types/backends/codex/contract.d.ts +3 -0
- package/lib/types/backends/codex/contract.d.ts.map +1 -1
- package/lib/types/backends/codex/contract.js +3 -0
- package/lib/types/backends/codex/detect.d.ts.map +1 -1
- package/lib/types/backends/codex/detect.js +9 -6
- package/lib/types/backends/codex/manifest.d.ts +30 -0
- package/lib/types/backends/codex/manifest.d.ts.map +1 -0
- package/lib/types/backends/codex/manifest.js +23 -0
- package/lib/types/backends/codex/prefs.d.ts +4 -2
- package/lib/types/backends/codex/prefs.d.ts.map +1 -1
- package/lib/types/backends/codex/prefs.js +4 -3
- package/lib/types/backends/codex/rpc/hub.js +2 -2
- package/lib/types/backends/codex/session/activity.d.ts +1 -1
- package/lib/types/backends/codex/session/activity.d.ts.map +1 -1
- package/lib/types/backends/codex/session/activity.js +13 -13
- package/lib/types/backends/codex/session/approvals.js +30 -30
- package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
- package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
- package/lib/types/backends/codex/session/async-questions.js +89 -0
- package/lib/types/backends/codex/session/commands.d.ts +8 -2
- package/lib/types/backends/codex/session/commands.d.ts.map +1 -1
- package/lib/types/backends/codex/session/commands.js +71 -23
- package/lib/types/backends/codex/session/controls.d.ts +1 -1
- package/lib/types/backends/codex/session/controls.d.ts.map +1 -1
- package/lib/types/backends/codex/session/controls.js +21 -16
- package/lib/types/backends/codex/session/goals.d.ts.map +1 -1
- package/lib/types/backends/codex/session/goals.js +3 -3
- package/lib/types/backends/codex/session/history.js +2 -2
- package/lib/types/backends/codex/session/images.js +8 -8
- package/lib/types/backends/codex/session/input.d.ts +6 -2
- package/lib/types/backends/codex/session/input.d.ts.map +1 -1
- package/lib/types/backends/codex/session/input.js +55 -13
- package/lib/types/backends/codex/session/plan-review.js +6 -6
- package/lib/types/backends/codex/session/session.d.ts.map +1 -1
- package/lib/types/backends/codex/session/session.js +100 -42
- package/lib/types/backends/codex/session/side-query.d.ts.map +1 -1
- package/lib/types/backends/codex/session/side-query.js +27 -9
- package/lib/types/backends/codex/session/state.d.ts +6 -1
- package/lib/types/backends/codex/session/state.d.ts.map +1 -1
- package/lib/types/backends/codex/session/subagents.js +5 -5
- package/lib/types/backends/codex/session/tasks.js +4 -4
- package/lib/types/backends/codex/text.d.ts +933 -0
- package/lib/types/backends/codex/text.d.ts.map +1 -0
- package/lib/types/backends/codex/text.js +313 -0
- package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
- package/lib/types/backends/codex/translate/items.js +7 -5
- package/lib/types/backends/codex/translate/live.d.ts.map +1 -1
- package/lib/types/backends/codex/translate/live.js +11 -8
- package/lib/types/backends/codex/translate/notices.js +10 -10
- package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
- package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/question-reply.js +53 -0
- package/lib/types/backends/shared/channel-slug.d.ts +4 -0
- package/lib/types/backends/shared/channel-slug.d.ts.map +1 -0
- package/lib/types/backends/shared/channel-slug.js +25 -0
- package/lib/types/backends/shared/channel-tokens.d.ts.map +1 -1
- package/lib/types/backends/shared/channel-tokens.js +30 -23
- package/lib/types/{channel → backends/shared}/elicitation.d.ts +78 -21
- package/lib/types/backends/shared/elicitation.d.ts.map +1 -0
- package/lib/types/{channel → backends/shared}/elicitation.js +64 -66
- package/lib/types/backends/shared/image-size.d.ts +33 -0
- package/lib/types/backends/shared/image-size.d.ts.map +1 -0
- package/lib/types/backends/shared/image-size.js +134 -0
- package/lib/types/{utils → backends/shared}/jsonl.d.ts +5 -1
- package/lib/types/backends/shared/jsonl.d.ts.map +1 -0
- package/lib/types/{utils → backends/shared}/jsonl.js +5 -1
- package/lib/types/backends/shared/localized-text.d.ts +30 -0
- package/lib/types/backends/shared/localized-text.d.ts.map +1 -0
- package/lib/types/backends/shared/localized-text.js +24 -0
- package/lib/types/backends/shared/platform-text.d.ts +88 -0
- package/lib/types/backends/shared/platform-text.d.ts.map +1 -0
- package/lib/types/backends/shared/platform-text.js +33 -0
- package/lib/types/branding.d.ts +13 -0
- package/lib/types/branding.d.ts.map +1 -1
- package/lib/types/branding.js +18 -0
- package/lib/types/channel/channel-slug.d.ts +3 -1
- package/lib/types/channel/channel-slug.d.ts.map +1 -1
- package/lib/types/channel/channel-slug.js +3 -1
- package/lib/types/channel/projection.d.ts.map +1 -1
- package/lib/types/channel/projection.js +10 -0
- package/lib/types/channel/sanitize.d.ts +7 -0
- package/lib/types/channel/sanitize.d.ts.map +1 -1
- package/lib/types/channel/sanitize.js +9 -0
- package/lib/types/channel/usage.d.ts.map +1 -1
- package/lib/types/channel/usage.js +5 -0
- package/lib/types/commands.d.ts +15 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +58 -10
- package/lib/types/components/AgentMessageComposer.d.ts.map +1 -1
- package/lib/types/components/AgentMessageComposer.js +3 -2
- package/lib/types/components/BtwPanel.d.ts.map +1 -1
- package/lib/types/components/BtwPanel.js +4 -2
- package/lib/types/components/Chat/JobCard.js +3 -3
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +24 -7
- package/lib/types/components/ContextBarView.d.ts +5 -1
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +6 -3
- package/lib/types/components/ExtensionDialog.d.ts.map +1 -1
- package/lib/types/components/ExtensionDialog.js +2 -3
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +14 -3
- package/lib/types/components/InlineMathParagraph.js +1 -1
- package/lib/types/components/KernelPicker.d.ts.map +1 -1
- package/lib/types/components/KernelPicker.js +1 -1
- package/lib/types/components/LogoV2.d.ts +4 -1
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +14 -9
- package/lib/types/components/MarkdownTable.d.ts.map +1 -1
- package/lib/types/components/MarkdownTable.js +4 -3
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +109 -15
- package/lib/types/components/ModelPicker.d.ts +24 -31
- package/lib/types/components/ModelPicker.d.ts.map +1 -1
- package/lib/types/components/ModelPicker.js +115 -40
- package/lib/types/components/PermissionsPicker.d.ts +10 -1
- package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
- package/lib/types/components/PermissionsPicker.js +24 -16
- package/lib/types/components/PluginInstallPane.d.ts +21 -0
- package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
- package/lib/types/components/PluginInstallPane.js +84 -0
- package/lib/types/components/PluginManagePane.d.ts +21 -0
- package/lib/types/components/PluginManagePane.d.ts.map +1 -0
- package/lib/types/components/PluginManagePane.js +69 -0
- package/lib/types/components/PromptEditor.d.ts +3 -3
- package/lib/types/components/PromptInput.d.ts +21 -3
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +65 -121
- package/lib/types/components/SdkInstallWizard.d.ts +3 -1
- package/lib/types/components/SdkInstallWizard.d.ts.map +1 -1
- package/lib/types/components/SdkInstallWizard.js +8 -1
- package/lib/types/components/SearchBox.d.ts +13 -15
- package/lib/types/components/SearchBox.d.ts.map +1 -1
- package/lib/types/components/SearchBox.js +58 -27
- package/lib/types/components/SubagentCard.d.ts +13 -1
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +27 -12
- package/lib/types/components/SubagentDashboard.d.ts +8 -1
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +58 -16
- package/lib/types/components/ThemePicker.d.ts +1 -1
- package/lib/types/components/ThemePicker.d.ts.map +1 -1
- package/lib/types/components/ThemePicker.js +14 -11
- package/lib/types/components/Tooltip.js +1 -1
- package/lib/types/components/WorkingSpinner.js +1 -1
- package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
- package/lib/types/components/WorkspaceFlowPicker.js +4 -3
- package/lib/types/components/composerImageTokens.d.ts +24 -0
- package/lib/types/components/composerImageTokens.d.ts.map +1 -0
- package/lib/types/components/composerImageTokens.js +37 -0
- package/lib/types/components/design-system/InputCaret.d.ts +7 -0
- package/lib/types/components/design-system/InputCaret.d.ts.map +1 -0
- package/lib/types/components/design-system/InputCaret.js +9 -0
- package/lib/types/components/design-system/ListItem.d.ts +13 -2
- package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
- package/lib/types/components/design-system/ListItem.js +11 -5
- package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemeProvider.js +6 -8
- package/lib/types/components/kernelCatalog.d.ts +55 -11
- package/lib/types/components/kernelCatalog.d.ts.map +1 -1
- package/lib/types/components/kernelCatalog.js +42 -23
- package/lib/types/components/launchpadActions.d.ts +4 -0
- package/lib/types/components/launchpadActions.d.ts.map +1 -1
- package/lib/types/components/launchpadActions.js +5 -4
- package/lib/types/components/launchpadLayout.d.ts +14 -1
- package/lib/types/components/launchpadLayout.d.ts.map +1 -1
- package/lib/types/components/launchpadLayout.js +38 -19
- package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
- package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
- package/lib/types/components/messages/TeamMessageBubble.js +15 -0
- package/lib/types/components/messages/UserPromptMessage.d.ts +4 -3
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +4 -3
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +8 -3
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +4 -3
- package/lib/types/components/questions/ProviderModelEditor.d.ts.map +1 -1
- package/lib/types/components/questions/ProviderModelEditor.js +3 -13
- package/lib/types/components/sessions/ForeignSessionRow.d.ts +3 -1
- package/lib/types/components/sessions/ForeignSessionRow.d.ts.map +1 -1
- package/lib/types/components/sessions/ForeignSessionRow.js +5 -2
- package/lib/types/components/sessions/SessionListRow.d.ts +3 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +5 -2
- package/lib/types/components/sidePanel/PanelBar.d.ts +1 -0
- package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -1
- package/lib/types/components/sidePanel/PanelBar.js +21 -17
- package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
- package/lib/types/components/sidePanel/PanelHost.js +5 -1
- package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
- package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
- package/lib/types/components/sidePanel/PanelStore.js +11 -0
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts +1 -1
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
- package/lib/types/components/sidePanel/SidePanelColumn.js +15 -2
- package/lib/types/components/sidePanel/SidePanelLayout.d.ts +6 -4
- package/lib/types/components/sidePanel/SidePanelLayout.d.ts.map +1 -1
- package/lib/types/components/sidePanel/SidePanelLayout.js +33 -7
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +7 -2
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwComposer.js +28 -8
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +156 -21
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwThreadScene.js +64 -16
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +15 -5
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwThreadView.js +101 -10
- package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
- package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/threads.js +51 -0
- package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
- package/lib/types/components/sidePanel/builtinPanels.js +5 -1
- package/lib/types/components/sidePanel/companion/CompanionPanel.js +2 -2
- package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
- package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
- package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
- package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
- package/lib/types/components/sidePanel/companion/skins.js +57 -12
- package/lib/types/components/sidePanel/types.d.ts +7 -1
- package/lib/types/components/sidePanel/types.d.ts.map +1 -1
- package/lib/types/components/sidePanel/useSidePanel.d.ts +2 -0
- package/lib/types/components/sidePanel/useSidePanel.d.ts.map +1 -1
- package/lib/types/components/sidePanel/useSidePanel.js +11 -1
- package/lib/types/components/splashArtRows.d.ts +29 -0
- package/lib/types/components/splashArtRows.d.ts.map +1 -0
- package/lib/types/components/splashArtRows.js +31 -0
- package/lib/types/components/splashFonts.d.ts +24 -1
- package/lib/types/components/splashFonts.d.ts.map +1 -1
- package/lib/types/components/splashFonts.js +40 -5
- package/lib/types/components/teamRoster.d.ts +70 -0
- package/lib/types/components/teamRoster.d.ts.map +1 -0
- package/lib/types/components/teamRoster.js +78 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +3 -1
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -1
- package/lib/types/components/workspaces/HomeWorkspaceRow.js +5 -2
- package/lib/types/dsh-adapter/admission-loader.d.ts +102 -0
- package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -0
- package/lib/types/dsh-adapter/admission-loader.js +301 -0
- package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
- package/lib/types/dsh-adapter/agent-view.js +3 -1
- package/lib/types/dsh-adapter/approvals.d.ts +7 -0
- package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
- package/lib/types/dsh-adapter/approvals.js +45 -1
- package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
- package/lib/types/dsh-adapter/backend/translate.js +71 -8
- package/lib/types/dsh-adapter/backend-admission.d.ts +64 -0
- package/lib/types/dsh-adapter/backend-admission.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend-admission.js +34 -0
- package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
- package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend-assembly.js +225 -0
- package/lib/types/dsh-adapter/backend-contribution.d.ts +62 -0
- package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend-contribution.js +78 -0
- package/lib/types/dsh-adapter/backend-registry.d.ts +136 -0
- package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend-registry.js +304 -0
- package/lib/types/dsh-adapter/backends.d.ts +67 -24
- package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
- package/lib/types/dsh-adapter/backends.generated.d.ts +12 -0
- package/lib/types/dsh-adapter/backends.generated.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backends.generated.js +6 -0
- package/lib/types/dsh-adapter/backends.js +91 -46
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/bundled-presets.js +60 -3
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +2 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +9 -3
- package/lib/types/dsh-adapter/channel/agent-view-projection.js +2 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +8 -3
- package/lib/types/dsh-adapter/channel/binding-events.d.ts +17 -3
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +19 -46
- package/lib/types/dsh-adapter/channel/channel-host.d.ts +45 -0
- package/lib/types/dsh-adapter/channel/channel-host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/channel-host.js +1 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/command-completions.js +79 -6
- package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
- package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/compaction.js +100 -26
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +4 -2
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +36 -5
- package/lib/types/dsh-adapter/channel/cordis-host.d.ts +14 -0
- package/lib/types/dsh-adapter/channel/cordis-host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/cordis-host.js +35 -0
- package/lib/types/dsh-adapter/channel/core/actions.d.ts +3 -3
- package/lib/types/dsh-adapter/channel/core/actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/actions.js +15 -6
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +10 -3
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/binding-feed.js +5 -1
- package/lib/types/dsh-adapter/channel/core/compose.d.ts +12 -28
- package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/compose.js +330 -117
- package/lib/types/dsh-adapter/channel/core/files.d.ts +7 -2
- package/lib/types/dsh-adapter/channel/core/files.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/files.js +1 -0
- package/lib/types/dsh-adapter/channel/core/host.d.ts +12 -6
- package/lib/types/dsh-adapter/channel/core/host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/host.js +69 -35
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts +5 -3
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/local-actions.js +5 -2
- package/lib/types/dsh-adapter/channel/core/session-controls.js +2 -2
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts +7 -4
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/session-switch.js +8 -4
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/sessions.js +75 -16
- package/lib/types/dsh-adapter/channel/extensions.d.ts +4 -3
- package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/extensions.js +109 -30
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +14 -5
- package/lib/types/dsh-adapter/channel/job-projection.d.ts +4 -0
- package/lib/types/dsh-adapter/channel/job-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/job-projection.js +205 -24
- package/lib/types/dsh-adapter/channel/mentions.d.ts +3 -3
- package/lib/types/dsh-adapter/channel/mentions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +7 -0
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.js +235 -13
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +5 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +48 -29
- package/lib/types/dsh-adapter/channel/model-selection.d.ts +17 -0
- package/lib/types/dsh-adapter/channel/model-selection.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/model-selection.js +109 -0
- package/lib/types/dsh-adapter/channel/model-switch.d.ts +12 -21
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +39 -102
- package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/permissions.js +4 -1
- package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
- package/lib/types/dsh-adapter/channel/projection.js +1 -1
- package/lib/types/dsh-adapter/channel/reports.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/reports.js +11 -3
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +33 -20
- package/lib/types/dsh-adapter/channel/session-listing.d.ts +20 -0
- package/lib/types/dsh-adapter/channel/session-listing.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/session-listing.js +51 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +3 -1
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +60 -30
- package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +22 -8
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +38 -24
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +38 -24
- package/lib/types/dsh-adapter/channel/settings-host.d.ts +5 -2
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +136 -5
- package/lib/types/dsh-adapter/channel/state.d.ts +43 -1
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +14 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +84 -12
- package/lib/types/dsh-adapter/channel/task-completion.d.ts +6 -0
- package/lib/types/dsh-adapter/channel/task-completion.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/task-completion.js +114 -0
- package/lib/types/dsh-adapter/channel/transcript.d.ts +8 -1
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +20 -3
- package/lib/types/dsh-adapter/channel/upstream-retry.d.ts +81 -0
- package/lib/types/dsh-adapter/channel/upstream-retry.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/upstream-retry.js +138 -0
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +9 -8
- package/lib/types/dsh-adapter/channel-ui.d.ts +3 -1
- package/lib/types/dsh-adapter/channel-ui.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel-ui.js +4 -2
- package/lib/types/dsh-adapter/channel.d.ts +2 -2
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +19 -5
- package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
- package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
- package/lib/types/dsh-adapter/context-occupancy.d.ts +81 -4
- package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -1
- package/lib/types/dsh-adapter/context-occupancy.js +108 -17
- package/lib/types/dsh-adapter/contract.d.ts +4 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +20 -5
- package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
- package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
- package/lib/types/dsh-adapter/effect-ledger.js +8 -1
- package/lib/types/dsh-adapter/entry-slot.d.ts +38 -0
- package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -0
- package/lib/types/dsh-adapter/entry-slot.js +28 -0
- package/lib/types/dsh-adapter/fresh-agent.d.ts +22 -0
- package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -0
- package/lib/types/dsh-adapter/fresh-agent.js +226 -0
- package/lib/types/dsh-adapter/host-access.d.ts +16 -1
- package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
- package/lib/types/dsh-adapter/host-access.js +148 -2
- package/lib/types/dsh-adapter/host-contract.d.ts +103 -0
- package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-contract.js +77 -0
- package/lib/types/dsh-adapter/host-dsh.d.ts +112 -0
- package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-dsh.js +481 -0
- package/lib/types/dsh-adapter/host-entry.d.ts +9 -0
- package/lib/types/dsh-adapter/host-entry.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-entry.js +253 -0
- package/lib/types/dsh-adapter/index.d.ts +53 -17
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +63 -9
- package/lib/types/dsh-adapter/install/executors.d.ts +44 -0
- package/lib/types/dsh-adapter/install/executors.d.ts.map +1 -0
- package/lib/types/dsh-adapter/install/executors.js +15 -0
- package/lib/types/dsh-adapter/install/pnpm-profile-add.d.ts +3 -0
- package/lib/types/dsh-adapter/install/pnpm-profile-add.d.ts.map +1 -0
- package/lib/types/dsh-adapter/install/pnpm-profile-add.js +150 -0
- package/lib/types/dsh-adapter/invariant.d.ts +7 -2
- package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
- package/lib/types/dsh-adapter/invariant.js +6 -3
- package/lib/types/dsh-adapter/jobs.d.ts +7 -0
- package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/jobs.js +13 -0
- package/lib/types/dsh-adapter/lite-profile.d.ts +50 -0
- package/lib/types/dsh-adapter/lite-profile.d.ts.map +1 -0
- package/lib/types/dsh-adapter/lite-profile.js +49 -0
- package/lib/types/dsh-adapter/migrate/index.js +2 -2
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +1 -1
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -1
- package/lib/types/dsh-adapter/migrate/parse/jsonl.js +4 -3
- package/lib/types/dsh-adapter/oauth/profiles.d.ts.map +1 -1
- package/lib/types/dsh-adapter/oauth/profiles.js +5 -1
- package/lib/types/dsh-adapter/panels.d.ts +7 -0
- package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
- package/lib/types/dsh-adapter/panels.js +41 -2
- package/lib/types/dsh-adapter/plugin-completions.d.ts +32 -0
- package/lib/types/dsh-adapter/plugin-completions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-completions.js +80 -0
- package/lib/types/dsh-adapter/plugin-declaration.d.ts +119 -0
- package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-declaration.js +183 -0
- package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
- package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-feed.js +135 -0
- package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
- package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-guard.js +108 -0
- package/lib/types/dsh-adapter/plugin-host.d.ts +13 -2
- package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin-host.js +34 -8
- package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
- package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-install.js +545 -0
- package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
- package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-manage.js +468 -0
- package/lib/types/dsh-adapter/plugin-manager.d.ts +144 -0
- package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-manager.js +83 -0
- package/lib/types/dsh-adapter/plugin.d.ts +50 -1
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +918 -234
- package/lib/types/dsh-adapter/plugins-info.d.ts +130 -8
- package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugins-info.js +469 -44
- package/lib/types/dsh-adapter/process-exit.d.ts +43 -0
- package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -0
- package/lib/types/dsh-adapter/process-exit.js +60 -0
- package/lib/types/dsh-adapter/root-dispose.d.ts +18 -0
- package/lib/types/dsh-adapter/root-dispose.d.ts.map +1 -0
- package/lib/types/dsh-adapter/root-dispose.js +28 -0
- package/lib/types/dsh-adapter/session-list-metadata.d.ts +20 -0
- package/lib/types/dsh-adapter/session-list-metadata.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-list-metadata.js +56 -0
- package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
- package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-projection-store.js +149 -0
- package/lib/types/dsh-adapter/session-seed.d.ts +11 -0
- package/lib/types/dsh-adapter/session-seed.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-seed.js +47 -0
- package/lib/types/dsh-adapter/sessions/list.d.ts +3 -1
- package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/list.js +11 -5
- package/lib/types/dsh-adapter/sessions/snapshot.d.ts +0 -2
- package/lib/types/dsh-adapter/sessions/snapshot.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/snapshot.js +7 -70
- package/lib/types/dsh-adapter/settingsEditor.js +2 -2
- package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
- package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sideQuestion.js +53 -0
- package/lib/types/dsh-adapter/startup-args.d.ts +2 -0
- package/lib/types/dsh-adapter/startup-args.d.ts.map +1 -1
- package/lib/types/dsh-adapter/startup-args.js +5 -0
- package/lib/types/dsh-adapter/subagents.d.ts +33 -1
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +112 -9
- package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
- package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
- package/lib/types/dsh-adapter/team-mode.js +188 -0
- package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
- package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
- package/lib/types/dsh-adapter/team-roster.js +136 -0
- package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
- package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
- package/lib/types/dsh-adapter/team-tools.js +208 -0
- package/lib/types/dsh-adapter/tui-settings.d.ts +57 -0
- package/lib/types/dsh-adapter/tui-settings.d.ts.map +1 -0
- package/lib/types/dsh-adapter/tui-settings.js +199 -0
- package/lib/types/dsh-adapter/types.d.ts +1 -1
- package/lib/types/dsh-adapter/types.d.ts.map +1 -1
- package/lib/types/effortPrefs.d.ts +6 -3
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +7 -4
- package/lib/types/hostEntryRoute.d.ts +18 -0
- package/lib/types/hostEntryRoute.d.ts.map +1 -0
- package/lib/types/hostEntryRoute.js +57 -0
- package/lib/types/i18n.d.ts +961 -1439
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +443 -387
- package/lib/types/ink/components/AlternateScreen.js +2 -2
- package/lib/types/ink/components/App.d.ts +1 -0
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +16 -4
- package/lib/types/ink/components/CursorDeclarationContext.d.ts +9 -0
- package/lib/types/ink/components/CursorDeclarationContext.d.ts.map +1 -1
- package/lib/types/ink/components/CursorDeclarationContext.js +2 -0
- package/lib/types/ink/components/ScrollBox.d.ts +9 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +23 -0
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts +2 -2
- package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.js +13 -7
- package/lib/types/ink/hooks/use-declared-cursor.d.ts +11 -3
- package/lib/types/ink/hooks/use-declared-cursor.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-declared-cursor.js +30 -10
- package/lib/types/ink/ink.d.ts +22 -17
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +151 -40
- package/lib/types/ink/kitty-graphics.d.ts +2 -0
- package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
- package/lib/types/ink/kitty-graphics.js +6 -1
- package/lib/types/ink/node-cache.d.ts +2 -1
- package/lib/types/ink/node-cache.d.ts.map +1 -1
- package/lib/types/ink/output.d.ts +10 -4
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +14 -10
- package/lib/types/ink/render-node-to-output.d.ts +5 -2
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +27 -9
- package/lib/types/ink/renderer.d.ts +1 -0
- package/lib/types/ink/renderer.d.ts.map +1 -1
- package/lib/types/ink/renderer.js +4 -3
- package/lib/types/ink/root.d.ts +4 -1
- package/lib/types/ink/root.d.ts.map +1 -1
- package/lib/types/ink/screen.d.ts +4 -2
- package/lib/types/ink/screen.d.ts.map +1 -1
- package/lib/types/ink/selection.d.ts +10 -1
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +94 -25
- package/lib/types/ink/stdin-handoff.d.ts +11 -0
- package/lib/types/ink/stdin-handoff.d.ts.map +1 -0
- package/lib/types/ink/stdin-handoff.js +20 -0
- package/lib/types/ink/styles.d.ts +2 -1
- package/lib/types/ink/styles.d.ts.map +1 -1
- package/lib/types/ink/terminal-image.d.ts +6 -4
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal-image.js +16 -39
- package/lib/types/ink/terminal-notification.d.ts +8 -0
- package/lib/types/ink/terminal-notification.d.ts.map +1 -0
- package/lib/types/ink/terminal-notification.js +83 -0
- package/lib/types/ink/terminal.d.ts +9 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +34 -1
- package/lib/types/ink/termio/csi.d.ts +11 -0
- package/lib/types/ink/termio/csi.d.ts.map +1 -1
- package/lib/types/ink/termio/csi.js +13 -0
- package/lib/types/ink/update-overflow-guard.d.ts +6 -0
- package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
- package/lib/types/ink/update-overflow-guard.js +17 -0
- package/lib/types/ink/wrap-text.d.ts +6 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -1
- package/lib/types/ink/wrap-text.js +17 -0
- package/lib/types/kernelPrefs.d.ts +130 -17
- package/lib/types/kernelPrefs.d.ts.map +1 -1
- package/lib/types/kernelPrefs.js +98 -35
- package/lib/types/math/inline-layout.d.ts +2 -0
- package/lib/types/math/inline-layout.d.ts.map +1 -1
- package/lib/types/math/inline-layout.js +5 -27
- package/lib/types/modelGroups.d.ts +15 -27
- package/lib/types/modelGroups.d.ts.map +1 -1
- package/lib/types/modelGroups.js +17 -31
- package/lib/types/modelPrefs.d.ts +5 -4
- package/lib/types/modelPrefs.d.ts.map +1 -1
- package/lib/types/modelPrefs.js +5 -4
- package/lib/types/modelRoute.d.ts +23 -9
- package/lib/types/modelRoute.d.ts.map +1 -1
- package/lib/types/modelRoute.js +25 -11
- package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
- package/lib/types/native-ts/yoga-layout/index.js +8 -1
- package/lib/types/permissionPrefs.d.ts +34 -0
- package/lib/types/permissionPrefs.d.ts.map +1 -0
- package/lib/types/permissionPrefs.js +61 -0
- package/lib/types/permissionPresetLabels.d.ts +25 -0
- package/lib/types/permissionPresetLabels.d.ts.map +1 -0
- package/lib/types/permissionPresetLabels.js +33 -0
- package/lib/types/plugin-host.d.ts +1 -0
- package/lib/types/plugin-host.d.ts.map +1 -1
- package/lib/types/preset-patch.d.ts +22 -0
- package/lib/types/preset-patch.d.ts.map +1 -0
- package/lib/types/preset-patch.js +14 -0
- package/lib/types/presetPrefs.d.ts +17 -3
- package/lib/types/presetPrefs.d.ts.map +1 -1
- package/lib/types/presetPrefs.js +20 -3
- package/lib/types/reload.d.ts +6 -10
- package/lib/types/reload.d.ts.map +1 -1
- package/lib/types/reload.js +14 -14
- package/lib/types/screens/Chat.d.ts +55 -16
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +742 -280
- package/lib/types/screens/Launchpad.d.ts +33 -17
- package/lib/types/screens/Launchpad.d.ts.map +1 -1
- package/lib/types/screens/Launchpad.js +256 -78
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/SessionSupervisor.js +53 -12
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +7 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +24 -7
- package/lib/types/screens/StatusMetrics.d.ts +46 -1
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +72 -0
- package/lib/types/screens/chat/useKernelPicker.d.ts +8 -4
- package/lib/types/screens/chat/useKernelPicker.d.ts.map +1 -1
- package/lib/types/screens/chat/useKernelPicker.js +61 -21
- package/lib/types/screens/chat/useModelPicker.d.ts +42 -0
- package/lib/types/screens/chat/useModelPicker.d.ts.map +1 -0
- package/lib/types/screens/chat/useModelPicker.js +182 -0
- package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
- package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
- package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
- package/lib/types/screens/chatOverlay.d.ts +30 -5
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- package/lib/types/screens/chatOverlay.js +0 -1
- package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts +4 -1
- package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.js +26 -5
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +1 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +51 -29
- package/lib/types/sessionHistory.d.ts +5 -0
- package/lib/types/sessionHistory.d.ts.map +1 -1
- package/lib/types/sessionHistory.js +5 -0
- package/lib/types/sessionModes.d.ts +5 -3
- package/lib/types/sessionModes.d.ts.map +1 -1
- package/lib/types/sessionModes.js +9 -3
- package/lib/types/sessions/listSnapshot.d.ts +6 -0
- package/lib/types/sessions/listSnapshot.d.ts.map +1 -0
- package/lib/types/sessions/listSnapshot.js +67 -0
- package/lib/types/settings/definitions.d.ts +50 -0
- package/lib/types/settings/definitions.d.ts.map +1 -1
- package/lib/types/settings/definitions.js +42 -8
- package/lib/types/terminal-utils/cjk-emphasis.d.ts +28 -0
- package/lib/types/terminal-utils/cjk-emphasis.d.ts.map +1 -0
- package/lib/types/terminal-utils/cjk-emphasis.js +31 -0
- package/lib/types/terminal-utils/markdown.d.ts +3 -1
- package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
- package/lib/types/terminal-utils/markdown.js +7 -2
- package/lib/types/theme.d.ts +29 -12
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +310 -23
- package/lib/types/themeCatalog.d.ts.map +1 -1
- package/lib/types/themeCatalog.js +21 -2
- package/lib/types/tips.js +4 -4
- package/lib/types/tuiSettingsFile.d.ts +56 -0
- package/lib/types/tuiSettingsFile.d.ts.map +1 -0
- package/lib/types/tuiSettingsFile.js +206 -0
- package/lib/types/ui.d.ts +2 -0
- package/lib/types/ui.d.ts.map +1 -1
- package/lib/types/ui.js +2 -0
- package/lib/types/update.d.ts +72 -26
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +131 -43
- package/lib/types/utils/bmp.d.ts +7 -0
- package/lib/types/utils/bmp.d.ts.map +1 -1
- package/lib/types/utils/bmp.js +27 -0
- package/lib/types/utils/bootTrace.d.ts +2 -0
- package/lib/types/utils/bootTrace.d.ts.map +1 -0
- package/lib/types/utils/bootTrace.js +20 -0
- package/lib/types/utils/clipboard.d.ts.map +1 -1
- package/lib/types/utils/clipboard.js +11 -3
- package/lib/types/utils/credentials.d.ts +14 -2
- package/lib/types/utils/credentials.d.ts.map +1 -1
- package/lib/types/utils/credentials.js +34 -11
- package/lib/types/utils/imageResize.d.ts +10 -20
- package/lib/types/utils/imageResize.d.ts.map +1 -1
- package/lib/types/utils/imageResize.js +61 -134
- package/lib/types/utils/inputPaste.d.ts +2 -2
- package/lib/types/utils/inputPaste.js +2 -2
- package/lib/types/utils/pastedImagePath.d.ts +5 -0
- package/lib/types/utils/pastedImagePath.d.ts.map +1 -1
- package/lib/types/utils/pastedImagePath.js +33 -0
- package/lib/types/utils/paths.d.ts +11 -0
- package/lib/types/utils/paths.d.ts.map +1 -1
- package/lib/types/utils/paths.js +13 -0
- package/package.json +150 -114
- package/presets/winbash.mjs +716 -0
- package/tui-profile/feed/README.md +63 -0
- package/tui-profile/feed/first-party.json +10 -0
- package/tui-profile/protocols/profile-definitions.d.ts +1 -0
- package/tui-profile/protocols/profile-definitions.js +14 -0
- package/tui-profile/protocols/tui-contributions.d.ts +55 -0
- package/tui-profile/protocols/tui-contributions.js +141 -0
- package/tui-profile/registry/contracts/backend-v1alpha1.json +13 -0
- package/tui-profile/registry/registry-0.15.json +12 -0
- package/lib/types/backends/claude/install.d.ts +0 -15
- package/lib/types/backends/claude/install.d.ts.map +0 -1
- package/lib/types/backends/claude/install.js +0 -91
- package/lib/types/channel/elicitation.d.ts.map +0 -1
- package/lib/types/dsh-adapter/channel/session-lineage.d.ts +0 -42
- package/lib/types/dsh-adapter/channel/session-lineage.d.ts.map +0 -1
- package/lib/types/dsh-adapter/channel/session-lineage.js +0 -51
- package/lib/types/utils/jsonl.d.ts.map +0 -1
|
@@ -4,24 +4,24 @@ import { t, getLang, setLang, isLang, writeLangPref, readLangPref, subscribeLang
|
|
|
4
4
|
import { checkForTuiUpdate, installedTuiVersion } from '../update.js';
|
|
5
5
|
import { installedKernelVersion } from '../dsh-adapter/contract.js';
|
|
6
6
|
import { readThemePref } from '../themePrefs.js';
|
|
7
|
-
import { readPresetPref } from '../presetPrefs.js';
|
|
7
|
+
import { presetOverrideFromEnv, readPresetPref } from '../presetPrefs.js';
|
|
8
8
|
import { readModelPref } from '../modelPrefs.js';
|
|
9
9
|
import { readActivityFrames } from '../activityPrefs.js';
|
|
10
10
|
import { envThemeOverride } from '../components/design-system/ThemeProvider.js';
|
|
11
11
|
import { resolveBrand, setActiveBrand } from '../branding.js';
|
|
12
12
|
import { hasPath } from '../dsh-adapter/settingsEditor.js';
|
|
13
13
|
import { planReload } from '../reload.js';
|
|
14
|
-
import { AlternateScreen, Box, Image, Text, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
|
|
14
|
+
import { AlternateScreen, Box, Image, Text, InputCaret, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
|
|
15
15
|
import { usePageInset } from '../components/PageMargin.js';
|
|
16
16
|
import { POINTER } from '../terminal-utils/figures.js';
|
|
17
|
+
import { previousCodePoint } from '../components/AgentMessageComposer.js';
|
|
17
18
|
import { isPlainReturnInput } from '../utils/modifiers.js';
|
|
18
19
|
import { actionMatches, effectiveComboDisplay, primaryComboString } from '../utils/keymap.js';
|
|
19
20
|
import { formatTokens } from '../terminal-utils/format.js';
|
|
20
21
|
import { formatClock } from '../trajectory/format.js';
|
|
21
22
|
import { homeDir } from '../utils/paths.js';
|
|
22
23
|
import { execFileNoThrow } from '../utils/execFileNoThrow.js';
|
|
23
|
-
import { cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
|
|
24
|
-
import { deriveModelGroups, modelPickerLanding, recentCatalogModels, RECENTS_GROUP_PROVIDER, } from '../modelGroups.js';
|
|
24
|
+
import { cleanBlockLines, cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
|
|
25
25
|
import { readModelRecents, recordModelUse } from '../modelRecents.js';
|
|
26
26
|
import { WORKING_GATE_NOTICES } from '../commands.js';
|
|
27
27
|
import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
|
|
@@ -37,6 +37,7 @@ const MATH_PREVIEW_MAX_COLUMNS = 480;
|
|
|
37
37
|
const MATH_PREVIEW_MAX_ROWS = 64;
|
|
38
38
|
import { runOAuthLogin, runProviderWizard } from '../dsh-adapter/providerWizard.js';
|
|
39
39
|
import { useKernelPicker } from './chat/useKernelPicker.js';
|
|
40
|
+
import { useModelPicker } from './chat/useModelPicker.js';
|
|
40
41
|
import { useBackendChannels } from './chat/useBackendChannels.js';
|
|
41
42
|
import { backendModeStatus as modeStatus, backendPermissionCommand, parseMcpCommand } from './chat/backendCommands.js';
|
|
42
43
|
import { PermissionStore } from '../channel/permissions.js';
|
|
@@ -60,11 +61,12 @@ import { ScrollbarGutter } from '../components/ScrollbarGutter.js';
|
|
|
60
61
|
import { normalizeScrollGutter } from '../tuiDisplayPrefs.js';
|
|
61
62
|
import { OverlayAbove } from '../components/OverlayAbove.js';
|
|
62
63
|
import { TooltipLayer } from '../components/Tooltip.js';
|
|
63
|
-
import { PromptInput } from '../components/PromptInput.js';
|
|
64
|
+
import { PromptInput, composerImageRefsForText } from '../components/PromptInput.js';
|
|
64
65
|
import { turnUsageParts } from '../components/TurnUsageRow.js';
|
|
65
66
|
import { AgentTranscriptScene } from './AgentTranscriptScene.js';
|
|
66
67
|
import { agentViewStore } from '../components/sidePanel/agentViewStore.js';
|
|
67
68
|
import { agentComposeTargetOf } from '../components/messages/agentTeam.js';
|
|
69
|
+
import { resolveBindingGeneration } from '../components/promptDraftCache.js';
|
|
68
70
|
import { PromptEditorLayer, usePromptEditorOpen } from '../components/PromptEditor.js';
|
|
69
71
|
import { GoalTodoPanel } from '../components/GoalTodoPanel.js';
|
|
70
72
|
import { useSidePanel } from '../components/sidePanel/useSidePanel.js';
|
|
@@ -105,8 +107,13 @@ import { PermissionsPicker } from '../components/PermissionsPicker.js';
|
|
|
105
107
|
import { ModePicker } from '../components/ModePicker.js';
|
|
106
108
|
import { KernelPicker } from '../components/KernelPicker.js';
|
|
107
109
|
import { SdkInstallWizard } from '../components/SdkInstallWizard.js';
|
|
110
|
+
import { PluginInstallPane } from '../components/PluginInstallPane.js';
|
|
111
|
+
import { PluginManagePane } from '../components/PluginManagePane.js';
|
|
112
|
+
import { teamMemberCounts } from '../components/teamRoster.js';
|
|
113
|
+
import { usePluginWriteFlow } from './chat/usePluginWriteFlow.js';
|
|
108
114
|
import { ChannelPicker } from '../components/ChannelPicker.js';
|
|
109
115
|
import { modeDisplayName } from '../sessionModes.js';
|
|
116
|
+
import { PERMISSION_PRESET_AUTO, permissionPresetLabel } from '../permissionPresetLabels.js';
|
|
110
117
|
import { PlanPicker } from '../components/PlanPicker.js';
|
|
111
118
|
import { LangPicker } from '../components/LangPicker.js';
|
|
112
119
|
import { ThemePicker, getThemeOptions } from '../components/ThemePicker.js';
|
|
@@ -142,12 +149,10 @@ import { Launchpad, launchpadVisible } from './Launchpad.js';
|
|
|
142
149
|
import { resolveLaunchpadActions } from '../components/launchpadActions.js';
|
|
143
150
|
import { Onboarding } from './Onboarding.js';
|
|
144
151
|
import { appendHistory } from '../history.js';
|
|
145
|
-
import { isHiddenCommandName, isLocalCommandName, parseCommandName } from '../commands.js';
|
|
152
|
+
import { isBootSafeCommand, isHiddenCommandName, isLocalCommandName, isUnavailableLocalCommand, parseCommandName } from '../commands.js';
|
|
146
153
|
import { extendTrajectory, projectWave } from '../dsh-adapter/trajectory/index.js';
|
|
147
154
|
import { miniWakeWidth } from '../components/trajectory/MiniWake.js';
|
|
148
155
|
import { readTrajectorySeen, writeTrajectorySeen } from '../trajectoryPrefs.js';
|
|
149
|
-
import { LoadingState } from '../components/design-system/LoadingState.js';
|
|
150
|
-
import { Pane } from '../components/design-system/Pane.js';
|
|
151
156
|
import { loadHistory } from '../history.js';
|
|
152
157
|
import { formatLoadedContextReport } from '../utils/loaded-context.js';
|
|
153
158
|
import { NO_OVERLAY, chatOverlayReducer, dialogOverlayVisible, wrapIndex, } from './chatOverlay.js';
|
|
@@ -171,6 +176,10 @@ const STATUS_VIEW_UI = Object.freeze({
|
|
|
171
176
|
/** Shared empty snapshot for hosts whose channel has no event log. */
|
|
172
177
|
const NO_EVENTS = [];
|
|
173
178
|
const COMMAND_RESULT_CELLS = 200;
|
|
179
|
+
/** Per-line width budget for a transcript block (`/plugins`, `/goal`): much
|
|
180
|
+
* wider than COMMAND_RESULT_CELLS, whose 200-cell single-line rule cannot
|
|
181
|
+
* carry a full goal objective. Still a bound, not "no limit". */
|
|
182
|
+
const LOCAL_BLOCK_CELLS = 4000;
|
|
174
183
|
/** Ceiling for one `dsh-tui migrate` child run. Discovery parses every source
|
|
175
184
|
* file, but a healthy import of thousands of conversations finishes well
|
|
176
185
|
* inside this; without a cap a wedged child would hang the loop forever. */
|
|
@@ -209,11 +218,24 @@ function cleanCommandError(error) {
|
|
|
209
218
|
return '';
|
|
210
219
|
}
|
|
211
220
|
}
|
|
221
|
+
/** Picking the experimental `auto` preset from the picker asks first, unless
|
|
222
|
+
* the session already sits on it. A typed `/permission auto` does not. */
|
|
223
|
+
function needsAutoConfirm(snapshot, value) {
|
|
224
|
+
return value === PERMISSION_PRESET_AUTO && snapshot.autoConfirmed !== true;
|
|
225
|
+
}
|
|
226
|
+
/** The current identity's display name, localized like the picker rows. */
|
|
227
|
+
function currentPermissionName(snapshot) {
|
|
228
|
+
const current = snapshot.current;
|
|
229
|
+
if (current === undefined)
|
|
230
|
+
return undefined;
|
|
231
|
+
return current.kind === 'preset' ? permissionPresetLabel(current) : current.name;
|
|
232
|
+
}
|
|
212
233
|
function clonePermissionPresetSnapshot(snapshot) {
|
|
213
234
|
return {
|
|
214
235
|
availability: snapshot.availability,
|
|
215
236
|
options: snapshot.options.map(option => ({ ...option })),
|
|
216
237
|
...(snapshot.current === undefined ? {} : { current: { ...snapshot.current } }),
|
|
238
|
+
...(snapshot.autoConfirmed === true ? { autoConfirmed: true } : {}),
|
|
217
239
|
};
|
|
218
240
|
}
|
|
219
241
|
/** Row kinds the message-selection cursor can land on. */
|
|
@@ -302,12 +324,14 @@ let fallbackStatusStore;
|
|
|
302
324
|
let fallbackActivityStore;
|
|
303
325
|
const noCouponSubscription = () => () => undefined;
|
|
304
326
|
const noCouponSnapshot = () => null;
|
|
327
|
+
/** Stable identity for hosts that supply no kernel entries (bare embeds, tests). */
|
|
328
|
+
const EMPTY_KERNEL_ENTRIES = [];
|
|
305
329
|
/** Identity of one caret-preview dismissal: the token (its title) on the
|
|
306
330
|
* image, so the same image staged twice is dismissed per token. */
|
|
307
331
|
function peekKey(image, title) {
|
|
308
332
|
return `${title ?? ''} ${image.id}`;
|
|
309
333
|
}
|
|
310
|
-
export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels,
|
|
334
|
+
export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels, kernelEntries = EMPTY_KERNEL_ENTRIES, onResolveSdkInstall, onPluginInstall, onPluginManage, onTeamCommand, kernelPinned, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, launchpadOnBoot, onboardingOnBoot, starPrompt, }) {
|
|
311
335
|
const writeRaw = React.useContext(TerminalWriteContext);
|
|
312
336
|
// Re-render whenever the channel mutates; rows/status are read fresh below.
|
|
313
337
|
// DEFAULT lane on purpose (useExternalVersion): the channel version bumps
|
|
@@ -423,35 +447,72 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
423
447
|
permissionOverlayFocusRef.current = null;
|
|
424
448
|
}
|
|
425
449
|
}, [overlay]);
|
|
450
|
+
// The preset registry and the session's current preset can change while
|
|
451
|
+
// the picker is open (the experimental `auto` preset registers or leaves
|
|
452
|
+
// live; another surface switches the preset; a session adopt moves to a
|
|
453
|
+
// fresh log). Reopen on the live snapshot, keeping the focused preset; a
|
|
454
|
+
// confirmation whose preset left drops back to the list. The channel
|
|
455
|
+
// memoizes the snapshot, so an unchanged roster, current identity and
|
|
456
|
+
// `autoConfirmed` flag are the same object and the resync stops there.
|
|
457
|
+
const permissionResyncRef = React.useRef(null);
|
|
458
|
+
React.useEffect(() => {
|
|
459
|
+
if (overlay.kind !== 'permission') {
|
|
460
|
+
permissionResyncRef.current = null;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
let live;
|
|
464
|
+
try {
|
|
465
|
+
live = channel.permissionPresets();
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const seen = permissionResyncRef.current;
|
|
471
|
+
if (seen?.overlay === overlay && seen.live === live)
|
|
472
|
+
return;
|
|
473
|
+
permissionResyncRef.current = { overlay, live };
|
|
474
|
+
const values = (snapshot) => snapshot.options.map(option => option.value).join('\n');
|
|
475
|
+
// A roster value change is the obvious case; the current identity and the
|
|
476
|
+
// session-scoped `autoConfirmed` flag can also move without changing the
|
|
477
|
+
// option values (another surface switches the preset, a session adopt
|
|
478
|
+
// lands, the auto preset leaves after a confirmation). Refresh on either,
|
|
479
|
+
// so `needsAutoConfirm` never reads a stale flag from another session.
|
|
480
|
+
if (values(live) === values(overlay.snapshot)
|
|
481
|
+
&& live.availability === overlay.snapshot.availability
|
|
482
|
+
&& live.current?.value === overlay.snapshot.current?.value
|
|
483
|
+
&& live.current?.kind === overlay.snapshot.current?.kind
|
|
484
|
+
&& live.autoConfirmed === overlay.snapshot.autoConfirmed)
|
|
485
|
+
return;
|
|
486
|
+
if (live.availability === 'unavailable' || live.options.length === 0) {
|
|
487
|
+
dispatchOverlay({ type: 'close-if', kind: 'permission' });
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const focusIndex = permissionOverlayFocusRef.current?.overlay === overlay
|
|
491
|
+
? permissionOverlayFocusRef.current.index
|
|
492
|
+
: overlay.index;
|
|
493
|
+
const focused = overlay.confirm === true ? PERMISSION_PRESET_AUTO : overlay.snapshot.options[focusIndex]?.value;
|
|
494
|
+
const liveCurrent = live.current?.kind === 'preset' ? live.current.value : undefined;
|
|
495
|
+
const index = [focused, liveCurrent]
|
|
496
|
+
.map(value => live.options.findIndex(option => option.value === value))
|
|
497
|
+
.find(found => found >= 0) ?? Math.min(1, live.options.length - 1);
|
|
498
|
+
const confirm = overlay.confirm === true && live.options.some(option => option.value === PERMISSION_PRESET_AUTO);
|
|
499
|
+
if (overlay.confirm === true && !confirm)
|
|
500
|
+
channel.notify(t('permission-auto-unavailable'), { color: 'warning' });
|
|
501
|
+
dispatchOverlay({
|
|
502
|
+
type: 'open-if',
|
|
503
|
+
overlay: { kind: 'permission', index, snapshot: clonePermissionPresetSnapshot(live), ...(confirm ? { confirm } : {}) },
|
|
504
|
+
when: ['permission'],
|
|
505
|
+
});
|
|
506
|
+
});
|
|
426
507
|
const [models, setModels] = React.useState([]);
|
|
427
|
-
|
|
508
|
+
const [modelsLoading, setModelsLoading] = React.useState(false);
|
|
509
|
+
const modelCatalogGeneration = React.useRef(0);
|
|
510
|
+
/** Provider display identities for the /model tabs; refreshed alongside `models`. */
|
|
428
511
|
const [providerInfos, setProviderInfos] = React.useState([]);
|
|
429
512
|
/** /model 最近使用分组:成功切换即记录(去重置顶,上限 10),重启保留。 */
|
|
430
|
-
|
|
513
|
+
const modelProviderTabs = channel.backendCapabilities?.modelRoutes !== 'backend';
|
|
431
514
|
const recentsBackend = channel.backendCapabilities?.backendId;
|
|
432
|
-
const [modelRecents, setModelRecents] = React.useState(() => readModelRecents(undefined, recentsBackend));
|
|
433
|
-
/** Two-level /model: the drilled-in provider route; undefined = group level.
|
|
434
|
-
* Reset on open; stale ids resolve back to the group level via `activeModelGroup`. */
|
|
435
|
-
const [modelGroup, setModelGroup] = React.useState(undefined);
|
|
436
|
-
/** True while the picker sits in the single-provider fast path (drilled in
|
|
437
|
-
* at open, the group level never shown): Esc closes directly and no back
|
|
438
|
-
* hint renders — a pinned recents pseudo-group must not fake a two-level
|
|
439
|
-
* walk the user never saw (issue #527 regression: repro-picker-windowing). */
|
|
440
|
-
const [modelPickerDirect, setModelPickerDirect] = React.useState(false);
|
|
441
|
-
/** Group rows over the current catalog, first-appearance (registry) order,
|
|
442
|
-
* with the pinned recents pseudo-group first when any entry is catalogued. */
|
|
443
|
-
const modelGroups = React.useMemo(() => deriveModelGroups(models, providerInfos, modelRecents), [models, providerInfos, modelRecents]);
|
|
444
|
-
/** The drilled-in group, but only while it still exists in the catalog. */
|
|
445
|
-
const activeModelGroup = modelGroup !== undefined && modelGroups.some(group => group.provider === modelGroup)
|
|
446
|
-
? modelGroup
|
|
447
|
-
: undefined;
|
|
448
|
-
const groupModels = React.useMemo(() => {
|
|
449
|
-
if (activeModelGroup === undefined)
|
|
450
|
-
return [];
|
|
451
|
-
if (activeModelGroup === RECENTS_GROUP_PROVIDER)
|
|
452
|
-
return recentCatalogModels(modelRecents, models);
|
|
453
|
-
return models.filter(model => model.provider === activeModelGroup);
|
|
454
|
-
}, [models, modelRecents, activeModelGroup]);
|
|
515
|
+
const [modelRecents, setModelRecents] = React.useState(() => modelProviderTabs ? readModelRecents(undefined, recentsBackend) : []);
|
|
455
516
|
/** Switch + record: every successful switch feeds the /model recents group
|
|
456
517
|
* (picker Enter/click, `/model provider/id`, the wizard's live switch,
|
|
457
518
|
* and /reload's applied model all ride this one path). */
|
|
@@ -463,10 +524,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
463
524
|
return ok;
|
|
464
525
|
if (name !== undefined)
|
|
465
526
|
channel.notify(t('model-switched', { name }));
|
|
466
|
-
|
|
527
|
+
if (modelProviderTabs)
|
|
528
|
+
setModelRecents(recordModelUse({ provider, id }, undefined, recentsBackend));
|
|
467
529
|
return ok;
|
|
468
530
|
});
|
|
469
531
|
};
|
|
532
|
+
const modelPicker = useModelPicker({
|
|
533
|
+
channel, models, providers: providerInfos, recents: modelProviderTabs ? modelRecents : undefined, open: overlay.kind === 'model',
|
|
534
|
+
onCancel: () => dispatchOverlay({ type: 'close-if', kind: 'model' }),
|
|
535
|
+
onPick: (model, effort) => {
|
|
536
|
+
dispatchOverlay({ type: 'close-if', kind: 'model' });
|
|
537
|
+
void switchModelRecorded(model.provider, model.id, model.name).then(ok => {
|
|
538
|
+
// Validate/apply on the adopted route; a refused switch leaves both
|
|
539
|
+
// the live effort and its persisted preference untouched.
|
|
540
|
+
if (ok && effort !== undefined)
|
|
541
|
+
return channel.setEffort(effort);
|
|
542
|
+
});
|
|
543
|
+
},
|
|
544
|
+
});
|
|
470
545
|
/** `/skills` 技能目录(issue #204):null = 注册表快照在途。 */
|
|
471
546
|
const [skillsList, setSkillsList] = React.useState(null);
|
|
472
547
|
/**
|
|
@@ -496,7 +571,13 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
496
571
|
// 整屏」,浏览器必须提前藏在下面;现在整屏(会话/设置/任务面板)盖在
|
|
497
572
|
// 落地页**之上**、Esc 退回落地页,按需打开即可——boot 时同时为真反而会
|
|
498
573
|
// 让浏览器盖住落地页(渲染顺序见各 early-return)。恢复重挂同样不开它。
|
|
499
|
-
|
|
574
|
+
// A channel still starting its session (in-process DSH kernel) holds the two
|
|
575
|
+
// DSH boot screens (home, guide) until `ready`; the effect after
|
|
576
|
+
// `settingsOpen` opens them then.
|
|
577
|
+
const heldBootScreensRef = React.useRef(channel.ready === false && !recoveryRemountOnBoot
|
|
578
|
+
? { home: openHomeOnBoot === true && launchpadOnBoot !== true, onboarding: onboardingOnBoot === true }
|
|
579
|
+
: undefined);
|
|
580
|
+
const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true && launchpadOnBoot !== true && !recoveryRemountOnBoot && channel.ready !== false);
|
|
500
581
|
/**
|
|
501
582
|
* The launchpad: the landing page every ordinary launch starts on.
|
|
502
583
|
*
|
|
@@ -514,6 +595,40 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
514
595
|
const [launchpadDraft, setLaunchpadDraft] = React.useState('');
|
|
515
596
|
const [launchpadCaret, setLaunchpadCaret] = React.useState(0);
|
|
516
597
|
const [launchpadFocus, setLaunchpadFocus] = React.useState(-1);
|
|
598
|
+
const launchpadImagesRef = React.useRef(new Map());
|
|
599
|
+
const changeLaunchpadDraft = (text, cursor) => {
|
|
600
|
+
const live = new Set(composerImageRefsForText(text, launchpadImagesRef.current).map(image => image.token));
|
|
601
|
+
for (const [token, stageId] of launchpadImagesRef.current) {
|
|
602
|
+
if (live.has(token))
|
|
603
|
+
continue;
|
|
604
|
+
launchpadImagesRef.current.delete(token);
|
|
605
|
+
channel.discardStagedImage(stageId);
|
|
606
|
+
}
|
|
607
|
+
setLaunchpadDraft(text);
|
|
608
|
+
setLaunchpadCaret(cursor);
|
|
609
|
+
};
|
|
610
|
+
const launchpadBindingGeneration = resolveBindingGeneration(channel);
|
|
611
|
+
// Capture the image epoch with each session binding. Automatic startup keeps
|
|
612
|
+
// it; explicit replacement revokes it before publishing the new binding.
|
|
613
|
+
const composerImageGeneration = channel.stagedImageGeneration?.() ?? 0;
|
|
614
|
+
const launchpadSessionRef = React.useRef({ id: channel.agentId, imageGeneration: composerImageGeneration });
|
|
615
|
+
const discardLaunchpadImages = () => {
|
|
616
|
+
for (const stageId of launchpadImagesRef.current.values())
|
|
617
|
+
channel.discardStagedImage(stageId);
|
|
618
|
+
launchpadImagesRef.current.clear();
|
|
619
|
+
};
|
|
620
|
+
// Lifetime cleanup is separate from binding changes: startup adoption keeps
|
|
621
|
+
// the same draft, including the capabilities behind its image tokens.
|
|
622
|
+
React.useEffect(() => discardLaunchpadImages, [channel]);
|
|
623
|
+
React.useEffect(() => {
|
|
624
|
+
const previous = launchpadSessionRef.current;
|
|
625
|
+
launchpadSessionRef.current = { id: channel.agentId, imageGeneration: composerImageGeneration };
|
|
626
|
+
if (previous.id === '' && channel.agentId !== '' && previous.imageGeneration === composerImageGeneration)
|
|
627
|
+
return;
|
|
628
|
+
setLaunchpadDraft('');
|
|
629
|
+
setLaunchpadCaret(0);
|
|
630
|
+
discardLaunchpadImages();
|
|
631
|
+
}, [channel, channel.agentId, launchpadBindingGeneration]);
|
|
517
632
|
/**
|
|
518
633
|
* 「整屏盖启动页」的显式授权(第七版防御位,用户实测回归:启动页一闪而过
|
|
519
634
|
* 被顶掉)。整屏分支排在落地页**之前**,任何一处状态在开机后被异步置真
|
|
@@ -555,7 +670,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
555
670
|
* settings / help 的 early-return 排在两个界面**之后**:不收掉当前界面就是
|
|
556
671
|
* "点了没反应",状态还滞留着、等界面关掉才突然弹出来。默认收,白名单只留给覆盖层。
|
|
557
672
|
*/
|
|
558
|
-
const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel']), []);
|
|
673
|
+
const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel', 'dsh', 'codex', 'claude']), []);
|
|
559
674
|
/**
|
|
560
675
|
* 打开**整屏界面**的命令(第七版):从落地页触发这些命令时**不收掉落地页**
|
|
561
676
|
* ——整屏盖在落地页之上渲染(它们的 early-return 排在落地页分支之前),
|
|
@@ -580,59 +695,80 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
580
695
|
setLaunchpadUpdateAvailable(update !== undefined);
|
|
581
696
|
}).catch(() => undefined);
|
|
582
697
|
}, [launchpadShown]);
|
|
583
|
-
const canInstallSdk =
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
channel, kernelVersion, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
|
|
698
|
+
const canInstallSdk = onResolveSdkInstall !== undefined;
|
|
699
|
+
const { currentId: kernelCurrentId, options: kernelOptions, open: openKernelPicker, pick: pickKernel, pickById: pickKernelById, reprobe: reprobeKernels } = useKernelPicker({
|
|
700
|
+
channel, kernelVersion, kernelEntries, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
|
|
587
701
|
});
|
|
702
|
+
/** 当前内核那一行:短名给落地页入口、PromptInput 的不可用提示等消费(同源,
|
|
703
|
+
* 不按 id 查表;目录里没有(宿主未接线/未知后端)就没有名字)。 */
|
|
704
|
+
const kernelCurrentOption = kernelOptions.find(option => option.current);
|
|
588
705
|
/**
|
|
589
706
|
* SDK 安装向导的步骤态(异步进程状态,按 chatOverlay 的分工留在 Chat,
|
|
590
|
-
* 不进 overlay union
|
|
591
|
-
*
|
|
592
|
-
* 的窗口内;关闭路径(Esc/Enter 离开)一律重置回 idle,下一次打开重新
|
|
593
|
-
* 解析安装目标。
|
|
707
|
+
* 不进 overlay union)。每次打开独占安装面与进程句柄;浮层关闭或替换时
|
|
708
|
+
* 取消安装并重置步骤,旧预检/安装结果不能落进下一次打开的向导。
|
|
594
709
|
*/
|
|
595
710
|
const [sdkPhase, setSdkPhase] = React.useState({ kind: 'idle' });
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
//
|
|
711
|
+
const sdkInstallRef = React.useRef(undefined);
|
|
712
|
+
const sdkOverlay = overlay.kind === 'sdk-install' ? overlay : undefined;
|
|
713
|
+
// 安装面在这次打开时快照;宿主回调更新不重启正在进行的安装。
|
|
599
714
|
React.useEffect(() => {
|
|
600
|
-
if (
|
|
715
|
+
if (sdkOverlay === undefined)
|
|
716
|
+
return;
|
|
717
|
+
const surface = onResolveSdkInstall?.(sdkOverlay.backendId);
|
|
718
|
+
if (surface === undefined) {
|
|
719
|
+
dispatchOverlay({ type: 'close' });
|
|
601
720
|
return;
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
721
|
+
}
|
|
722
|
+
const installation = { surface };
|
|
723
|
+
sdkInstallRef.current = installation;
|
|
724
|
+
const target = surface.resolveTarget();
|
|
725
|
+
if (target.kind === 'profile') {
|
|
726
|
+
setSdkPhase({
|
|
727
|
+
kind: 'confirm',
|
|
728
|
+
dir: target.dir,
|
|
729
|
+
version: surface.version,
|
|
730
|
+
specifier: surface.specifier,
|
|
731
|
+
...(sdkOverlay.foundCli === undefined ? {} : { foundCli: sdkOverlay.foundCli }),
|
|
732
|
+
});
|
|
605
733
|
}
|
|
606
734
|
else {
|
|
607
735
|
setSdkPhase({ kind: 'no-target', reason: target.kind === 'standalone' ? 'standalone' : 'no-profile' });
|
|
608
736
|
}
|
|
609
|
-
|
|
737
|
+
return () => {
|
|
738
|
+
sdkInstallRef.current = undefined;
|
|
739
|
+
installation.installer?.cancel();
|
|
740
|
+
setSdkPhase({ kind: 'idle' });
|
|
741
|
+
};
|
|
742
|
+
}, [sdkOverlay]);
|
|
610
743
|
const closeSdkInstallToKernelPicker = () => {
|
|
611
|
-
setSdkPhase({ kind: 'idle' });
|
|
612
744
|
dispatchOverlay({ type: 'close' });
|
|
613
745
|
openKernelPicker();
|
|
614
746
|
};
|
|
615
747
|
const closeSdkInstall = () => {
|
|
616
|
-
setSdkPhase({ kind: 'idle' });
|
|
617
748
|
dispatchOverlay({ type: 'close' });
|
|
618
749
|
};
|
|
619
750
|
const runSdkInstall = (dir) => {
|
|
620
|
-
|
|
751
|
+
const installation = sdkInstallRef.current;
|
|
752
|
+
if (installation === undefined)
|
|
621
753
|
return;
|
|
622
|
-
const
|
|
623
|
-
|
|
754
|
+
const { surface } = installation;
|
|
755
|
+
const installer = surface.start(dir);
|
|
756
|
+
installation.installer = installer;
|
|
624
757
|
setSdkPhase({ kind: 'running' });
|
|
625
758
|
void installer.result.then(result => {
|
|
759
|
+
if (sdkInstallRef.current !== installation)
|
|
760
|
+
return;
|
|
761
|
+
installation.installer = undefined;
|
|
626
762
|
if (result.kind === 'ok') {
|
|
627
763
|
// 装好了:重探内核(灰行变亮,无需重启进程),停在完成面板。
|
|
628
764
|
reprobeKernels();
|
|
629
|
-
setSdkPhase({ kind: 'done' });
|
|
765
|
+
setSdkPhase({ kind: 'done', rebuiltStore: result.rebuiltStore === true });
|
|
630
766
|
}
|
|
631
767
|
else if (result.kind === 'failed') {
|
|
632
|
-
setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version:
|
|
768
|
+
setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version: surface.version, specifier: surface.specifier });
|
|
633
769
|
}
|
|
634
770
|
else if (result.kind === 'pnpm-missing') {
|
|
635
|
-
setSdkPhase({ kind: 'pnpm-missing', dir, version:
|
|
771
|
+
setSdkPhase({ kind: 'pnpm-missing', dir, version: surface.version, specifier: surface.specifier });
|
|
636
772
|
}
|
|
637
773
|
else {
|
|
638
774
|
setSdkPhase({ kind: 'cancelled' });
|
|
@@ -640,17 +776,93 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
640
776
|
});
|
|
641
777
|
};
|
|
642
778
|
const confirmSdkInstall = (dir) => {
|
|
643
|
-
|
|
779
|
+
const installation = sdkInstallRef.current;
|
|
780
|
+
if (installation === undefined)
|
|
644
781
|
return;
|
|
782
|
+
const { surface } = installation;
|
|
645
783
|
setSdkPhase({ kind: 'checking' });
|
|
646
|
-
void
|
|
647
|
-
if (
|
|
648
|
-
|
|
784
|
+
void surface.preflight().then(ok => {
|
|
785
|
+
if (sdkInstallRef.current !== installation)
|
|
786
|
+
return;
|
|
787
|
+
if (!ok) {
|
|
788
|
+
setSdkPhase({ kind: 'pnpm-missing', dir, version: surface.version, specifier: surface.specifier });
|
|
649
789
|
return;
|
|
650
790
|
}
|
|
651
791
|
runSdkInstall(dir);
|
|
652
792
|
});
|
|
653
793
|
};
|
|
794
|
+
/**
|
|
795
|
+
* `/plugin install <spec>` 的步骤态(C-4)。六件套(ref / state / 收尾 / 结算 /
|
|
796
|
+
* 栅栏 / 起步)与 manage 侧共用 `usePluginWriteFlow`,两处的差异只有「关浮层
|
|
797
|
+
* 要不要取消」与「Enter 调哪个方法」。
|
|
798
|
+
*/
|
|
799
|
+
const pluginInstall = usePluginWriteFlow({
|
|
800
|
+
overlayKind: 'plugin-install',
|
|
801
|
+
overlay,
|
|
802
|
+
dispatchOverlay,
|
|
803
|
+
pushLocal: lines => channel.pushLocal('/plugin', lines),
|
|
804
|
+
initialStep: { kind: 'done' },
|
|
805
|
+
// 装了半截就关浮层会把 profile 留在半装状态:取消由服务自己结算(回滚)。
|
|
806
|
+
cancelOnClose: flow => flow.cancel(),
|
|
807
|
+
failureLine: error => t('plugins-install-failed', { reason: cleanScalarText(error, COMMAND_RESULT_CELLS) }),
|
|
808
|
+
});
|
|
809
|
+
/** 开始一次安装;`false` 表示这段输入不是 install 形式(或本启动没有服务)。 */
|
|
810
|
+
const startPluginInstall = (rawArgs) => {
|
|
811
|
+
const flow = onPluginInstall?.(rawArgs, {
|
|
812
|
+
binding: () => channel.agentBindingGeneration,
|
|
813
|
+
// 回合运行中改 profile 会触发应用/HMR:门禁在流程里(inspect 之前与写入之前各查一次)。
|
|
814
|
+
busy: () => channel.working,
|
|
815
|
+
onLines: lines => channel.pushLocal('/plugin', lines),
|
|
816
|
+
});
|
|
817
|
+
if (flow === undefined)
|
|
818
|
+
return false;
|
|
819
|
+
pluginInstall.start(flow, flow.begin());
|
|
820
|
+
return true;
|
|
821
|
+
};
|
|
822
|
+
/**
|
|
823
|
+
* 取消在途安装。取消由服务自己结算(回滚 profile),浮层等它回答。
|
|
824
|
+
* 「还没开始装」(confirm 步)时不该走这里:服务那边没有可取消的请求,
|
|
825
|
+
* 只会打出一行「没有在跑的安装」——那条路径直接 `pluginInstall.close()`。
|
|
826
|
+
*/
|
|
827
|
+
const cancelPluginInstall = () => {
|
|
828
|
+
const view = pluginInstall.view;
|
|
829
|
+
if (view === undefined)
|
|
830
|
+
return;
|
|
831
|
+
pluginInstall.run(view.flow.cancel());
|
|
832
|
+
};
|
|
833
|
+
/**
|
|
834
|
+
* `/plugin remove|enable|disable <target>` 的步骤态(C-5):与装链路同一副骨架,
|
|
835
|
+
* 只有两条差异——没有 `cancelOnClose`(这三个动作服务不给取消面,写也是一次就
|
|
836
|
+
* 结算的 profile 操作,关掉浮层它照旧跑完并把结果写进转录),以及 Enter 只有
|
|
837
|
+
* 「确认」一种答案。
|
|
838
|
+
*/
|
|
839
|
+
const pluginManage = usePluginWriteFlow({
|
|
840
|
+
overlayKind: 'plugin-manage',
|
|
841
|
+
overlay,
|
|
842
|
+
dispatchOverlay,
|
|
843
|
+
pushLocal: lines => channel.pushLocal('/plugin', lines),
|
|
844
|
+
initialStep: { kind: 'done' },
|
|
845
|
+
failureLine: error => t('plugins-manage-failed', { reason: cleanScalarText(error, COMMAND_RESULT_CELLS) }),
|
|
846
|
+
});
|
|
847
|
+
/** 绑定会话的 teammate 数、其中运行中/准备中的数与可能在运行的数(关闭团队前的确认用)。 */
|
|
848
|
+
const teamMembers = () => {
|
|
849
|
+
const team = channel.team;
|
|
850
|
+
return team === undefined ? { total: 0, active: 0, unseen: 0 } : teamMemberCounts(team, [...channel.subagents], channel.sessionId);
|
|
851
|
+
};
|
|
852
|
+
/** 开始一次生命周期动作;`false` 表示这段输入不是那三种形式(或本启动没有服务)。 */
|
|
853
|
+
const startPluginManage = (rawArgs) => {
|
|
854
|
+
const flow = onPluginManage?.(rawArgs, {
|
|
855
|
+
binding: () => channel.agentBindingGeneration,
|
|
856
|
+
// 回合运行中改 profile 会触发应用/HMR:门禁在流程里(解析之前与写入之前各查一次)。
|
|
857
|
+
busy: () => channel.working,
|
|
858
|
+
onLines: lines => channel.pushLocal('/plugin', lines),
|
|
859
|
+
teamActiveMembers: teamMembers,
|
|
860
|
+
});
|
|
861
|
+
if (flow === undefined)
|
|
862
|
+
return false;
|
|
863
|
+
pluginManage.start(flow, flow.begin());
|
|
864
|
+
return true;
|
|
865
|
+
};
|
|
654
866
|
const host = channel.backendChannels?.();
|
|
655
867
|
const { rows: channelRows, open: openChannelPicker, pick: pickChannel, setMode: runBackendModeCommand, login: runBackendLogin } = useBackendChannels({
|
|
656
868
|
channel, host, questionStore, dispatchOverlay, onRestartFreshSession, runOAuthLogin,
|
|
@@ -665,7 +877,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
665
877
|
* The first-run guide. Renders above the launchpad (see the prop docs): a
|
|
666
878
|
* launch that needs setup has not answered the launchpad's question yet.
|
|
667
879
|
*/
|
|
668
|
-
const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
|
|
880
|
+
const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot && channel.ready !== false);
|
|
669
881
|
/**
|
|
670
882
|
* 落地页那条"第一次用?跑一遍引导"的横幅认的是**还欠一次引导**,而不是启动快照:
|
|
671
883
|
* 完成(写进 onboarding.json)之后立刻收掉;跳过刻意保留——没记账,下次启动还会问,
|
|
@@ -724,6 +936,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
724
936
|
* browser, a screen rather than a panel: it owns its own focus, staged
|
|
725
937
|
* drafts and keyboard; Chat only opens it. */
|
|
726
938
|
const [settingsOpen, setSettingsOpen] = React.useState(false);
|
|
939
|
+
// The held boot screens open once the session is adopted, unless the user
|
|
940
|
+
// went to another screen; a failed startup never opens them.
|
|
941
|
+
const channelReady = channel.ready;
|
|
942
|
+
const channelStartupFailed = channel.startupFailure !== undefined;
|
|
943
|
+
React.useEffect(() => {
|
|
944
|
+
const held = heldBootScreensRef.current;
|
|
945
|
+
if (held === undefined)
|
|
946
|
+
return;
|
|
947
|
+
// A later `/new` that adopts a session must not open them over the chat.
|
|
948
|
+
if (channelStartupFailed) {
|
|
949
|
+
heldBootScreensRef.current = undefined;
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (channelReady === false)
|
|
953
|
+
return;
|
|
954
|
+
heldBootScreensRef.current = undefined;
|
|
955
|
+
if (settingsOpen || treeOpen)
|
|
956
|
+
return;
|
|
957
|
+
if (held.onboarding)
|
|
958
|
+
setOnboardingOpen(true);
|
|
959
|
+
if (held.home)
|
|
960
|
+
setSupervisorOpen(true);
|
|
961
|
+
}, [channelReady, channelStartupFailed, settingsOpen, treeOpen]);
|
|
727
962
|
/** 99h / 999 次的"求 star"开屏弹窗(`usageStats` 记账,一档只弹一次):
|
|
728
963
|
* 只在启动时判定一次——回合进行中、或已有整屏界面在开(如开机首页),
|
|
729
964
|
* 这一轮不弹也**不记账**,留给下一次启动。`starPrompt` 是测试缝:传
|
|
@@ -760,7 +995,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
760
995
|
// 让开屏先画半秒:弹窗压在介绍动画之上,而不是同抢第一帧。
|
|
761
996
|
const timer = setTimeout(() => {
|
|
762
997
|
// 到点时回合已经开始的仍不弹(channel 是活对象,读到的是当前值)。
|
|
763
|
-
|
|
998
|
+
// /restart、/kernel 的旧进程不卸这棵树,channel 生命周期结束后读它会抛:读不到就不弹。
|
|
999
|
+
let working;
|
|
1000
|
+
try {
|
|
1001
|
+
working = channel.working;
|
|
1002
|
+
}
|
|
1003
|
+
catch {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
if (working)
|
|
764
1007
|
return;
|
|
765
1008
|
if (starModalPreview) {
|
|
766
1009
|
const preview = STAR_MILESTONES.findIndex(milestone => milestone.hours === 99);
|
|
@@ -890,8 +1133,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
890
1133
|
* (Standard/PTC/极简…),名册是异步的——落地页出来时顺手预热一次
|
|
891
1134
|
* (空名册不写;失败静默,段缺省不画)。/preset 自己的加载路径不动。
|
|
892
1135
|
*/
|
|
1136
|
+
// No roster to ask on a placeholder still starting, nor on a kernel without
|
|
1137
|
+
// /preset (the refusal would land as a "not supported" notice).
|
|
1138
|
+
const presetsReady = channel.ready !== false;
|
|
1139
|
+
const presetsServed = !isUnavailableLocalCommand('preset', channel.backendCapabilities);
|
|
893
1140
|
React.useEffect(() => {
|
|
894
|
-
if (!launchpadShown || presetOptions.length > 0)
|
|
1141
|
+
if (!launchpadShown || presetOptions.length > 0 || !presetsReady || !presetsServed)
|
|
895
1142
|
return;
|
|
896
1143
|
let cancelled = false;
|
|
897
1144
|
channel.listPresets()
|
|
@@ -899,7 +1146,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
899
1146
|
setPresetOptions(list); })
|
|
900
1147
|
.catch(() => { });
|
|
901
1148
|
return () => { cancelled = true; };
|
|
902
|
-
}, [launchpadShown, presetOptions.length, channel]);
|
|
1149
|
+
}, [launchpadShown, presetOptions.length, channel, presetsReady, presetsServed]);
|
|
903
1150
|
/** `/effort` adapter levels: load async before the slider opens. */
|
|
904
1151
|
const [effortOptions, setEffortOptions] = React.useState([]);
|
|
905
1152
|
/** True when those levels are the CLI-standard compatibility ladder (the
|
|
@@ -1036,8 +1283,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1036
1283
|
}, [autoRecapSessionId]);
|
|
1037
1284
|
// The user starts a new message → the auto recap has served its purpose
|
|
1038
1285
|
// (catching them up) and bows out. A newer user row is the signal; the
|
|
1039
|
-
// assistant's own streamed rows don't count.
|
|
1040
|
-
const lastUserRowId = channel.rows.filter(row => row.kind === 'user').at(-1)?.id ?? -1;
|
|
1286
|
+
// assistant's own streamed rows (and a teammate's message) don't count.
|
|
1287
|
+
const lastUserRowId = channel.rows.filter(row => row.kind === 'user' && row.label !== 'team-message').at(-1)?.id ?? -1;
|
|
1041
1288
|
React.useEffect(() => {
|
|
1042
1289
|
if (recap !== null &&
|
|
1043
1290
|
recap.auto &&
|
|
@@ -1240,7 +1487,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1240
1487
|
}, [launchpadCoverScreenUp]);
|
|
1241
1488
|
/**
|
|
1242
1489
|
* 从落地页出发的交互要开整屏前先授权(配合 `launchpadGate`):调用点只在
|
|
1243
|
-
* 落地页自己的回调里(onAction / onCommandPick / onEscape
|
|
1490
|
+
* 落地页自己的回调里(onAction / onSubmit / onCommandPick / onEscape)。
|
|
1244
1491
|
* 异步误置真的整屏状态没有这道授权 → 闸门挡下,落地页留在最上层。
|
|
1245
1492
|
*/
|
|
1246
1493
|
const authorizeLaunchpadCover = () => { launchpadCoverRef.current = true; };
|
|
@@ -1667,8 +1914,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1667
1914
|
};
|
|
1668
1915
|
}, []);
|
|
1669
1916
|
const draftSessionId = channel.agentId;
|
|
1670
|
-
|
|
1671
|
-
|
|
1917
|
+
const draftBindingGeneration = resolveBindingGeneration(channel);
|
|
1918
|
+
/** Last reconciled binding; its image epoch distinguishes adoption from replacement. */
|
|
1919
|
+
const draftSessionRef = React.useRef({ id: draftSessionId, generation: draftBindingGeneration, imageGeneration: composerImageGeneration });
|
|
1672
1920
|
/**
|
|
1673
1921
|
* The session a fill Chat itself requested belongs to, if one is in flight.
|
|
1674
1922
|
*
|
|
@@ -1694,9 +1942,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1694
1942
|
* answered by the snapshot's owner fields.
|
|
1695
1943
|
*/
|
|
1696
1944
|
React.useLayoutEffect(() => {
|
|
1697
|
-
|
|
1945
|
+
const previous = draftSessionRef.current;
|
|
1946
|
+
draftSessionRef.current = { id: draftSessionId, generation: draftBindingGeneration, imageGeneration: composerImageGeneration };
|
|
1947
|
+
if (previous.id === draftSessionId)
|
|
1698
1948
|
return;
|
|
1699
|
-
|
|
1949
|
+
if (previous.id === '' && previous.imageGeneration === composerImageGeneration) {
|
|
1950
|
+
// Startup adoption gives the existing draft its first conversation.
|
|
1951
|
+
// A covered composer has parked that draft in the owner slot instead.
|
|
1952
|
+
const snapshot = promptDraftRef.current.current;
|
|
1953
|
+
if (snapshot?.ownerAgentId === '' && snapshot.bindingGeneration === previous.generation) {
|
|
1954
|
+
promptDraftRef.current.current = {
|
|
1955
|
+
...snapshot,
|
|
1956
|
+
ownerAgentId: String(draftSessionId),
|
|
1957
|
+
bindingGeneration: draftBindingGeneration,
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1700
1962
|
// A stored draft can only belong to the conversation being replaced: the
|
|
1701
1963
|
// composer is the one that writes it, and it writes it on the way out.
|
|
1702
1964
|
promptDraftRef.current.current = null;
|
|
@@ -1705,7 +1967,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1705
1967
|
return;
|
|
1706
1968
|
}
|
|
1707
1969
|
promptControllerRef.current?.clear();
|
|
1708
|
-
}, [draftSessionId]);
|
|
1970
|
+
}, [draftSessionId, draftBindingGeneration]);
|
|
1709
1971
|
const previewGallery = activePreview === null ? [] : activePreview.peek
|
|
1710
1972
|
? promptControllerRef.current?.previewImages?.() ?? [activePreview]
|
|
1711
1973
|
: overlay.kind === 'image-preview' ? overlay.gallery ?? [activePreview] : [];
|
|
@@ -1744,7 +2006,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1744
2006
|
if (!controller)
|
|
1745
2007
|
return;
|
|
1746
2008
|
const text = controller.append('').trim();
|
|
1747
|
-
if (text === '')
|
|
2009
|
+
if (text === '' || refusedAtStartup(undefined))
|
|
1748
2010
|
return;
|
|
1749
2011
|
channel.submit(text);
|
|
1750
2012
|
controller.clear();
|
|
@@ -1798,7 +2060,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1798
2060
|
// Mouse text selection auto-copy: active only in
|
|
1799
2061
|
// fullscreen (<AlternateScreen> supplies mouse tracking); a no-op
|
|
1800
2062
|
// subscription in inline mode, where selection belongs to the terminal.
|
|
1801
|
-
// The copy
|
|
2063
|
+
// The copy retains the highlight and posts a transient notification.
|
|
1802
2064
|
// Smart migration hint (product ask): ~12s after mount, one background
|
|
1803
2065
|
// pass over the foreign-agent stores; when a source was active inside the
|
|
1804
2066
|
// 20-minute window, surface the user's own wording once per session. The
|
|
@@ -1806,14 +2068,20 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1806
2068
|
// off the render path; failures read as "no data" and stay silent.
|
|
1807
2069
|
const migrateHintShownRef = React.useRef(false);
|
|
1808
2070
|
React.useEffect(() => {
|
|
2071
|
+
// A replaced Channel must not retain the old hint's Enter shortcut.
|
|
2072
|
+
setMigrateHintAgent(null);
|
|
1809
2073
|
if (migrateHintShownRef.current)
|
|
1810
2074
|
return;
|
|
2075
|
+
let disposed = false;
|
|
2076
|
+
let hintTimer;
|
|
1811
2077
|
const timer = setTimeout(() => {
|
|
1812
2078
|
migrateHintShownRef.current = true;
|
|
1813
2079
|
void (async () => {
|
|
1814
2080
|
const newest = await new Promise(resolve => {
|
|
1815
2081
|
setImmediate(() => resolve(collectActivitySamples(MIGRATION_ADAPTERS, adapter => MIGRATE_SCAN_SPECS[adapter.id])));
|
|
1816
2082
|
});
|
|
2083
|
+
if (disposed)
|
|
2084
|
+
return;
|
|
1817
2085
|
const top = recentAgentsFrom(newest, Date.now())[0];
|
|
1818
2086
|
if (top !== undefined) {
|
|
1819
2087
|
channel.notify(t('migrate-hint-notify', { agent: top.label }), { timeoutMs: 10000 });
|
|
@@ -1821,18 +2089,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1821
2089
|
// overlay) jumps into the picker with this source pre-checked;
|
|
1822
2090
|
// the global key layer below consumes it, anything else disarms.
|
|
1823
2091
|
setMigrateHintAgent(top.agentId);
|
|
1824
|
-
setTimeout(() => setMigrateHintAgent(current => current === top.agentId ? null : current), 10_000);
|
|
2092
|
+
hintTimer = setTimeout(() => setMigrateHintAgent(current => current === top.agentId ? null : current), 10_000);
|
|
1825
2093
|
}
|
|
1826
2094
|
})();
|
|
1827
2095
|
}, 12_000);
|
|
1828
|
-
return () =>
|
|
2096
|
+
return () => {
|
|
2097
|
+
disposed = true;
|
|
2098
|
+
clearTimeout(timer);
|
|
2099
|
+
if (hintTimer !== undefined)
|
|
2100
|
+
clearTimeout(hintTimer);
|
|
2101
|
+
};
|
|
1829
2102
|
}, [channel]);
|
|
1830
2103
|
useCopyOnSelect(text => channel.notify(t('copied-chars', { n: text.length }), { timeoutMs: 1500 }),
|
|
1831
2104
|
// Stale-selection refusal: the highlighted rows were replaced in place
|
|
1832
2105
|
// (streaming overwrite), so nothing was copied — say why instead of
|
|
1833
2106
|
// letting the highlight vanish silently.
|
|
1834
2107
|
() => channel.notify(t('copy-refused-stale'), { timeoutMs: 2500 }));
|
|
1835
|
-
const { clearSelection: clearMouseSelection, hasSelection: hasMouseSelection } = useSelection();
|
|
2108
|
+
const { clearSelection: clearMouseSelection, hasSelection: hasMouseSelection, getState: getMouseSelectionState, } = useSelection();
|
|
1836
2109
|
React.useEffect(() => {
|
|
1837
2110
|
if (!channel.working || !terminalFocused)
|
|
1838
2111
|
return;
|
|
@@ -1963,8 +2236,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1963
2236
|
* plugin (plan/goal/…) dispatches through the command registry, whose
|
|
1964
2237
|
* result text lands as a notification. `rawInput` carries the text after
|
|
1965
2238
|
* the command name (`/plan off` → ` off`).
|
|
2239
|
+
*
|
|
2240
|
+
* `render.block` prints a multi-line report the way `/plugins` prints one:
|
|
2241
|
+
* a `local` echo row plus one wrapped `local-output` row per line, in the
|
|
2242
|
+
* transcript (native scrollback in inline mode). A single truncated toast
|
|
2243
|
+
* row cannot carry a full goal objective, so the bare `/goal` status query
|
|
2244
|
+
* asks for the block; errors always notify — they want the color and the
|
|
2245
|
+
* transient read.
|
|
1966
2246
|
*/
|
|
1967
|
-
const runExternalCommand = (name, rawInput, images = []) => {
|
|
2247
|
+
const runExternalCommand = (name, rawInput, images = [], render) => {
|
|
1968
2248
|
const originAgentBinding = channel.agentBindingGeneration;
|
|
1969
2249
|
return channel.runExternalCommandOutcome(name, rawInput, images).then((outcome) => {
|
|
1970
2250
|
if (channel.agentBindingGeneration !== originAgentBinding)
|
|
@@ -1973,9 +2253,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1973
2253
|
channel.notify(t('command-not-found', { name }), { color: 'error' });
|
|
1974
2254
|
return false;
|
|
1975
2255
|
}
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2256
|
+
if (render?.block === true && outcome.kind !== 'error') {
|
|
2257
|
+
// Per-line sanitize: the newlines here are the report's structure.
|
|
2258
|
+
const lines = cleanBlockLines(outcome.text, LOCAL_BLOCK_CELLS);
|
|
2259
|
+
if (lines.length > 0)
|
|
2260
|
+
channel.pushLocal(`/${name}`, lines, { lineLimit: LOCAL_BLOCK_CELLS });
|
|
2261
|
+
}
|
|
2262
|
+
else {
|
|
2263
|
+
const cleaned = cleanRenderText(outcome.text, COMMAND_RESULT_CELLS);
|
|
2264
|
+
if (cleaned !== '') {
|
|
2265
|
+
channel.notify(cleaned, outcome.kind === 'error' ? { color: 'error' } : undefined);
|
|
2266
|
+
}
|
|
1979
2267
|
}
|
|
1980
2268
|
return outcome.consumeDraft;
|
|
1981
2269
|
}).catch((error) => {
|
|
@@ -2123,18 +2411,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2123
2411
|
: t('migrate-failed', { n: failures }), failures === 0 ? { timeoutMs: 6000 } : { color: 'error', timeoutMs: 10000 });
|
|
2124
2412
|
})();
|
|
2125
2413
|
};
|
|
2414
|
+
/** Not-ready refusal (`ChannelUi.ready`) for paths that bypass the composer:
|
|
2415
|
+
* true, after a notice, when `name` (undefined: plain text) must wait. */
|
|
2416
|
+
const refusedAtStartup = (name) => {
|
|
2417
|
+
if (channel.ready !== false || (name !== undefined && isBootSafeCommand(name)))
|
|
2418
|
+
return false;
|
|
2419
|
+
channel.notify(t('startup-not-ready', { backend: kernelCurrentOption?.shortLabel ?? channel.backendCapabilities.backendId }), { color: 'warning', timeoutMs: 2500 });
|
|
2420
|
+
return true;
|
|
2421
|
+
};
|
|
2126
2422
|
/**
|
|
2127
|
-
*
|
|
2423
|
+
* Submit launchpad input or a selected command through the chat routes.
|
|
2128
2424
|
*
|
|
2129
2425
|
* THREE cases, and they are genuinely different:
|
|
2130
2426
|
*
|
|
2131
2427
|
* - a slash command → `runCommand`, the same dispatch a typed command
|
|
2132
|
-
* takes in the composer.
|
|
2428
|
+
* takes in the composer. Completion-only filesystem skills keep
|
|
2429
|
+
* the composer's model route.
|
|
2133
2430
|
* Recognition is the composer's OWN rule (第六版 BUG 1 修复): the merged
|
|
2134
2431
|
* command list (locals + plugin/registry commands via channel.commandList)
|
|
2135
2432
|
* decides whether the line is a command — isLocalCommandName alone missed
|
|
2136
2433
|
* registry-only names (e.g. /plan, /goal), which then fell through to
|
|
2137
2434
|
* channel.submit and went to the model as a user message.
|
|
2435
|
+
* Picker and full-screen commands keep the launchpad mounted underneath;
|
|
2436
|
+
* the consumed command is cleared before either surface opens.
|
|
2138
2437
|
* - ordinary text → SENT DIRECTLY (fifth revision, user-reported bug:
|
|
2139
2438
|
* "按了回车就直接进入流式输出"). The line rides the composer's own
|
|
2140
2439
|
* submit path (`channel.submit`, which queues through the DSH inbox
|
|
@@ -2145,9 +2444,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2145
2444
|
* History is appended for the two non-empty cases (matching what PromptInput
|
|
2146
2445
|
* does on submit) so the launchpad's first line is reachable with ↑ later.
|
|
2147
2446
|
*/
|
|
2148
|
-
const
|
|
2447
|
+
const submitLaunchpad = (submit) => {
|
|
2149
2448
|
const text = submit.trim();
|
|
2150
|
-
|
|
2449
|
+
const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
|
|
2450
|
+
// Refused BEFORE the page closes, so the draft stays on it.
|
|
2451
|
+
if (text !== '' && refusedAtStartup(parsed?.name))
|
|
2452
|
+
return;
|
|
2453
|
+
const images = composerImageRefsForText(text, launchpadImagesRef.current);
|
|
2454
|
+
const command = parsed === undefined ? undefined : channel.commandList.find(entry => entry.name === parsed.name);
|
|
2455
|
+
const knownCommand = parsed !== undefined && (isLocalCommandName(parsed.name) || isHiddenCommandName(parsed.name) || command !== undefined);
|
|
2456
|
+
const modelRoutedSkill = command?.skill === true && command.external !== true;
|
|
2457
|
+
// Match the composer's image admission before consuming the draft.
|
|
2458
|
+
if (knownCommand && images.length > 0 && !modelRoutedSkill && command?.acceptsImages !== true) {
|
|
2459
|
+
return t('command-images-unsupported', { name: parsed.name });
|
|
2460
|
+
}
|
|
2461
|
+
const submitted = new Set(images.map(image => image.stageId));
|
|
2462
|
+
for (const stageId of launchpadImagesRef.current.values()) {
|
|
2463
|
+
if (!submitted.has(stageId))
|
|
2464
|
+
channel.discardStagedImage(stageId);
|
|
2465
|
+
}
|
|
2466
|
+
launchpadImagesRef.current.clear();
|
|
2151
2467
|
// 首启时 openHomeOnBoot 与落地页同时为真:会话浏览器已经开着、只是被落地页盖住。
|
|
2152
2468
|
// 提交首句后必须把它收掉,否则用户落到浏览器而不是"草稿就在眼前的对话",
|
|
2153
2469
|
// 与本函数 doc 承诺的落点直接矛盾。
|
|
@@ -2155,10 +2471,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2155
2471
|
setLaunchpadFocus(-1);
|
|
2156
2472
|
setLaunchpadDraft('');
|
|
2157
2473
|
setLaunchpadCaret(0);
|
|
2158
|
-
if (text === '')
|
|
2474
|
+
if (text === '') {
|
|
2475
|
+
setLaunchpadOpen(false);
|
|
2159
2476
|
return;
|
|
2477
|
+
}
|
|
2160
2478
|
void appendHistory(text);
|
|
2161
|
-
const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
|
|
2162
2479
|
// 第八版:/help 在落地页上也是盖屏浮层(补全面板被 Esc 收掉后直接
|
|
2163
2480
|
// Enter 的那条路)——不收落地页、不进对话页。聊天页里 /help 的行为
|
|
2164
2481
|
// 不变(那边不走这个回调)。
|
|
@@ -2168,18 +2485,51 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2168
2485
|
}
|
|
2169
2486
|
// 与 composer 的 tryRunCommand 同一条判定:合并命令表(LOCAL_COMMANDS +
|
|
2170
2487
|
// channel.commandList 的插件/registry 命令)里有名字才是命令;hidden
|
|
2171
|
-
//
|
|
2172
|
-
if (parsed !== undefined &&
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2488
|
+
// 命令照旧认。模型路由技能与判定之外的 / 开头行走 submit,与聊天页一致。
|
|
2489
|
+
if (parsed !== undefined && knownCommand && !modelRoutedSkill) {
|
|
2490
|
+
if (launchpadScreenCommands.has(parsed.name)) {
|
|
2491
|
+
authorizeLaunchpadCover();
|
|
2492
|
+
}
|
|
2493
|
+
else if (!overlayCommandNames.has(parsed.name)) {
|
|
2494
|
+
setLaunchpadOpen(false);
|
|
2495
|
+
}
|
|
2496
|
+
void runCommand(parsed.name, parsed.rawInput, images);
|
|
2176
2497
|
return;
|
|
2177
2498
|
}
|
|
2178
2499
|
// 直接发送:与 composer 回车同一条提交路径。发出去之后输入框是空的
|
|
2179
2500
|
// (内容已作为首轮发出,绝不"既发了又留在框里"),也没有交接提示——
|
|
2180
2501
|
// 没有草稿要交,一句"已放进输入框"的 toast 反而是假的。
|
|
2181
|
-
|
|
2182
|
-
|
|
2502
|
+
setLaunchpadOpen(false);
|
|
2503
|
+
channel.submit(text, images);
|
|
2504
|
+
};
|
|
2505
|
+
/**
|
|
2506
|
+
* A failed startup open closes the landing page, uncovering the failure row
|
|
2507
|
+
* and its `/new` hint; the draft moves to the composer once it mounts.
|
|
2508
|
+
*/
|
|
2509
|
+
const launchpadDraftHandoffRef = React.useRef(undefined);
|
|
2510
|
+
const startupFailure = channel.startupFailure;
|
|
2511
|
+
React.useEffect(() => {
|
|
2512
|
+
if (!launchpadOpen || startupFailure === undefined)
|
|
2513
|
+
return;
|
|
2514
|
+
launchpadDraftHandoffRef.current = launchpadDraft;
|
|
2515
|
+
setLaunchpadOpen(false);
|
|
2516
|
+
setSupervisorOpen(false);
|
|
2517
|
+
setLaunchpadFocus(-1);
|
|
2518
|
+
setLaunchpadDraft('');
|
|
2519
|
+
setLaunchpadCaret(0);
|
|
2520
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the draft is read at the moment of the failure, not tracked
|
|
2521
|
+
}, [launchpadOpen, startupFailure]);
|
|
2522
|
+
React.useEffect(() => {
|
|
2523
|
+
const draft = launchpadDraftHandoffRef.current;
|
|
2524
|
+
if (launchpadOpen || draft === undefined)
|
|
2525
|
+
return;
|
|
2526
|
+
const controller = promptControllerRef.current;
|
|
2527
|
+
if (controller === null)
|
|
2528
|
+
return;
|
|
2529
|
+
launchpadDraftHandoffRef.current = undefined;
|
|
2530
|
+
if (draft.trim() !== '')
|
|
2531
|
+
controller.append(draft);
|
|
2532
|
+
});
|
|
2183
2533
|
/**
|
|
2184
2534
|
* The screen's command dispatcher. Every entry point reaches this one
|
|
2185
2535
|
* closure — PromptInput's `onRunCommand`, the completion menu, this screen's
|
|
@@ -2187,6 +2537,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2187
2537
|
* second dispatcher for the landing page.
|
|
2188
2538
|
*/
|
|
2189
2539
|
const runCommand = (name, rawInput = '', images = []) => {
|
|
2540
|
+
if (refusedAtStartup(name))
|
|
2541
|
+
return true;
|
|
2190
2542
|
switch (name) {
|
|
2191
2543
|
case 'activity': {
|
|
2192
2544
|
// Ported from the pi working-activity extension: bare `/activity`
|
|
@@ -2507,8 +2859,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2507
2859
|
setHelpOpen(true);
|
|
2508
2860
|
return true;
|
|
2509
2861
|
case 'model': {
|
|
2510
|
-
// `/model <provider/model>` switches directly (same
|
|
2511
|
-
// as the picker's Enter), bare `/model` opens the picker.
|
|
2862
|
+
// `/model <provider/model>` switches directly (same in-session route
|
|
2863
|
+
// switch as the picker's Enter), bare `/model` opens the picker.
|
|
2512
2864
|
const parts = rawInput.trim().split(/\s+/).filter(Boolean);
|
|
2513
2865
|
if (parts.length > 0) {
|
|
2514
2866
|
setHelpOpen(false);
|
|
@@ -2533,37 +2885,37 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2533
2885
|
return true;
|
|
2534
2886
|
}
|
|
2535
2887
|
setHelpOpen(false);
|
|
2536
|
-
//
|
|
2537
|
-
//
|
|
2538
|
-
//
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
let recentsNow = modelRecents;
|
|
2544
|
-
if (channel.provider !== '' && channel.model !== ''
|
|
2545
|
-
&& !recentsNow.some(ref => ref.provider === channel.provider && ref.id === channel.model)) {
|
|
2546
|
-
recentsNow = recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend);
|
|
2547
|
-
setModelRecents(recentsNow);
|
|
2548
|
-
}
|
|
2549
|
-
// Two-level landing: recents (when catalogued) focus their pinned
|
|
2550
|
-
// row; else multi-provider catalogs focus the current provider's
|
|
2551
|
-
// group row; a single-provider catalog without a meaningful recents
|
|
2552
|
-
// list drills straight into its model list (pre-grouping UX).
|
|
2553
|
-
{
|
|
2554
|
-
const landing = modelPickerLanding(models, channel.provider, channel.model, recentsNow);
|
|
2555
|
-
setModelGroup(landing.group);
|
|
2556
|
-
setModelPickerDirect(landing.group !== undefined);
|
|
2557
|
-
dispatchOverlay({ type: 'open', overlay: { kind: 'model', index: landing.index } });
|
|
2888
|
+
// Opening counts the live route as the latest use, including when
|
|
2889
|
+
// restoring a session whose model already exists later in recents.
|
|
2890
|
+
// Refresh the catalog without overriding navigation made meanwhile.
|
|
2891
|
+
const latestRecent = modelRecents[0];
|
|
2892
|
+
if (modelProviderTabs && channel.provider !== '' && channel.model !== ''
|
|
2893
|
+
&& (latestRecent?.provider !== channel.provider || latestRecent?.id !== channel.model)) {
|
|
2894
|
+
setModelRecents(recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend));
|
|
2558
2895
|
}
|
|
2896
|
+
modelPicker.reset();
|
|
2897
|
+
dispatchOverlay({ type: 'open', overlay: { kind: 'model' } });
|
|
2898
|
+
setModelsLoading(true);
|
|
2899
|
+
const generation = ++modelCatalogGeneration.current;
|
|
2559
2900
|
void channel.listModels().then((list) => {
|
|
2901
|
+
if (generation !== modelCatalogGeneration.current)
|
|
2902
|
+
return;
|
|
2560
2903
|
setModels(list);
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2904
|
+
setModelsLoading(false);
|
|
2905
|
+
}).catch(() => {
|
|
2906
|
+
if (generation !== modelCatalogGeneration.current)
|
|
2907
|
+
return;
|
|
2908
|
+
setModelsLoading(false);
|
|
2909
|
+
channel.notify(t('model-load-failed'), { color: 'error' });
|
|
2565
2910
|
});
|
|
2566
|
-
|
|
2911
|
+
if (modelProviderTabs)
|
|
2912
|
+
void channel.listProviders().then(list => {
|
|
2913
|
+
if (generation === modelCatalogGeneration.current)
|
|
2914
|
+
setProviderInfos(list);
|
|
2915
|
+
}).catch(() => {
|
|
2916
|
+
if (generation === modelCatalogGeneration.current)
|
|
2917
|
+
setProviderInfos([]);
|
|
2918
|
+
});
|
|
2567
2919
|
return true;
|
|
2568
2920
|
}
|
|
2569
2921
|
case 'skills': {
|
|
@@ -3032,13 +3384,66 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3032
3384
|
void collectMigrateRows().then(setMigrateRows);
|
|
3033
3385
|
return true;
|
|
3034
3386
|
}
|
|
3035
|
-
case '
|
|
3387
|
+
case 'plugin': {
|
|
3036
3388
|
// Plugin diagnostics (C-070): trust banner first, then descriptor /
|
|
3037
3389
|
// grant matrix / ledger tail — or validate+negotiate for
|
|
3038
|
-
// `/
|
|
3390
|
+
// `/plugin check <path>` (rawInput carries the subcommand).
|
|
3391
|
+
setHelpOpen(false);
|
|
3392
|
+
// `/plugin install <spec>` is the one form that needs a flow of its own
|
|
3393
|
+
// (C-4). Anything else — and any launch whose entry has no service to
|
|
3394
|
+
// install through — falls through to the read-only report below.
|
|
3395
|
+
// The three lifecycle forms (C-5) and the install form each need a flow
|
|
3396
|
+
// of their own. They are mutually exclusive by their subcommand, so
|
|
3397
|
+
// trying one and then the other cannot take the wrong path; anything
|
|
3398
|
+
// else — and any launch whose entry has no service — falls through to
|
|
3399
|
+
// the read-only report below.
|
|
3400
|
+
if (startPluginManage(rawInput))
|
|
3401
|
+
return true;
|
|
3402
|
+
if (startPluginInstall(rawInput))
|
|
3403
|
+
return true;
|
|
3404
|
+
// The bundle/row half comes from the host plugin service, so the
|
|
3405
|
+
// report is async (the `/agents` case reads the same way). `pushLocal`
|
|
3406
|
+
// writes the CURRENTLY bound session, and a resume or `/new` can land
|
|
3407
|
+
// while the service is still answering: fence the report to the
|
|
3408
|
+
// binding that asked for it, or it appears in the new transcript.
|
|
3409
|
+
const originAgentBinding = channel.agentBindingGeneration;
|
|
3410
|
+
void channel.pluginsInfo(rawInput).then((lines) => {
|
|
3411
|
+
if (channel.agentBindingGeneration !== originAgentBinding)
|
|
3412
|
+
return;
|
|
3413
|
+
channel.pushLocal('/plugin', lines);
|
|
3414
|
+
});
|
|
3415
|
+
return true;
|
|
3416
|
+
}
|
|
3417
|
+
case 'team': {
|
|
3418
|
+
// `/team` 是团队 bundle 的启停(team-mode.ts):on/off 走与 /plugin 同一个
|
|
3419
|
+
// 生命周期流程与确认浮层,status 是一段报告;都按发起时的绑定落行。
|
|
3039
3420
|
setHelpOpen(false);
|
|
3040
|
-
|
|
3421
|
+
if (onTeamCommand === undefined) {
|
|
3422
|
+
channel.pushLocal('/team', [t('team-cmd-unavailable')]);
|
|
3423
|
+
return true;
|
|
3424
|
+
}
|
|
3425
|
+
const originAgentBinding = channel.agentBindingGeneration;
|
|
3426
|
+
const outcome = onTeamCommand(rawInput, {
|
|
3427
|
+
binding: () => channel.agentBindingGeneration,
|
|
3428
|
+
busy: () => channel.working,
|
|
3429
|
+
onLines: lines => channel.pushLocal('/team', lines),
|
|
3430
|
+
members: teamMembers,
|
|
3431
|
+
});
|
|
3432
|
+
if (outcome.kind === 'flow') {
|
|
3433
|
+
pluginManage.start(outcome.flow, outcome.flow.begin());
|
|
3434
|
+
return true;
|
|
3435
|
+
}
|
|
3436
|
+
void outcome.lines.then((lines) => {
|
|
3437
|
+
if (channel.agentBindingGeneration !== originAgentBinding)
|
|
3438
|
+
return;
|
|
3439
|
+
channel.pushLocal('/team', [...lines]);
|
|
3440
|
+
}, (error) => {
|
|
3441
|
+
if (channel.agentBindingGeneration !== originAgentBinding)
|
|
3442
|
+
return;
|
|
3443
|
+
channel.pushLocal('/team', [t('plugins-manage-failed', { reason: cleanCommandError(error) })]);
|
|
3444
|
+
});
|
|
3041
3445
|
return true;
|
|
3446
|
+
}
|
|
3042
3447
|
case 'export': {
|
|
3043
3448
|
const target = channel.exportSession();
|
|
3044
3449
|
channel.notify(target === null
|
|
@@ -3107,12 +3512,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3107
3512
|
}
|
|
3108
3513
|
return false;
|
|
3109
3514
|
}
|
|
3110
|
-
case 'agents':
|
|
3515
|
+
case 'agents': {
|
|
3111
3516
|
setHelpOpen(false);
|
|
3517
|
+
// The roster comes from the host subagents service, so the report is
|
|
3518
|
+
// async. Two fences, each for a window of its own: the generation guard
|
|
3519
|
+
// drops an answer that raced a session switch (`pushLocal` writes the
|
|
3520
|
+
// CURRENT binding), and the catch takes the rejection `listSubagents`
|
|
3521
|
+
// raises on purpose when the capture it read for has ended — an
|
|
3522
|
+
// unhandledRejection there is fatal to the process guard, and there is
|
|
3523
|
+
// nothing left to report to.
|
|
3524
|
+
const originAgentBinding = channel.agentBindingGeneration;
|
|
3112
3525
|
void channel.listSubagents().then((lines) => {
|
|
3526
|
+
if (channel.agentBindingGeneration !== originAgentBinding)
|
|
3527
|
+
return;
|
|
3113
3528
|
channel.pushLocal('/agents', lines);
|
|
3114
|
-
});
|
|
3529
|
+
}).catch(() => undefined);
|
|
3115
3530
|
return true;
|
|
3531
|
+
}
|
|
3116
3532
|
case 'login': {
|
|
3117
3533
|
setHelpOpen(false);
|
|
3118
3534
|
if (runBackendLogin())
|
|
@@ -3195,7 +3611,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3195
3611
|
}
|
|
3196
3612
|
const currentName = snapshot.availability === 'unavailable'
|
|
3197
3613
|
? t('permission-roster-unavailable')
|
|
3198
|
-
: snapshot
|
|
3614
|
+
: currentPermissionName(snapshot) ?? '—';
|
|
3199
3615
|
channel.pushLocal('/permission', [
|
|
3200
3616
|
t('permission-current', { name: currentName }),
|
|
3201
3617
|
t('permission-policy-hint'),
|
|
@@ -3250,15 +3666,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3250
3666
|
}
|
|
3251
3667
|
case 'plan': {
|
|
3252
3668
|
// Registered by dsh-plan-mode: bare `/plan` opens an on/off picker
|
|
3253
|
-
// marked with the current state instead of toggling blindly;
|
|
3254
|
-
//
|
|
3255
|
-
//
|
|
3256
|
-
//
|
|
3257
|
-
//
|
|
3258
|
-
//
|
|
3669
|
+
// marked with the current state instead of toggling blindly; the
|
|
3670
|
+
// picker's own rows dispatch the bare command and ` off`, never the
|
|
3671
|
+
// catalog token. The catalog's `on` child (the only producer of that
|
|
3672
|
+
// literal argument) is normalized back to the bare command:
|
|
3673
|
+
// upstream's grammar is `/plan [off|message]`, so a verbatim `on`
|
|
3674
|
+
// would enter plan mode AND steer the word "on" into the next step as
|
|
3675
|
+
// a user message. Every other argument — `/plan off` and
|
|
3676
|
+
// `/plan <message>` — passes through verbatim. Availability comes from
|
|
3677
|
+
// the shared capability facts (the same read Shift+Tab uses), not from
|
|
3678
|
+
// a second command-list scan; with no registry command the line falls
|
|
3679
|
+
// through to the model, exactly as before.
|
|
3259
3680
|
const plan = channel.capabilities().plan;
|
|
3260
3681
|
const mounted = plan.route !== 'none';
|
|
3261
3682
|
const parts = rawInput.trim().split(/\s+/).filter(Boolean);
|
|
3683
|
+
const argument = parts.length === 1 && parts[0] === 'on' ? '' : rawInput;
|
|
3262
3684
|
if (mounted && parts.length === 0) {
|
|
3263
3685
|
setHelpOpen(false);
|
|
3264
3686
|
dispatchOverlay({
|
|
@@ -3269,7 +3691,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3269
3691
|
}
|
|
3270
3692
|
if (mounted) {
|
|
3271
3693
|
setHelpOpen(false);
|
|
3272
|
-
return runExternalCommand('plan',
|
|
3694
|
+
return runExternalCommand('plan', argument, images);
|
|
3273
3695
|
}
|
|
3274
3696
|
return false;
|
|
3275
3697
|
}
|
|
@@ -3338,13 +3760,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3338
3760
|
currentLang: getLang(),
|
|
3339
3761
|
langOverriddenBySettings: tuiNamespace !== undefined && hasPath(tuiNamespace.user, ['lang']),
|
|
3340
3762
|
configuredLang: channel.configuredLang,
|
|
3341
|
-
|
|
3763
|
+
envPreset: presetOverrideFromEnv(),
|
|
3342
3764
|
presetPref: readPresetPref(),
|
|
3343
3765
|
currentPreset: channel.agentPreset,
|
|
3344
|
-
configuredModel: {
|
|
3345
|
-
provider: channel.configuredProvider,
|
|
3346
|
-
model: channel.configuredModel,
|
|
3347
|
-
},
|
|
3348
3766
|
modelPref: readModelPref(),
|
|
3349
3767
|
currentModel: { provider: channel.provider, model: channel.model },
|
|
3350
3768
|
configuredActivity: channel.configuredActivityFrames,
|
|
@@ -3398,7 +3816,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3398
3816
|
// default branch below would dispatch it.
|
|
3399
3817
|
if (channel.commandList.some(command => command.external && command.name === 'goal')) {
|
|
3400
3818
|
setHelpOpen(false);
|
|
3401
|
-
|
|
3819
|
+
// Bare `/goal` is DSH's status query. Print it as a transcript
|
|
3820
|
+
// block: inline mode sees no pointer events, so the hover tooltip
|
|
3821
|
+
// cannot carry the objective there, and the toast truncates it to
|
|
3822
|
+
// one row.
|
|
3823
|
+
return runExternalCommand(name, rawInput, images, { block: rawInput.trim() === '' });
|
|
3402
3824
|
}
|
|
3403
3825
|
// Another backend: the channel core's host over its typed `goals`
|
|
3404
3826
|
// capability. None (DSH without the row, or a backend's own `goal`
|
|
@@ -3416,7 +3838,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3416
3838
|
const command = parseGoalCommand(rawInput);
|
|
3417
3839
|
switch (command.kind) {
|
|
3418
3840
|
case 'status':
|
|
3419
|
-
channel.pushLocal('/goal', goalStatusLines(channel.goal));
|
|
3841
|
+
channel.pushLocal('/goal', goalStatusLines(channel.goal), { lineLimit: LOCAL_BLOCK_CELLS });
|
|
3420
3842
|
return true;
|
|
3421
3843
|
case 'invalid':
|
|
3422
3844
|
channel.notify(command.reason, { color: 'error' });
|
|
@@ -3442,7 +3864,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3442
3864
|
return true;
|
|
3443
3865
|
}
|
|
3444
3866
|
case 'kernel':
|
|
3445
|
-
//
|
|
3867
|
+
// 内核选择器,每个内核下都可用。
|
|
3446
3868
|
// 确认后由组合根的 onSwitchBackend 记住选择并以新内核重启。与 /help、
|
|
3447
3869
|
// 参数行一致:选择器已开着就收起,没开才打开。
|
|
3448
3870
|
setHelpOpen(false);
|
|
@@ -3451,6 +3873,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3451
3873
|
else
|
|
3452
3874
|
openKernelPicker();
|
|
3453
3875
|
return true;
|
|
3876
|
+
case 'dsh':
|
|
3877
|
+
case 'codex':
|
|
3878
|
+
case 'claude':
|
|
3879
|
+
setHelpOpen(false);
|
|
3880
|
+
return pickKernelById(name).then(() => true);
|
|
3454
3881
|
case 'restart':
|
|
3455
3882
|
// pi-style reload tail: /reload cannot re-read boot-time-only state
|
|
3456
3883
|
// (cordis.yml root config, frozen fullscreen layout, newly built
|
|
@@ -3679,10 +4106,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3679
4106
|
const pageInsetX = usePageInset().x;
|
|
3680
4107
|
// 侧栏控制器:几何(chatColumns/panelColumns)、焦点与键盘分发都在
|
|
3681
4108
|
// 这个 hook 里(设计文档 §16.5——Chat 只多一次调用、一处键盘让位、
|
|
3682
|
-
// 一条 runCommand case
|
|
4109
|
+
// 一条 runCommand case)。启动页没有侧栏,命令走整屏回退;编辑器
|
|
4110
|
+
// 展开时几何同样强制 collapsed。
|
|
3683
4111
|
const sidePanel = useSidePanel({
|
|
3684
4112
|
columns: terminalColumns,
|
|
3685
|
-
fullscreen,
|
|
4113
|
+
fullscreen: fullscreen && !launchpadShown,
|
|
3686
4114
|
editorOpen: promptEditorOpen,
|
|
3687
4115
|
});
|
|
3688
4116
|
/**
|
|
@@ -3935,7 +4363,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3935
4363
|
// The launchpad owns the whole terminal while it is up — including the
|
|
3936
4364
|
// plain letters that would otherwise reach the composer, which is exactly
|
|
3937
4365
|
// the point: it IS the composer on this screen, and its draft is submitted
|
|
3938
|
-
// directly (see
|
|
4366
|
+
// directly (see submitLaunchpad). ONE exception (fifth revision): a picker
|
|
3939
4367
|
// opened from the param row renders ABOVE the launchpad and therefore owns
|
|
3940
4368
|
// the keyboard — fall through to the overlay branches below (Esc closes the
|
|
3941
4369
|
// picker back onto the launchpad). The launchpad's own useInput is paused
|
|
@@ -4078,6 +4506,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4078
4506
|
}
|
|
4079
4507
|
return;
|
|
4080
4508
|
}
|
|
4509
|
+
if (overlay.kind === 'model') {
|
|
4510
|
+
if (actionMatches('sidePanel', input, key) || actionMatches('sidePanelZoom', input, key)) {
|
|
4511
|
+
if (sidePanel.handleKey(input, key, event))
|
|
4512
|
+
return;
|
|
4513
|
+
}
|
|
4514
|
+
// The model picker owns both navigation axes, including when a side
|
|
4515
|
+
// panel or transcript selection held focus before it opened.
|
|
4516
|
+
const now = Date.now();
|
|
4517
|
+
const confirm = isPlainReturnInput(input, key) && now - lastModalEnterAtRef.current >= 80;
|
|
4518
|
+
if (confirm)
|
|
4519
|
+
lastModalEnterAtRef.current = now;
|
|
4520
|
+
modelPicker.handleKey(input, key, confirm);
|
|
4521
|
+
event.stopImmediatePropagation();
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4081
4524
|
// 侧栏键盘分发(v2.1 优先级):上面的审批 / 问卷 / 对话框守卫仍然
|
|
4082
4525
|
// 最先,其次是侧栏全局快捷键(Ctrl+B / Alt+Z,两种焦点都生效),
|
|
4083
4526
|
// 然后焦点在右栏时一切按键归侧栏——活动面板的业务键优先,宿主
|
|
@@ -4111,11 +4554,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4111
4554
|
event.stopImmediatePropagation();
|
|
4112
4555
|
return;
|
|
4113
4556
|
}
|
|
4114
|
-
//
|
|
4115
|
-
//
|
|
4116
|
-
//
|
|
4117
|
-
|
|
4118
|
-
if (key.escape && hasMouseSelection()) {
|
|
4557
|
+
// With no overlay open, Esc cancels an active mouse drag or retained
|
|
4558
|
+
// selection before ordinary chat meanings. Open overlays own Esc.
|
|
4559
|
+
// Selection queries are imperative reads — no subscription needed.
|
|
4560
|
+
if (overlay.kind === 'none' && key.escape && (hasMouseSelection() || getMouseSelectionState()?.isDragging)) {
|
|
4119
4561
|
clearMouseSelection();
|
|
4120
4562
|
event.stopImmediatePropagation();
|
|
4121
4563
|
return;
|
|
@@ -4336,59 +4778,6 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4336
4778
|
}
|
|
4337
4779
|
return;
|
|
4338
4780
|
}
|
|
4339
|
-
if (overlay.kind === 'model') {
|
|
4340
|
-
// Two-level picker: group rows at the top (Enter drills in), one
|
|
4341
|
-
// provider's models below (Enter switches, the same live-fork path as
|
|
4342
|
-
// the flat picker always had). Esc/⌫ climbs one level and only closes
|
|
4343
|
-
// at the top; a single-group catalog never shows the group level, so
|
|
4344
|
-
// Esc there closes directly.
|
|
4345
|
-
const rowCount = activeModelGroup === undefined ? modelGroups.length : groupModels.length;
|
|
4346
|
-
if (key.upArrow || key.downArrow) {
|
|
4347
|
-
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: rowCount });
|
|
4348
|
-
}
|
|
4349
|
-
else if (plainReturn) {
|
|
4350
|
-
if (activeModelGroup === undefined) {
|
|
4351
|
-
const group = modelGroups[overlay.index];
|
|
4352
|
-
if (!group) {
|
|
4353
|
-
dispatchOverlay({ type: 'close' });
|
|
4354
|
-
return;
|
|
4355
|
-
}
|
|
4356
|
-
setModelGroup(group.provider);
|
|
4357
|
-
// The recents group opens on its most-recent entry; a provider
|
|
4358
|
-
// group on its current model when it owns one, else its first row.
|
|
4359
|
-
if (group.provider === RECENTS_GROUP_PROVIDER) {
|
|
4360
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
|
|
4361
|
-
return;
|
|
4362
|
-
}
|
|
4363
|
-
const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
|
|
4364
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
|
|
4365
|
-
return;
|
|
4366
|
-
}
|
|
4367
|
-
const model = groupModels[overlay.index];
|
|
4368
|
-
// oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: out-of-range index on an empty list
|
|
4369
|
-
if (model) {
|
|
4370
|
-
// Enter switches the live model right away: the conversation is
|
|
4371
|
-
// forked at its end and continued with an agent routed to the new
|
|
4372
|
-
// model (history replays unchanged) — and feeds the recents group.
|
|
4373
|
-
dispatchOverlay({ type: 'close' });
|
|
4374
|
-
void switchModelRecorded(model.provider, model.id, model.name);
|
|
4375
|
-
}
|
|
4376
|
-
else {
|
|
4377
|
-
dispatchOverlay({ type: 'close' });
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4380
|
-
else if (key.escape || key.backspace) {
|
|
4381
|
-
if (activeModelGroup !== undefined && modelGroups.length > 1 && !modelPickerDirect) {
|
|
4382
|
-
setModelGroup(undefined);
|
|
4383
|
-
const groupIndex = Math.max(0, modelGroups.findIndex(group => group.provider === activeModelGroup));
|
|
4384
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: groupIndex });
|
|
4385
|
-
}
|
|
4386
|
-
else {
|
|
4387
|
-
dispatchOverlay({ type: 'close' });
|
|
4388
|
-
}
|
|
4389
|
-
}
|
|
4390
|
-
return;
|
|
4391
|
-
}
|
|
4392
4781
|
if (overlay.kind === 'skills') {
|
|
4393
4782
|
const list = skillsList ?? [];
|
|
4394
4783
|
if (key.upArrow || key.downArrow) {
|
|
@@ -4548,6 +4937,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4548
4937
|
}
|
|
4549
4938
|
return;
|
|
4550
4939
|
}
|
|
4940
|
+
if (overlay.kind === 'permission' && overlay.confirm === true) {
|
|
4941
|
+
if (plainReturn) {
|
|
4942
|
+
permissionOverlayFocusRef.current = null;
|
|
4943
|
+
dispatchOverlay({ type: 'close' });
|
|
4944
|
+
void runPermissionCommand(` ${PERMISSION_PRESET_AUTO}`);
|
|
4945
|
+
}
|
|
4946
|
+
else if (key.escape) {
|
|
4947
|
+
dispatchOverlay({ type: 'open', overlay: { ...overlay, confirm: false } });
|
|
4948
|
+
}
|
|
4949
|
+
return;
|
|
4950
|
+
}
|
|
4551
4951
|
if (overlay.kind === 'permission') {
|
|
4552
4952
|
if (key.upArrow || key.downArrow) {
|
|
4553
4953
|
const currentIndex = permissionOverlayFocusRef.current?.overlay === overlay
|
|
@@ -4563,6 +4963,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4563
4963
|
: overlay.index;
|
|
4564
4964
|
const option = overlay.snapshot.options[currentIndex];
|
|
4565
4965
|
permissionOverlayFocusRef.current = null;
|
|
4966
|
+
if (needsAutoConfirm(overlay.snapshot, option?.value)) {
|
|
4967
|
+
dispatchOverlay({ type: 'open', overlay: { ...overlay, index: currentIndex, confirm: true } });
|
|
4968
|
+
return;
|
|
4969
|
+
}
|
|
4566
4970
|
dispatchOverlay({ type: 'close' });
|
|
4567
4971
|
if (option !== undefined)
|
|
4568
4972
|
void runPermissionCommand(` ${option.value}`);
|
|
@@ -4604,7 +5008,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4604
5008
|
}
|
|
4605
5009
|
if (overlay.kind === 'sdk-install') {
|
|
4606
5010
|
// 向导按键按步骤态分派;checking/running 期间除 Esc(取消安装)外
|
|
4607
|
-
//
|
|
5011
|
+
// 全部吞掉;鼠标关闭/替换浮层由向导的 effect 取消并隔离迟到结果。
|
|
4608
5012
|
if (sdkPhase.kind === 'confirm') {
|
|
4609
5013
|
if (plainReturn)
|
|
4610
5014
|
confirmSdkInstall(sdkPhase.dir);
|
|
@@ -4616,7 +5020,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4616
5020
|
}
|
|
4617
5021
|
else if (sdkPhase.kind === 'running') {
|
|
4618
5022
|
if (key.escape)
|
|
4619
|
-
|
|
5023
|
+
sdkInstallRef.current?.installer?.cancel();
|
|
4620
5024
|
}
|
|
4621
5025
|
else if (sdkPhase.kind === 'done') {
|
|
4622
5026
|
if (plainReturn)
|
|
@@ -4637,6 +5041,77 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4637
5041
|
}
|
|
4638
5042
|
return;
|
|
4639
5043
|
}
|
|
5044
|
+
if (overlay.kind === 'plugin-install') {
|
|
5045
|
+
// 装链路浮层(C-4):一次安装的每一步都是显式的——确认、批准构建脚本、
|
|
5046
|
+
// 接受版本风险;取消由服务自己结算(回滚 profile),期间除 Esc 外不接键。
|
|
5047
|
+
const view = pluginInstall.view;
|
|
5048
|
+
if (view === undefined || view.busy) {
|
|
5049
|
+
if (key.escape) {
|
|
5050
|
+
cancelPluginInstall();
|
|
5051
|
+
event.stopImmediatePropagation();
|
|
5052
|
+
}
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
if (view.step.kind === 'confirm') {
|
|
5056
|
+
if (plainReturn) {
|
|
5057
|
+
pluginInstall.run(view.flow.confirm());
|
|
5058
|
+
event.stopImmediatePropagation();
|
|
5059
|
+
}
|
|
5060
|
+
else if (key.escape) {
|
|
5061
|
+
// 还没开始装:收起浮层即可,不去服务那边取消一个不存在的安装。
|
|
5062
|
+
pluginInstall.close();
|
|
5063
|
+
event.stopImmediatePropagation();
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
5066
|
+
else if (view.step.kind === 'build-blocked') {
|
|
5067
|
+
if (plainReturn) {
|
|
5068
|
+
pluginInstall.run(view.flow.approve(view.step.builds));
|
|
5069
|
+
event.stopImmediatePropagation();
|
|
5070
|
+
}
|
|
5071
|
+
else if (key.escape) {
|
|
5072
|
+
pluginInstall.close();
|
|
5073
|
+
event.stopImmediatePropagation();
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
else if (view.step.kind === 'incompatible') {
|
|
5077
|
+
if (plainReturn) {
|
|
5078
|
+
pluginInstall.run(view.flow.acceptRisk());
|
|
5079
|
+
event.stopImmediatePropagation();
|
|
5080
|
+
}
|
|
5081
|
+
else if (key.escape) {
|
|
5082
|
+
pluginInstall.close();
|
|
5083
|
+
event.stopImmediatePropagation();
|
|
5084
|
+
}
|
|
5085
|
+
}
|
|
5086
|
+
else if (key.escape) {
|
|
5087
|
+
pluginInstall.close();
|
|
5088
|
+
event.stopImmediatePropagation();
|
|
5089
|
+
}
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
if (overlay.kind === 'plugin-manage') {
|
|
5093
|
+
// 生命周期浮层(C-5):只有「确认」一种答案,写入中除 Esc 外不接键。
|
|
5094
|
+
// 与装链路的关键差异是**没有取消**:这三个动作服务不提供取消面,写也是一次
|
|
5095
|
+
// 就结算的 profile 操作,所以 Esc 只关面板,流程照旧跑完并把结果(仍按发起时
|
|
5096
|
+
// 的 binding 加栅栏)写进转录;浮层没了就不再更新步骤态。
|
|
5097
|
+
const view = pluginManage.view;
|
|
5098
|
+
if (view === undefined || view.busy) {
|
|
5099
|
+
if (key.escape) {
|
|
5100
|
+
pluginManage.close();
|
|
5101
|
+
event.stopImmediatePropagation();
|
|
5102
|
+
}
|
|
5103
|
+
return;
|
|
5104
|
+
}
|
|
5105
|
+
if (plainReturn) {
|
|
5106
|
+
pluginManage.run(view.flow.confirm());
|
|
5107
|
+
event.stopImmediatePropagation();
|
|
5108
|
+
}
|
|
5109
|
+
else if (key.escape) {
|
|
5110
|
+
pluginManage.close();
|
|
5111
|
+
event.stopImmediatePropagation();
|
|
5112
|
+
}
|
|
5113
|
+
return;
|
|
5114
|
+
}
|
|
4640
5115
|
if (overlay.kind === 'channel') {
|
|
4641
5116
|
// 名册不冻在 overlay 里(channelRows 是渲染期派生值):切换/导入后
|
|
4642
5117
|
// 选择器自己就刷新成新状态,不需要重开。
|
|
@@ -5169,8 +5644,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5169
5644
|
// 鼠标等价),浮层收起、人还在启动页(第八版:不许进对话页)。
|
|
5170
5645
|
dispatchOverlay({ type: 'close' });
|
|
5171
5646
|
const filled = '/' + name + ' ';
|
|
5172
|
-
|
|
5173
|
-
setLaunchpadCaret(filled.length);
|
|
5647
|
+
changeLaunchpadDraft(filled, filled.length);
|
|
5174
5648
|
setLaunchpadFocus(-1);
|
|
5175
5649
|
} }) })), overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
|
|
5176
5650
|
// 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
|
|
@@ -5195,28 +5669,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5195
5669
|
return;
|
|
5196
5670
|
dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
|
|
5197
5671
|
runWorkspaceFlowAction(signal => choice.choose(signal));
|
|
5198
|
-
} }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.
|
|
5199
|
-
// 点击分组行 = 进入该组(与 Enter 同一条路径)
|
|
5200
|
-
const group = modelGroups[index];
|
|
5201
|
-
if (!group)
|
|
5202
|
-
return;
|
|
5203
|
-
setModelGroup(group.provider);
|
|
5204
|
-
if (group.provider === RECENTS_GROUP_PROVIDER) {
|
|
5205
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
|
|
5206
|
-
return;
|
|
5207
|
-
}
|
|
5208
|
-
const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
|
|
5209
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
|
|
5210
|
-
} })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
|
|
5211
|
-
? t('picker-group-recent')
|
|
5212
|
-
: modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
|
|
5213
|
-
// 点击行 = 应用该行模型(与 Enter 同一条路径)
|
|
5214
|
-
const model = groupModels[index];
|
|
5215
|
-
if (!model)
|
|
5216
|
-
return;
|
|
5217
|
-
dispatchOverlay({ type: 'close' });
|
|
5218
|
-
void switchModelRecorded(model.provider, model.id, model.name);
|
|
5219
|
-
} })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
|
|
5672
|
+
} }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ModelPicker, { groups: modelPicker.groups, provider: modelPicker.provider, models: modelPicker.models, focusIndex: modelPicker.index, currentModel: `${channel.provider}/${channel.model}`, loading: modelsLoading, efforts: modelPicker.efforts, effortId: modelPicker.effortId, effortsLoading: modelPicker.effortsLoading, effortError: modelPicker.effortError, levelsFallback: modelPicker.levelsFallback, cursorZone: modelPicker.cursorZone, onProvider: modelPicker.focusProvider, onFocus: modelPicker.focusModel, onEffort: modelPicker.pickEffort, onMove: modelPicker.moveModel, onConfirm: modelPicker.confirm, onCancel: modelPicker.cancel }) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
|
|
5220
5673
|
const row = (migrateRows ?? [])[index];
|
|
5221
5674
|
if (!row)
|
|
5222
5675
|
return;
|
|
@@ -5264,10 +5717,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5264
5717
|
const option = presetOptions[index];
|
|
5265
5718
|
if (option)
|
|
5266
5719
|
void channel.switchPreset(option.id);
|
|
5267
|
-
} }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd,
|
|
5720
|
+
} }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, confirming: overlay.confirm === true, onConfirm: () => {
|
|
5721
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5722
|
+
return;
|
|
5723
|
+
permissionOverlayFocusRef.current = null;
|
|
5724
|
+
dispatchOverlay({ type: 'close' });
|
|
5725
|
+
void runPermissionCommand(` ${PERMISSION_PRESET_AUTO}`);
|
|
5726
|
+
}, onCancelConfirm: () => {
|
|
5727
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5728
|
+
return;
|
|
5729
|
+
dispatchOverlay({ type: 'open', overlay: { ...overlay, confirm: false } });
|
|
5730
|
+
}, onPick: (index) => {
|
|
5268
5731
|
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5269
5732
|
return;
|
|
5270
5733
|
const option = overlay.snapshot.options[index];
|
|
5734
|
+
if (needsAutoConfirm(overlay.snapshot, option?.value)) {
|
|
5735
|
+
dispatchOverlay({ type: 'open', overlay: { ...overlay, index, confirm: true } });
|
|
5736
|
+
return;
|
|
5737
|
+
}
|
|
5271
5738
|
dispatchOverlay({ type: 'close' });
|
|
5272
5739
|
if (option !== undefined)
|
|
5273
5740
|
void runPermissionCommand(` ${option.value}`);
|
|
@@ -5282,7 +5749,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5282
5749
|
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5283
5750
|
return;
|
|
5284
5751
|
pickKernel(index);
|
|
5285
|
-
} }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
|
|
5752
|
+
} }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'plugin-install' && pluginInstall.view !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PluginInstallPane, { step: pluginInstall.view.step, busy: pluginInstall.view.busy }) })), overlay.kind === 'plugin-manage' && pluginManage.view !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PluginManagePane, { step: pluginManage.view.step, busy: pluginManage.view.busy }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
|
|
5286
5753
|
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5287
5754
|
return;
|
|
5288
5755
|
pickChannel(index);
|
|
@@ -5424,12 +5891,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5424
5891
|
// 第七版:明确选中一个会话 = 有意导航(与 Esc「退出」相对)——浏览页
|
|
5425
5892
|
// 与盖在它底下的落地页**一起收**,人落在那个会话的聊天页。只收浏览页
|
|
5426
5893
|
// 会露出启动页,正是用户实测的「选完会话还是回到启动页」。落地页的
|
|
5427
|
-
// 草稿/焦点也按
|
|
5894
|
+
// 草稿/焦点也按 submitLaunchpad 同一口径清掉(进入的是别的会话,旧草稿
|
|
5428
5895
|
// 不该跟过去)。
|
|
5429
5896
|
setLaunchpadOpen(false);
|
|
5430
5897
|
setLaunchpadFocus(-1);
|
|
5431
|
-
|
|
5432
|
-
setLaunchpadCaret(0);
|
|
5898
|
+
changeLaunchpadDraft('', 0);
|
|
5433
5899
|
repaintTranscript();
|
|
5434
5900
|
return result;
|
|
5435
5901
|
}, onNewSession: async (target) => {
|
|
@@ -5441,8 +5907,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5441
5907
|
// 同 onOpenSession:新建/切工作区会话也是有意导航,落地页一并收。
|
|
5442
5908
|
setLaunchpadOpen(false);
|
|
5443
5909
|
setLaunchpadFocus(-1);
|
|
5444
|
-
|
|
5445
|
-
setLaunchpadCaret(0);
|
|
5910
|
+
changeLaunchpadDraft('', 0);
|
|
5446
5911
|
repaintTranscript();
|
|
5447
5912
|
}
|
|
5448
5913
|
return ok;
|
|
@@ -5540,7 +6005,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5540
6005
|
// of the sidebar panel. Esc returns to the sidebar exactly as it was — the
|
|
5541
6006
|
// thread and the composer draft live in btwThreads, nothing is cleared.
|
|
5542
6007
|
if (btwSceneOpen && launchpadGate()) {
|
|
5543
|
-
const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false)
|
|
6008
|
+
const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false),
|
|
6009
|
+
// 送聊天之后整屏场景让位:关场景 + 焦点回主输入框——与侧栏形态里
|
|
6010
|
+
// 「面板留着、焦点回输入框」的落点一致(见 BtwThreadScene.sendToChat)。
|
|
6011
|
+
onFocusChat: sidePanel.focusChat }));
|
|
5544
6012
|
return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
|
|
5545
6013
|
}
|
|
5546
6014
|
// Subagent dashboard: displays all active and completed subagents.
|
|
@@ -5548,7 +6016,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5548
6016
|
if (subagentDashboardOpen && launchpadGate()) {
|
|
5549
6017
|
// No kernel serves agents from other sessions yet, so the dashboard gets
|
|
5550
6018
|
// no `peers`; once one does, pass them here.
|
|
5551
|
-
const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], onSelect: (id) => {
|
|
6019
|
+
const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], team: channel.team, sessionId: channel.sessionId, onSelect: (id) => {
|
|
5552
6020
|
setSubagentDashboardOpen(false);
|
|
5553
6021
|
setSubagentDetailId(id);
|
|
5554
6022
|
}, onOpenView: (id) => openAgentView(id, { kind: 'agents-dashboard' }), messages: channel.subagentControl?.message?.messages(), onClose: () => setSubagentDashboardOpen(false) }));
|
|
@@ -5598,7 +6066,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5598
6066
|
let launchpadPermission;
|
|
5599
6067
|
try {
|
|
5600
6068
|
const snapshot = channel.permissionPresets();
|
|
5601
|
-
launchpadPermission = snapshot.availability === 'runtime' ? snapshot
|
|
6069
|
+
launchpadPermission = snapshot.availability === 'runtime' ? currentPermissionName(snapshot) : undefined;
|
|
5602
6070
|
}
|
|
5603
6071
|
catch {
|
|
5604
6072
|
launchpadPermission = undefined;
|
|
@@ -5618,10 +6086,22 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5618
6086
|
jobsRunning: (channel.backgroundJobs ?? []).some(job => job.status === 'running' || job.status === 'stopping'),
|
|
5619
6087
|
updateAvailable: launchpadUpdateAvailable,
|
|
5620
6088
|
starDue: launchpadStarDue,
|
|
5621
|
-
// 内核入口带名(「内核 · Claude」):backendId
|
|
6089
|
+
// 内核入口带名(「内核 · Claude」):backendId 是内核身份的唯一来源,
|
|
6090
|
+
// 名字取同一份选择器目录里的短品牌名(manifest 的 shortLabel)。
|
|
5622
6091
|
backendId: kernelCurrentId,
|
|
6092
|
+
backendLabel: kernelCurrentOption?.shortLabel,
|
|
5623
6093
|
});
|
|
5624
|
-
const
|
|
6094
|
+
const lastNotification = channel.notifications.at(-1);
|
|
6095
|
+
// While the session's backend is still starting (the status line's
|
|
6096
|
+
// `status-starting` segment), the Tips row says so — below any notice.
|
|
6097
|
+
const launchpadNotice = lastNotification === undefined
|
|
6098
|
+
? channel.ready === false && channel.startupFailure === undefined
|
|
6099
|
+
? { text: t('status-starting', { backend: channel.backendCapabilities?.backendLabel ?? 'DSH' }), color: 'warning' }
|
|
6100
|
+
: undefined
|
|
6101
|
+
: { text: lastNotification.text, ...(lastNotification.color === undefined ? {} : { color: lastNotification.color }) };
|
|
6102
|
+
const launchpad = (_jsx(Launchpad, { query: launchpadDraft, imageComposer: { channel, bindings: launchpadImagesRef.current }, cursorOffset: launchpadCaret, focusIndex: launchpadFocus, isTerminalFocused: terminalFocused, whale: channel.whale, whaleIdle: channel.whaleIdle, whaleGirl: channel.whaleGirl, fontId: splashFontIdOf(channel.splashFont), brand: brand, starred: starred, onStarClick: runStarAction, firstRun: onboardingPending, actions: launchpadActions,
|
|
6103
|
+
// 落地页没有 toast 区:最近一条 channel 通知借 Tips 行显示。
|
|
6104
|
+
notice: launchpadNotice,
|
|
5625
6105
|
// 参数行四段点开的既有选择器(第五版):pickerPanels 与聊天页共用
|
|
5626
6106
|
// 同一份 JSX,盖在落地页之上;选择器开着时落地页键盘让位(inputPaused)。
|
|
5627
6107
|
overlayPanel: launchpadOverlayUp ? pickerPanels : undefined, inputPaused: launchpadOverlayUp, onParamPick: (segment) => {
|
|
@@ -5642,10 +6122,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5642
6122
|
dispatchOverlay({ type: 'close' });
|
|
5643
6123
|
}
|
|
5644
6124
|
void runCommand(segment, '');
|
|
5645
|
-
}, onQueryChange:
|
|
5646
|
-
setLaunchpadDraft(text);
|
|
5647
|
-
setLaunchpadCaret(cursor);
|
|
5648
|
-
}, onSubmit: closeLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
|
|
6125
|
+
}, onQueryChange: changeLaunchpadDraft, onSubmit: submitLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
|
|
5649
6126
|
// 第八版(用户实测:「刚点帮助,不知道为什么直接进入聊天页面了」):
|
|
5650
6127
|
// 帮助**不属于**离开启动页的两条路(Enter 发非命令消息 / 会话浏览
|
|
5651
6128
|
// 里选中会话)——它盖在落地页之上(overlay kind 'help'),再点同一
|
|
@@ -5663,6 +6140,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5663
6140
|
// launchpadGate 的授权位(防御:异步误置的整屏状态盖不走启动页)。
|
|
5664
6141
|
// 其余命令(star / update——反馈在对话页的转录/通知)仍收掉落地页
|
|
5665
6142
|
// 再执行,这是用户主动执行命令,不是「返回」。
|
|
6143
|
+
if (refusedAtStartup(action.command))
|
|
6144
|
+
return;
|
|
5666
6145
|
if (launchpadScreenCommands.has(action.command)) {
|
|
5667
6146
|
authorizeLaunchpadCover();
|
|
5668
6147
|
}
|
|
@@ -5693,26 +6172,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5693
6172
|
? undefined
|
|
5694
6173
|
: presetOptions.find(option => option.id === channel.agentPreset)?.name ?? channel.agentPreset, permission: launchpadPermission, commands: launchpadOverlayUp || !launchpadDraft.startsWith('/')
|
|
5695
6174
|
? undefined
|
|
5696
|
-
: channel.commandCompletions(launchpadDraft), onCommandPick:
|
|
5697
|
-
// 补全面板选中(Enter/Tab/点击):走 runCommand,与快捷入口同一条
|
|
5698
|
-
// 白名单口径——覆盖层与整屏命令(第七版 launchpadScreenCommands)
|
|
5699
|
-
// 不收落地页(盖在它之上),其余收掉再执行。/help 与快捷入口同一条
|
|
5700
|
-
// 拦截:盖屏浮层,不进对话页(第八版)。
|
|
5701
|
-
const parsed = parseCommandName(commandLine);
|
|
5702
|
-
if (parsed === undefined)
|
|
5703
|
-
return;
|
|
5704
|
-
if (parsed.name === 'help') {
|
|
5705
|
-
dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
|
|
5706
|
-
return;
|
|
5707
|
-
}
|
|
5708
|
-
if (launchpadScreenCommands.has(parsed.name)) {
|
|
5709
|
-
authorizeLaunchpadCover();
|
|
5710
|
-
}
|
|
5711
|
-
else if (!overlayCommandNames.has(parsed.name)) {
|
|
5712
|
-
setLaunchpadOpen(false);
|
|
5713
|
-
}
|
|
5714
|
-
void runCommand(parsed.name, parsed.rawInput);
|
|
5715
|
-
}, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
|
|
6175
|
+
: channel.commandCompletions(launchpadDraft), onCommandPick: submitLaunchpad, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
|
|
5716
6176
|
// 右下角的内核行:与选择器同一份目录,标出当前内核,点它打开选择器。
|
|
5717
6177
|
kernels: kernelOptions, onKernelPick: () => openKernelPicker(),
|
|
5718
6178
|
// 左下角工作目录铭牌(第七版):点开/回车开既有 /workspace 菜单——
|
|
@@ -5772,7 +6232,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5772
6232
|
? () => setPeekSuppressed(peekKey(activePreview.image, activePreview.title))
|
|
5773
6233
|
: () => dispatchOverlay({ type: 'close-if', kind: 'image-preview' }), region: imagePreviewRegion }))
|
|
5774
6234
|
: null;
|
|
5775
|
-
return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
|
|
6235
|
+
return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, onResize: sidePanel.resize, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
|
|
5776
6236
|
approvals: approvalSnapshot !== null ? 1 : 0,
|
|
5777
6237
|
questions: questionSnapshot !== null ? 1 : 0,
|
|
5778
6238
|
}, trajectory: trajectory, onExpand: openPanelFullscreen }), children: [!isSticky && timeline.activeId !== null && (_jsx(PinnedTurnHeader, { text: anchorUserText || null, onClick: () => {
|
|
@@ -5852,6 +6312,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5852
6312
|
writeRaw?.(raw); });
|
|
5853
6313
|
channel.notify(t('copied-chars', { n: answer.length }), { timeoutMs: 1500 });
|
|
5854
6314
|
} }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen,
|
|
6315
|
+
// 选择器、搜索框或侧栏持有键盘焦点时,让对应输入框接管原生
|
|
6316
|
+
// 光标与 IME 锚点,避免主输入框在后续提交中抢回声明。
|
|
6317
|
+
cursorParking: overlay.kind === 'none' && sidePanel.focus !== 'panel',
|
|
5855
6318
|
// 宠物面板是活动面板时,通知由它的头顶气泡「说出来」,输入框上方
|
|
5856
6319
|
// 不再重复弹同一条(error 色除外——可能要行动的信号永远走 toast)。
|
|
5857
6320
|
// 渲染期判定(split + activePanelId),与气泡同一次提交切换,不会
|
|
@@ -5865,7 +6328,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
5865
6328
|
onOpenSessions: () => {
|
|
5866
6329
|
agentViewOpenSessionRef.current = channel.agentId;
|
|
5867
6330
|
setSupervisorOpen(true);
|
|
5868
|
-
},
|
|
6331
|
+
},
|
|
6332
|
+
// 当前内核的短品牌名:与选择器、落地页铭牌同一份 manifest 数据(P0 D2)。
|
|
6333
|
+
backendLabel: kernelCurrentOption?.shortLabel, backgroundAgentsNeedingInput:
|
|
5869
6334
|
// Only the real channel supplies the seam; pre-agent-view test
|
|
5870
6335
|
// stubs must not grow the footer row (layout-dependent
|
|
5871
6336
|
// regressions pin the visible row count). The footer only
|
|
@@ -5920,15 +6385,12 @@ function NewMessagesPill({ count, onClick, }) {
|
|
|
5920
6385
|
? t(count === 1 ? 'new-message' : 'new-messages', { n: count })
|
|
5921
6386
|
: t('back-to-bottom'), ' '] }) }) }));
|
|
5922
6387
|
}
|
|
5923
|
-
/** /model while the provider catalog is still loading. */
|
|
5924
|
-
function ModelPickerLoading() {
|
|
5925
|
-
return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, color: "permission", children: t('picker-title-model') }), _jsx(LoadingState, { message: t('model-loading'), bold: true, subtitle: t('model-loading-subtitle') })] }) }));
|
|
5926
|
-
}
|
|
5927
6388
|
/**
|
|
5928
6389
|
* The `/` incsearch bar: a
|
|
5929
6390
|
* single row above the prompt input with the query, a block cursor, and the
|
|
5930
6391
|
* match counter (`current/count`) or a red `no matches` when nothing hits.
|
|
5931
6392
|
*/ function TranscriptSearch({ query, cursorOffset, count, current, }) {
|
|
5932
|
-
const
|
|
5933
|
-
|
|
6393
|
+
const caretOffset = cursorOffset < query.length ? previousCodePoint(query, cursorOffset + 1) : query.length;
|
|
6394
|
+
const cursorChar = [...query.slice(caretOffset)][0] ?? ' ';
|
|
6395
|
+
return (_jsxs(NoSelect, { borderTopDimColor: true, borderBottom: false, borderLeft: false, borderRight: false, borderStyle: "single", marginTop: 1, paddingLeft: 2, width: "100%", children: [_jsx(Text, { children: "/" }), _jsx(Text, { children: query.slice(0, caretOffset) }), _jsx(InputCaret, { children: cursorChar }), caretOffset < query.length && _jsx(Text, { children: query.slice(caretOffset + cursorChar.length) }), _jsx(Box, { flexGrow: 1 }), query && count === 0 ? (_jsxs(Text, { color: "error", children: [t('search-no-matches'), " "] })) : count > 0 ? (_jsxs(Text, { dimColor: true, children: [Math.min(current + 1, count), "/", count, ' '] })) : null] }));
|
|
5934
6396
|
}
|