@deepseek-harness-tui/dsh-tui 0.15.0 → 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 +92 -5
- package/guide/dsh-tui-guide/codex-backend.en.md +13 -3
- package/guide/dsh-tui-guide/codex-backend.md +9 -2
- package/guide/dsh-tui-guide/configuration.en.md +39 -2
- package/guide/dsh-tui-guide/configuration.md +34 -2
- 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 +8 -1
- package/guide/dsh-tui-guide/interaction.md +8 -1
- package/guide/dsh-tui-guide/plugins.en.md +66 -5
- package/guide/dsh-tui-guide/plugins.md +37 -3
- package/guide/dsh-tui-guide/user-guide.en.md +3 -2
- package/guide/dsh-tui-guide/user-guide.md +3 -2
- package/lib/settings.json +1 -1
- 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 +1 -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 +5 -3
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +7 -1
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +47 -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/agent/events.d.ts +3 -2
- package/lib/types/agent/events.d.ts.map +1 -1
- 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/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/session.d.ts.map +1 -1
- package/lib/types/backends/codex/session/session.js +35 -9
- package/lib/types/backends/codex/text.d.ts +3 -3
- package/lib/types/backends/codex/text.js +1 -1
- package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
- package/lib/types/backends/codex/translate/items.js +3 -1
- 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/channel/projection.d.ts.map +1 -1
- package/lib/types/channel/projection.js +10 -0
- package/lib/types/commands.d.ts +10 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +11 -2
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +4 -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 +5 -3
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +95 -14
- 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/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +7 -3
- 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/launchpadLayout.d.ts +14 -1
- package/lib/types/components/launchpadLayout.d.ts.map +1 -1
- package/lib/types/components/launchpadLayout.js +36 -17
- 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/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.map +1 -1
- package/lib/types/components/sidePanel/SidePanelColumn.js +13 -1
- 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 +3 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwComposer.js +20 -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 +104 -13
- 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 +61 -15
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +14 -4
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
- package/lib/types/components/sidePanel/btw/BtwThreadView.js +90 -5
- 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/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 +6 -0
- package/lib/types/components/sidePanel/types.d.ts.map +1 -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/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/dsh-adapter/admission-loader.d.ts +82 -0
- package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -1
- package/lib/types/dsh-adapter/admission-loader.js +73 -28
- 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 +68 -8
- 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 +36 -0
- package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/backend-contribution.js +41 -0
- package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -1
- package/lib/types/dsh-adapter/backend-registry.js +22 -3
- package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
- package/lib/types/dsh-adapter/backends.js +4 -5
- 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/binding-events.d.ts +1 -0
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +1 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/command-completions.js +64 -7
- 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/core/binding-feed.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/binding-feed.js +2 -1
- package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/core/compose.js +12 -0
- package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/extensions.js +68 -8
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +6 -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 +104 -12
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +8 -1
- 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/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +4 -3
- 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 +7 -0
- package/lib/types/dsh-adapter/channel/settings-host.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +135 -5
- package/lib/types/dsh-adapter/channel/state.d.ts +6 -0
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +18 -6
- package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -0
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +19 -2
- 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/contract.d.ts +4 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +5 -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 +3 -1
- package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -1
- package/lib/types/dsh-adapter/entry-slot.js +2 -2
- package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -1
- package/lib/types/dsh-adapter/fresh-agent.js +6 -1
- package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
- package/lib/types/dsh-adapter/host-access.js +95 -0
- package/lib/types/dsh-adapter/host-contract.d.ts +1 -1
- package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/host-contract.js +3 -2
- package/lib/types/dsh-adapter/host-dsh.d.ts +8 -2
- package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -1
- package/lib/types/dsh-adapter/host-dsh.js +45 -30
- package/lib/types/dsh-adapter/host-entry.js +35 -10
- package/lib/types/dsh-adapter/index.d.ts +9 -10
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +8 -6
- 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/migrate/index.js +2 -2
- package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
- package/lib/types/dsh-adapter/panels.js +6 -0
- package/lib/types/dsh-adapter/plugin-declaration.d.ts +99 -1
- package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin-declaration.js +132 -2
- 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-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 +78 -2
- package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin-manager.js +32 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +49 -2
- package/lib/types/dsh-adapter/plugins-info.d.ts +87 -1
- package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugins-info.js +131 -26
- package/lib/types/dsh-adapter/process-exit.d.ts +1 -1
- package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -1
- package/lib/types/dsh-adapter/process-exit.js +1 -1
- 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/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/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +2 -1
- 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/types.d.ts +1 -1
- package/lib/types/dsh-adapter/types.d.ts.map +1 -1
- package/lib/types/i18n.d.ts +607 -16
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +295 -9
- 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/kernelPrefs.d.ts +1 -1
- package/lib/types/kernelPrefs.d.ts.map +1 -1
- 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/permissionPresetLabels.d.ts +25 -0
- package/lib/types/permissionPresetLabels.d.ts.map +1 -0
- package/lib/types/permissionPresetLabels.js +33 -0
- 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/screens/Chat.d.ts +33 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +301 -9
- package/lib/types/screens/Launchpad.d.ts +7 -1
- package/lib/types/screens/Launchpad.d.ts.map +1 -1
- package/lib/types/screens/Launchpad.js +19 -4
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +1 -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 +19 -1
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- 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/tips.js +2 -2
- 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 +126 -120
- package/tui-profile/feed/README.md +63 -0
- package/tui-profile/feed/first-party.json +10 -0
|
@@ -80,7 +80,10 @@ export function CommandSuggestions({ commands, selectedIndex, columns, query = '
|
|
|
80
80
|
: stringWidth(rawDescription) > descriptionWidth
|
|
81
81
|
? truncateToWidth(rawDescription, descriptionWidth - 1) + '…'
|
|
82
82
|
: rawDescription;
|
|
83
|
-
|
|
83
|
+
// 名字比名字列还宽时(长 spec、长 bundle 名)差值为 0,描述会贴着名字
|
|
84
|
+
// 渲染成 `…ple.gitInstall from a git URL`——至少留一格分隔;超出的这一格
|
|
85
|
+
// 由行尾的 truncate 裁掉,行内容不会因此多出一行。
|
|
86
|
+
const padAfter = Math.max(1, nameWidth - stringWidth(command.name));
|
|
84
87
|
// 灰区整行一个 `subtle`,且刻意不做查询命中提亮(灰区不该看起来像
|
|
85
88
|
// 「可用」)。选中行仍走下方通用样式,保证光标始终可见。
|
|
86
89
|
if (isHeld && !isSelected) {
|
|
@@ -3,6 +3,7 @@ import { type Tip } from '../tips.js';
|
|
|
3
3
|
import { type UpstreamDriftSummary } from '../dsh-adapter/contract.js';
|
|
4
4
|
import { type Brand } from '../branding.js';
|
|
5
5
|
import { type SplashEgg } from './splashEggs.js';
|
|
6
|
+
import type { SplashImageBox } from './splashArtRows.js';
|
|
6
7
|
import { type WhaleIntroId } from './whaleFrames.js';
|
|
7
8
|
/**
|
|
8
9
|
* The header splash: one layout, two phases. The **opening** (~1.7–3.5s,
|
|
@@ -32,7 +33,7 @@ import { type WhaleIntroId } from './whaleFrames.js';
|
|
|
32
33
|
* with a clickable "star us on GitHub" line whose indent is recomputed from
|
|
33
34
|
* its own width.
|
|
34
35
|
*/
|
|
35
|
-
export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, fontId, whale, whaleIdle, whaleGirl, brand, starred, starReveal, onStarClick, working, drift, egg, starChance, align, chrome, arrangement, companionSkin, }: {
|
|
36
|
+
export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, fontId, whale, whaleIdle, whaleGirl, brand, starred, starReveal, onStarClick, working, drift, egg, starChance, align, chrome, arrangement, companionSkin, mascotBox, }: {
|
|
36
37
|
/** 模型/effort/工作目录只画在 full 形态里;minimal(落地页)不传也行。 */
|
|
37
38
|
model?: string;
|
|
38
39
|
effort?: string | undefined;
|
|
@@ -128,5 +129,7 @@ export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, font
|
|
|
128
129
|
/** 测试缝:钉住启动页吉祥物皮肤(undefined——生产——读 companion.skin;
|
|
129
130
|
* 'whale'/未知 = 维持原鲸鱼/女仆娘路径,见 SplashMascot.tsx)。 */
|
|
130
131
|
companionSkin?: string;
|
|
132
|
+
/** 落地页传入与高度预算相同的紧凑图片槽。 */
|
|
133
|
+
mascotBox?: SplashImageBox;
|
|
131
134
|
}): React.ReactNode;
|
|
132
135
|
//# sourceMappingURL=LogoV2.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAiB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAoD,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAMxH,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAM9E,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAU/E,OAAO,EAA+E,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AA+CjI;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAU,EACV,MAAM,EACN,GAAQ,EACR,SAAiB,EACjB,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAY,EACZ,SAAgB,EAChB,SAAiB,EACjB,KAAkB,EAClB,OAAe,EACf,UAAU,EACV,WAAW,EACX,OAAe,EACf,KAAK,EACL,GAAG,EACH,UAAU,EACV,KAAe,EACf,MAAe,EACf,WAAmB,EACnB,aAAa,
|
|
1
|
+
{"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAiB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAoD,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAMxH,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAM9E,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAU/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAA+E,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AA+CjI;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAU,EACV,MAAM,EACN,GAAQ,EACR,SAAiB,EACjB,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAY,EACZ,SAAgB,EAChB,SAAiB,EACjB,KAAkB,EAClB,OAAe,EACf,UAAU,EACV,WAAW,EACX,OAAe,EACf,KAAK,EACL,GAAG,EACH,UAAU,EACV,KAAe,EACf,MAAe,EACf,WAAmB,EACnB,aAAa,EACb,SAAS,GACV,EAAE;IACD,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,GAAG,CAAA;IACT;;qCAEiC;IACjC,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB;oEACgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;;8CAO0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,UAAU,CAAC,EAAE,SAAS,CAAA;IACtB;sCACkC;IAClC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;4CAGwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;2EACuE;IACvE,KAAK,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACnC;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC9B;wDACoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,cAAc,CAAA;CAC3B,GAAG,KAAK,CAAC,SAAS,CA4jBlB"}
|
|
@@ -23,7 +23,7 @@ import { STANDARD_FRAME_INDEX, WhaleArt } from './Whale.js';
|
|
|
23
23
|
import { WhaleGirlArt } from './WhaleGirl.js';
|
|
24
24
|
import { ClaudeGirlArt } from './ClaudeGirl.js';
|
|
25
25
|
import { MAID_BOX_CENTER, MaidPortrait, portraitAssetsOf, useMaidPortraits } from './maidPortrait.js';
|
|
26
|
-
import { SplashMascot, useSplashMascotSkin } from './sidePanel/companion/SplashMascot.js';
|
|
26
|
+
import { SplashMascot, useSplashMascotSkin, useSplashMascotBox } from './sidePanel/companion/SplashMascot.js';
|
|
27
27
|
import { OPENING_SEQUENCES, pickOpeningSequence, WHALE_FRAME_INDEX } from './whaleFrames.js';
|
|
28
28
|
import { RESTING_POSE } from './whaleLayers.js';
|
|
29
29
|
import { initialWhaleIdleState, nextWhaleIdleStep, } from './whaleIdle.js';
|
|
@@ -90,7 +90,7 @@ function capitalize(text) {
|
|
|
90
90
|
* with a clickable "star us on GitHub" line whose indent is recomputed from
|
|
91
91
|
* its own width.
|
|
92
92
|
*/
|
|
93
|
-
export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro, tip, fontId, whale = true, whaleIdle = true, whaleGirl = false, brand = 'deepseek', starred = false, starReveal, onStarClick, working = false, drift, egg, starChance, align = 'start', chrome = 'full', arrangement = 'row', companionSkin, }) {
|
|
93
|
+
export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro, tip, fontId, whale = true, whaleIdle = true, whaleGirl = false, brand = 'deepseek', starred = false, starReveal, onStarClick, working = false, drift, egg, starChance, align = 'start', chrome = 'full', arrangement = 'row', companionSkin, mascotBox, }) {
|
|
94
94
|
// One intro per logo mount: the production path rolls (startup splash
|
|
95
95
|
// and each /deepseek replay roll independently), the `intro` seam pins
|
|
96
96
|
// a specific animation for probes.
|
|
@@ -127,6 +127,8 @@ export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro,
|
|
|
127
127
|
// 'whale'/未知皮肤 → undefined,原路径零改动。冻结/落地页(whaleIdle=
|
|
128
128
|
// false)时吉祥物定格 idle 帧 0、零时钟(SplashMascot 内部保证)。
|
|
129
129
|
const mascotSkin = useSplashMascotSkin(companionSkin);
|
|
130
|
+
const compactMascotBox = useSplashMascotBox(mascotSkin, brand === 'deepseek' && arrangement === 'column' && chrome === 'minimal');
|
|
131
|
+
const imageBox = mascotBox ?? compactMascotBox;
|
|
130
132
|
// ── Whale behaviors (ported from the dsh-ui-whale pet) ─────────────────
|
|
131
133
|
// Intro-phase click → heart pass: whole heart frames over the opening
|
|
132
134
|
// animation (one-way heart1→heart2→heart3). Once the header settles, the
|
|
@@ -475,7 +477,7 @@ export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro,
|
|
|
475
477
|
setHeartSeq(0);
|
|
476
478
|
setHeartKey(k => k + 1);
|
|
477
479
|
}
|
|
478
|
-
}, children: _jsx(Box, { width: WHALE_BOX_WIDTH, flexDirection: "column", alignItems: "center", children: brand === 'deepseek' && mascotSkin !== undefined ? (_jsx(SplashMascot, { skin: mascotSkin, active: !whaleFrozen && whaleIdle })) : portraitMode ? (_jsx(Box, { width: WHALE_BOX_WIDTH, height: textColumnRows, flexDirection: "row", justifyContent: "center", alignItems: "center", children: maidImageActive ? (_jsx(MaidPortrait, { source: maidHappy ? (portraits?.happy ?? maidSource) : maidSource, maxColumns: WHALE_BOX_WIDTH, maxRows: textColumnRows, presentation: "transcript" })) : (claudeArt ? _jsx(ClaudeGirlArt, { width: WHALE_BOX_WIDTH }) : _jsx(WhaleGirlArt, { width: WHALE_BOX_WIDTH })) })) : (_jsx(WhaleArt, { frameIndex: frameIndex, pose: settled && whaleIdle && !whaleFrozen ? (idlePose ?? RESTING_POSE) : undefined, width: WHALE_BOX_WIDTH })) }) })), (showBigTitle || showPlainTitle) && (_jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [chrome !== 'minimal' && (_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] })), showBigTitle ? (_jsxs(_Fragment, { children: [bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `ds-${index}`))), _jsx(Box, { height: 1 }), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `h-${index}`)))] })) : (showPlainTitle && (_jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: words.plain }))), chrome !== 'minimal' && (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), getLang() === 'zh' ? randomTip.zh : randomTip.en, _jsx(Text, { dimColor: true, children: ' · /tips ' + tr('logo-tip-more') })] })] })), chrome !== 'minimal' && driftLine != null && (_jsxs(Text, { color: "warning", wrap: "wrap", children: ["\u26A0", ' ', tOr(`logo-drift-${driftLine.kind}`, `The dsh engine (${driftLine.versions.join(' / ')}) does not match the validated ${UPSTREAM_VALIDATED_VERSION}; reinstall via npm i -g @deepseek-ai/dsh@${UPSTREAM_VALIDATED_VERSION}.`, {
|
|
480
|
+
}, children: _jsx(Box, { width: WHALE_BOX_WIDTH, flexDirection: "column", alignItems: "center", children: brand === 'deepseek' && mascotSkin !== undefined ? (_jsx(SplashMascot, { skin: mascotSkin, active: !whaleFrozen && whaleIdle, imageBox: imageBox })) : portraitMode ? (_jsx(Box, { width: WHALE_BOX_WIDTH, height: textColumnRows, flexDirection: "row", justifyContent: "center", alignItems: "center", children: maidImageActive ? (_jsx(MaidPortrait, { source: maidHappy ? (portraits?.happy ?? maidSource) : maidSource, maxColumns: WHALE_BOX_WIDTH, maxRows: textColumnRows, presentation: "transcript" })) : (claudeArt ? _jsx(ClaudeGirlArt, { width: WHALE_BOX_WIDTH }) : _jsx(WhaleGirlArt, { width: WHALE_BOX_WIDTH })) })) : (_jsx(WhaleArt, { frameIndex: frameIndex, pose: settled && whaleIdle && !whaleFrozen ? (idlePose ?? RESTING_POSE) : undefined, width: WHALE_BOX_WIDTH })) }) })), (showBigTitle || showPlainTitle) && (_jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [chrome !== 'minimal' && (_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] })), showBigTitle ? (_jsxs(_Fragment, { children: [bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `ds-${index}`))), _jsx(Box, { height: 1 }), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `h-${index}`)))] })) : (showPlainTitle && (_jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: words.plain }))), chrome !== 'minimal' && (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), getLang() === 'zh' ? randomTip.zh : randomTip.en, _jsx(Text, { dimColor: true, children: ' · /tips ' + tr('logo-tip-more') })] })] })), chrome !== 'minimal' && driftLine != null && (_jsxs(Text, { color: "warning", wrap: "wrap", children: ["\u26A0", ' ', tOr(`logo-drift-${driftLine.kind}`, `The dsh engine (${driftLine.versions.join(' / ')}) does not match the validated ${UPSTREAM_VALIDATED_VERSION}; reinstall via npm i -g @deepseek-ai/dsh@${UPSTREAM_VALIDATED_VERSION}.`, {
|
|
479
481
|
installed: driftLine.versions.join(' / '),
|
|
480
482
|
validated: UPSTREAM_VALIDATED_VERSION,
|
|
481
483
|
primary: UPSTREAM_VALIDATED_VERSION,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,UAAU,CAAA;AAE3E,OAAO,KAAK,EAAE,OAAO,EAA2E,MAAM,2BAA2B,CAAA;AAEjI,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { Box, Text, useTerminalSize } from '../ui.js';
|
|
|
5
5
|
import { normalizeIdePath } from '../dsh-adapter/ide-channel.js';
|
|
6
6
|
import { Divider } from './design-system/Divider.js';
|
|
7
7
|
import { UserPromptMessage } from './messages/UserPromptMessage.js';
|
|
8
|
+
import { TeamMessageBubble } from './messages/TeamMessageBubble.js';
|
|
8
9
|
import { AssistantTextLeafRow, ThinkingLeafRow, ToolLeafRow } from './messages/TranscriptLeaves.js';
|
|
9
10
|
import { liveOutputMaxLines, liveOutputRows } from './messages/liveOutputLines.js';
|
|
10
11
|
import { SubagentMessage } from './Chat/SubagentMessage.js';
|
|
@@ -79,6 +80,16 @@ const NOOP_TOGGLE_STREAM_VIEW = (_rowId) => { };
|
|
|
79
80
|
// replayed history paints complete); once created, a cursor keeps revealing
|
|
80
81
|
// until it catches up — settling mid-reveal must not snap (that is the
|
|
81
82
|
// "non-streaming delivery becomes a smooth flow" contract).
|
|
83
|
+
/** A row that opens a turn on the rail and the pinned header: a user row,
|
|
84
|
+
* but not an Agent Teams peer message (never the human's prompt). */
|
|
85
|
+
function isTurnRow(row) {
|
|
86
|
+
return row.kind === 'user' && row.label !== 'team-message';
|
|
87
|
+
}
|
|
88
|
+
/** The sender a team-message row shows (empty when the event named none);
|
|
89
|
+
* undefined for every other row, which renders as the human's prompt. */
|
|
90
|
+
function teamSenderOf(row) {
|
|
91
|
+
return row.label === 'team-message' ? row.sender ?? '' : undefined;
|
|
92
|
+
}
|
|
82
93
|
function assistantRevealText(row, enabled) {
|
|
83
94
|
const stripped = stripNarration(row.text);
|
|
84
95
|
return revealTextOf(`a${row.id}`, stripped, {
|
|
@@ -263,7 +274,9 @@ function signatureParts(row, columns, expanded, expandedRows, streamViewToggledR
|
|
|
263
274
|
// differ from JS length), not the JS string length — two paths with
|
|
264
275
|
// equal length but different terminal widths must not share a cached
|
|
265
276
|
// height (coderabbit review, repo width convention).
|
|
266
|
-
signatureScratch.push(row.selectionAttached === undefined ? 0 : 1, stringWidth(displaySelectionPath(row.selectionAttached?.path ?? '', sessionCwd)), String(row.selectionAttached?.lines ?? '')
|
|
277
|
+
signatureScratch.push(row.selectionAttached === undefined ? 0 : 1, stringWidth(displaySelectionPath(row.selectionAttached?.path ?? '', sessionCwd)), String(row.selectionAttached?.lines ?? ''),
|
|
278
|
+
// A team message adds its sender line above the body.
|
|
279
|
+
teamSenderOf(row) ?? '');
|
|
267
280
|
// Long-line fold: expanding a folded row swaps the folded preview for
|
|
268
281
|
// the raw line (thousands of rows), so both expansion switches are
|
|
269
282
|
// height inputs on user rows too — same rationale as the default arm.
|
|
@@ -674,11 +687,14 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
674
687
|
parts.length === cachedParts.length &&
|
|
675
688
|
typeof parts[2] === 'number' && typeof cachedParts[2] === 'number' && parts[2] >= cachedParts[2] &&
|
|
676
689
|
parts.every((part, index) => index === 2 || part === cachedParts[index]);
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
//
|
|
680
|
-
|
|
690
|
+
// Keep a mounted row's estimate until the fresh Yoga read: falling back
|
|
691
|
+
// here could eject still-visible rows from this render's mount window.
|
|
692
|
+
// An unmounted row really paints the fallback spacer until it remounts.
|
|
693
|
+
// Retaining an estimate must never skip the next fresh measurement.
|
|
694
|
+
if (localRefs.current.has(row.id))
|
|
681
695
|
growingStreamNeedsMeasure = true;
|
|
696
|
+
else if (!growingStream)
|
|
697
|
+
heightsRef.current.delete(row.id);
|
|
682
698
|
heightsVersionRef.current++;
|
|
683
699
|
}
|
|
684
700
|
}
|
|
@@ -706,11 +722,29 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
706
722
|
offsets[i] = total;
|
|
707
723
|
total += heightOf(visibleRows[i]);
|
|
708
724
|
}
|
|
709
|
-
|
|
725
|
+
// Predict the anchor's signed offset delta before scanning the mount window.
|
|
726
|
+
// A remeasured offscreen spacer must return its provisional shrink, not leave
|
|
727
|
+
// the reader permanently over-corrected. Scan against the corrected position
|
|
728
|
+
// so the anchor stays mounted; the layout effect refines that prediction
|
|
729
|
+
// from fresh Yoga before paint. Never fight following, wheel debt, or a
|
|
730
|
+
// position the user changed. A row below the viewport top (the header's
|
|
731
|
+
// fallback pick) does not own the reader's position.
|
|
732
|
+
const anchorRef = React.useRef(null);
|
|
733
|
+
const scrollTopRaw = scrollHandle?.getScrollTop() ?? 0;
|
|
710
734
|
const pending = scrollHandle?.getPendingDelta() ?? 0;
|
|
711
735
|
const viewport = scrollHandle?.getViewportHeight() ?? 24;
|
|
712
736
|
const sticky = scrollHandle?.isSticky() ?? true;
|
|
713
737
|
const base = baseRef.current ?? DEFAULT_HEADER_LINES;
|
|
738
|
+
const prevAnchor = anchorRef.current;
|
|
739
|
+
let anchorCorrection = 0;
|
|
740
|
+
if (scrollHandle && prevAnchor !== null && prevAnchor.top <= prevAnchor.scrollTop &&
|
|
741
|
+
!sticky && pending === 0 && scrollTopRaw === prevAnchor.scrollTop) {
|
|
742
|
+
const anchored = visibleRows[prevAnchor.index];
|
|
743
|
+
if (anchored !== undefined && anchored.id === prevAnchor.id) {
|
|
744
|
+
anchorCorrection = prevAnchor.top - (base + (offsets[prevAnchor.index] ?? 0));
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
const scrollTop = Math.max(0, scrollTopRaw - anchorCorrection);
|
|
714
748
|
// Mount the union of the committed position and any in-flight pending
|
|
715
749
|
// delta, plus overscan; when sticky, always reach the tail (streaming row).
|
|
716
750
|
const relTop = Math.min(scrollTop, scrollTop + pending) - OVERSCAN_LINES - base;
|
|
@@ -992,7 +1026,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
992
1026
|
const measuredTops = new Map();
|
|
993
1027
|
for (let i = 0; i < visibleRows.length; i++) {
|
|
994
1028
|
const row = visibleRows[i];
|
|
995
|
-
if (row
|
|
1029
|
+
if (!isTurnRow(row))
|
|
996
1030
|
continue;
|
|
997
1031
|
measuredTops.set(row.id, base + offsets[i] + (margins.get(row.id) === true ? 1 : 0));
|
|
998
1032
|
}
|
|
@@ -1005,7 +1039,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1005
1039
|
// click goes through the reveal path, not scrollTo).
|
|
1006
1040
|
const turns = [];
|
|
1007
1041
|
for (const row of rows) {
|
|
1008
|
-
if (row
|
|
1042
|
+
if (!isTurnRow(row))
|
|
1009
1043
|
continue;
|
|
1010
1044
|
let cached = previewCache.get(row.id);
|
|
1011
1045
|
const imageCount = row.images?.length ?? 0;
|
|
@@ -1096,6 +1130,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1096
1130
|
lastTimelineReportRef.current = timeline;
|
|
1097
1131
|
onTimeline?.(timeline);
|
|
1098
1132
|
});
|
|
1133
|
+
// Scroll anchoring, commit half of the render-time pass above.
|
|
1099
1134
|
// Post-commit: measure mounted rows, derive the content-space base from
|
|
1100
1135
|
// the first mounted row's Yoga top, and clamp render-time scrollTop to the
|
|
1101
1136
|
// mounted coverage so burst scrolls never show blank spacer.
|
|
@@ -1132,6 +1167,14 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1132
1167
|
}
|
|
1133
1168
|
}
|
|
1134
1169
|
if (scrollHandle) {
|
|
1170
|
+
// Fresh bounds must move with a prefix's real height, too: an estimated
|
|
1171
|
+
// max can otherwise clamp away a positive correction larger than overscan.
|
|
1172
|
+
const mountedTop = top ?? base + topPad;
|
|
1173
|
+
const lastMounted = visibleRows[end - 1];
|
|
1174
|
+
const lastYoga = lastMounted ? localRefs.current.get(lastMounted.id)?.yogaNode : undefined;
|
|
1175
|
+
const mountedEnd = lastYoga === undefined
|
|
1176
|
+
? base + mountedBottom
|
|
1177
|
+
: lastYoga.getComputedTop() + lastYoga.getComputedHeight();
|
|
1135
1178
|
if (sticky || (start === 0 && end >= visibleRows.length)) {
|
|
1136
1179
|
// Sticky still needs the MIN clamp: the first wheel-up breaks sticky
|
|
1137
1180
|
// on the DOM (ScrollBox.scrollBy) several frames before React
|
|
@@ -1141,11 +1184,12 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1141
1184
|
// behavior as the steady-state scroll path. The MAX clamp stays
|
|
1142
1185
|
// disabled: sticky follow pushes scrollTop to each frame's new
|
|
1143
1186
|
// maxScroll, which a stale mounted max would clamp away.
|
|
1144
|
-
const min = start > 0 ? Math.max(0,
|
|
1187
|
+
const min = start > 0 ? Math.max(0, mountedTop - viewport) : undefined;
|
|
1145
1188
|
scrollHandle.setClampBounds(min, undefined);
|
|
1146
1189
|
}
|
|
1147
1190
|
else {
|
|
1148
|
-
|
|
1191
|
+
// With no top spacer, the mounted header must remain reachable at Home.
|
|
1192
|
+
const min = start > 0 ? Math.max(0, mountedTop - viewport) : 0;
|
|
1149
1193
|
// Upper clamp only while unmounted content remains below the window
|
|
1150
1194
|
// (bottomPad spacer): it exists to pin the paint to the mounted edge
|
|
1151
1195
|
// during burst scrolls that outrun React's window re-render. Once the
|
|
@@ -1156,8 +1200,45 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1156
1200
|
// would then cull the last line at every non-sticky paint — the
|
|
1157
1201
|
// scrolled-away-and-back tail loss. Leave the max open; the renderer
|
|
1158
1202
|
// still caps at the frame's real maxScroll.
|
|
1159
|
-
scrollHandle.setClampBounds(min, bottomPad <= 0 ? undefined : Math.max(min,
|
|
1203
|
+
scrollHandle.setClampBounds(min, bottomPad <= 0 ? undefined : Math.max(min, mountedEnd - viewport));
|
|
1204
|
+
}
|
|
1205
|
+
// Yoga is fresh even when this render retained an old height estimate.
|
|
1206
|
+
// Refine the prediction before paint, not on the later measure tick, and
|
|
1207
|
+
// recheck input intent in case scrolling moved between render and commit.
|
|
1208
|
+
const anchorBase = baseRef.current ?? base;
|
|
1209
|
+
let anchoredTop = scrollHandle.getScrollTop();
|
|
1210
|
+
if (prevAnchor !== null && prevAnchor.top <= prevAnchor.scrollTop &&
|
|
1211
|
+
visibleRows[prevAnchor.index]?.id === prevAnchor.id &&
|
|
1212
|
+
!scrollHandle.isSticky() && scrollHandle.getPendingDelta() === 0 &&
|
|
1213
|
+
anchoredTop === prevAnchor.scrollTop) {
|
|
1214
|
+
const measuredTop = localRefs.current.get(prevAnchor.id)?.yogaNode?.getComputedTop();
|
|
1215
|
+
const correction = measuredTop === undefined ? anchorCorrection : prevAnchor.top - measuredTop;
|
|
1216
|
+
if (correction !== 0) {
|
|
1217
|
+
scrollHandle.anchorBy(-correction);
|
|
1218
|
+
anchoredTop = scrollHandle.getScrollTop();
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
else if (anchorCorrection !== 0) {
|
|
1222
|
+
changed = true;
|
|
1223
|
+
}
|
|
1224
|
+
// Pick and record in the same fresh coordinates as the correction.
|
|
1225
|
+
// Recording old offsets after a fresh read would consume that delta again.
|
|
1226
|
+
let pick = start;
|
|
1227
|
+
let pickedTop = anchorBase + (offsets[start] ?? 0);
|
|
1228
|
+
for (let i = start; i < end; i++) {
|
|
1229
|
+
const row = visibleRows[i];
|
|
1230
|
+
const rowTop = localRefs.current.get(row.id)?.yogaNode?.getComputedTop() ?? anchorBase + (offsets[i] ?? 0);
|
|
1231
|
+
if (i === start || rowTop <= anchoredTop) {
|
|
1232
|
+
pick = i;
|
|
1233
|
+
pickedTop = rowTop;
|
|
1234
|
+
}
|
|
1235
|
+
if (rowTop > anchoredTop)
|
|
1236
|
+
break;
|
|
1160
1237
|
}
|
|
1238
|
+
const picked = visibleRows[pick];
|
|
1239
|
+
anchorRef.current = picked === undefined
|
|
1240
|
+
? null
|
|
1241
|
+
: { id: picked.id, index: pick, top: pickedTop, scrollTop: anchoredTop };
|
|
1161
1242
|
}
|
|
1162
1243
|
if ((changed || growingStreamNeedsMeasure) && measureTimerRef.current === null) {
|
|
1163
1244
|
// Layout corrections can cascade for many rows. Yield to the next
|
|
@@ -1229,7 +1310,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
|
|
|
1229
1310
|
else if (row.kind === 'reasoning' && smoothStreaming) {
|
|
1230
1311
|
displayText = revealTextOf(`r${row.id}`, row.text, { enabled: true, active: displayStreaming });
|
|
1231
1312
|
}
|
|
1232
|
-
return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: displayText, interruptBackend: row.interruptBackend, images: row.images, textFull: row.kind === 'reasoning' ? row.text : undefined, executionTarget: row.executionTarget, selectionAttached: row.selectionAttached, streaming: displayStreaming, thinkingOpen: row.thinkingOpen === true, durationMs: row.durationMs, reasoningTokens: row.reasoningTokens, time: row.time, marginTopOnTurn: marginTopOnTurn, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, smoothStreaming: smoothStreaming, fresh: row.fresh === true, revealVersion: revealVersion, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, toolSourceFolded: row.folded === true, toolLiveOutput: tool?.liveOutput, toolLiveOutputDropped: tool?.liveOutputDropped, fullscreen: fullscreen, turnUsage: row.turnUsage, subagent: subagent, job: job, jobGroup: jobGroup, onToggleRow: onToggleRow, onToggleStreamView: onToggleStreamView, streamViewToggled: streamViewToggledRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenSubagentView: onOpenSubagentView, onOpenJobs: onOpenJobs, onWatchJobOutput: onWatchJobOutput, onOpenFile: onOpenFile, sessionCwd: sessionCwd, onPreviewImage: onPreviewImage, suppressImageGraphics: suppressImageGraphics, setRowRef: setRowRef }, row.id));
|
|
1313
|
+
return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: displayText, interruptBackend: row.interruptBackend, images: row.images, textFull: row.kind === 'reasoning' ? row.text : undefined, executionTarget: row.executionTarget, selectionAttached: row.selectionAttached, sender: teamSenderOf(row), streaming: displayStreaming, thinkingOpen: row.thinkingOpen === true, durationMs: row.durationMs, reasoningTokens: row.reasoningTokens, time: row.time, marginTopOnTurn: marginTopOnTurn, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, smoothStreaming: smoothStreaming, fresh: row.fresh === true, revealVersion: revealVersion, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, toolSourceFolded: row.folded === true, toolLiveOutput: tool?.liveOutput, toolLiveOutputDropped: tool?.liveOutputDropped, fullscreen: fullscreen, turnUsage: row.turnUsage, subagent: subagent, job: job, jobGroup: jobGroup, onToggleRow: onToggleRow, onToggleStreamView: onToggleStreamView, streamViewToggled: streamViewToggledRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenSubagentView: onOpenSubagentView, onOpenJobs: onOpenJobs, onWatchJobOutput: onWatchJobOutput, onOpenFile: onOpenFile, sessionCwd: sessionCwd, onPreviewImage: onPreviewImage, suppressImageGraphics: suppressImageGraphics, setRowRef: setRowRef }, row.id));
|
|
1233
1314
|
}), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
|
|
1234
1315
|
}
|
|
1235
1316
|
/** Load-earlier / show-previous divider row with a mouse hover tint — the
|
|
@@ -1238,7 +1319,7 @@ function ClickableDivider({ title, onClick }) {
|
|
|
1238
1319
|
const [hovered, setHovered] = useState(false);
|
|
1239
1320
|
return (_jsx(Box, { marginTop: 1, onClick: onClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), backgroundColor: hovered ? 'userMessageBackgroundHover' : undefined, children: _jsx(Divider, { title: title }) }));
|
|
1240
1321
|
}
|
|
1241
|
-
function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull, executionTarget, selectionAttached, sessionCwd, streaming, thinkingOpen, durationMs, reasoningTokens, time, marginTopOnTurn, isSelected, isExpanded, expanded, model, diffLayout, smoothStreaming, fresh, revealVersion, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, toolSourceFolded, toolLiveOutput, toolLiveOutputDropped, fullscreen, turnUsage, subagent, job, jobGroup, onToggleRow, onToggleStreamView, streamViewToggled, onOpenSubagent, onOpenSubagentView, onOpenJobs, onWatchJobOutput, onOpenFile, onPreviewImage, suppressImageGraphics, setRowRef, }) {
|
|
1322
|
+
function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull, executionTarget, selectionAttached, sender, sessionCwd, streaming, thinkingOpen, durationMs, reasoningTokens, time, marginTopOnTurn, isSelected, isExpanded, expanded, model, diffLayout, smoothStreaming, fresh, revealVersion, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, toolSourceFolded, toolLiveOutput, toolLiveOutputDropped, fullscreen, turnUsage, subagent, job, jobGroup, onToggleRow, onToggleStreamView, streamViewToggled, onOpenSubagent, onOpenSubagentView, onOpenJobs, onWatchJobOutput, onOpenFile, onPreviewImage, suppressImageGraphics, setRowRef, }) {
|
|
1242
1323
|
const ref = React.useCallback((el) => {
|
|
1243
1324
|
setRowRef(rowId, el);
|
|
1244
1325
|
}, [setRowRef, rowId]);
|
|
@@ -1297,7 +1378,7 @@ function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull,
|
|
|
1297
1378
|
lines: selectionAttached.lines,
|
|
1298
1379
|
count: selectionAttached.lines,
|
|
1299
1380
|
path: displaySelectionPath(selectionAttached.path, sessionCwd),
|
|
1300
|
-
})] })), text !== '' && (_jsx(UserPromptMessage, { text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), images !== undefined && (_jsx(Box, { marginTop: text === '' && marginTopOnTurn ? 1 : 0, children: _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics }) }))] }));
|
|
1381
|
+
})] })), text !== '' && sender !== undefined && (_jsx(TeamMessageBubble, { sender: sender, text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), text !== '' && sender === undefined && (_jsx(UserPromptMessage, { text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), images !== undefined && (_jsx(Box, { marginTop: text === '' && marginTopOnTurn ? 1 : 0, children: _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics }) }))] }));
|
|
1301
1382
|
case 'assistant':
|
|
1302
1383
|
return streaming ? (_jsxs(Box, { alignItems: "flex-start", flexDirection: "row", marginTop: marginTopOnTurn ? 1 : 0, width: "100%", backgroundColor: background, ref: ref, onClick: foldClickable ? foldOnClick : undefined, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: "text", children: "\u25CF" }) }), _jsxs(Box, { flexDirection: "column", children: [_jsx(StreamingMarkdown, { children: stripNarration(displayText) }), images !== undefined && _jsx(TranscriptImages, { images: images, indent: 0, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics })] })] })) : (_jsxs(Box, { width: "100%", flexDirection: "column", backgroundColor: background, ref: ref, onClick: foldClickable ? foldOnClick : undefined, children: [expanded && (_jsx(Box, { flexDirection: "row", justifyContent: "flex-end", gap: 1, marginTop: 1, children: _jsx(MessageMetadata, { timestamp: time, model: model }) })), _jsx(AssistantTextLeafRow, { text: stripNarration(displayText), marginTopOnTurn: marginTopOnTurn, isSelected: isSelected, isExpanded: isExpanded }), images !== undefined && _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics })] }));
|
|
1303
1384
|
case 'reasoning': {
|
|
@@ -7,14 +7,23 @@ import type { PermissionPresetOption } from '../dsh-adapter/channel.js';
|
|
|
7
7
|
* `/permission <preset>` through the same external-command path a hand-typed
|
|
8
8
|
* argument takes. The roster comes from the adapter snapshot so host plugins
|
|
9
9
|
* can contribute additional preset identities without UI changes.
|
|
10
|
+
*
|
|
11
|
+
* DSH's experimental `auto` preset is tagged EXP, and picking it first shows
|
|
12
|
+
* a session-scoped risk confirmation (`confirming`); Chat owns the keys.
|
|
10
13
|
*/
|
|
11
|
-
export declare function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }: {
|
|
14
|
+
export declare function PermissionsPicker({ options, focusIndex, currentValue, cwd, confirming, onPick, onConfirm, onCancelConfirm, }: {
|
|
12
15
|
options: readonly PermissionPresetOption[];
|
|
13
16
|
focusIndex: number;
|
|
14
17
|
currentValue: string | undefined;
|
|
15
18
|
cwd: string;
|
|
19
|
+
/** Show the Auto review risk confirmation instead of the list. */
|
|
20
|
+
confirming?: boolean;
|
|
16
21
|
/** Mouse pick (fullscreen): clicked row's absolute index (Chat applies
|
|
17
22
|
* the same code path as the keyboard Enter). */
|
|
18
23
|
onPick?: (index: number) => void;
|
|
24
|
+
/** Mouse confirm / back on the risk confirmation (fullscreen); the
|
|
25
|
+
* keyboard path stays Enter / Esc in Chat. */
|
|
26
|
+
onConfirm?: () => void;
|
|
27
|
+
onCancelConfirm?: () => void;
|
|
19
28
|
}): React.ReactNode;
|
|
20
29
|
//# sourceMappingURL=PermissionsPicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAEvE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,UAAU,EACV,YAAY,EACZ,GAAG,EACH,UAAkB,EAClB,MAAM,EACN,SAAS,EACT,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC;mDAC+C;IAC/C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAC7B,GAAG,KAAK,CAAC,SAAS,CA+BlB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { t } from '../i18n.js';
|
|
3
|
+
import { PERMISSION_PRESET_AUTO, permissionPresetDescription, permissionPresetLabel } from '../permissionPresetLabels.js';
|
|
3
4
|
import { Box, Text } from '../ui.js';
|
|
4
5
|
import { Pane } from './design-system/Pane.js';
|
|
5
6
|
import { Select } from './Select.js';
|
|
@@ -11,23 +12,30 @@ import { HintLine } from './design-system/HintLine.js';
|
|
|
11
12
|
* `/permission <preset>` through the same external-command path a hand-typed
|
|
12
13
|
* argument takes. The roster comes from the adapter snapshot so host plugins
|
|
13
14
|
* can contribute additional preset identities without UI changes.
|
|
15
|
+
*
|
|
16
|
+
* DSH's experimental `auto` preset is tagged EXP, and picking it first shows
|
|
17
|
+
* a session-scoped risk confirmation (`confirming`); Chat owns the keys.
|
|
14
18
|
*/
|
|
15
|
-
export function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }) {
|
|
19
|
+
export function PermissionsPicker({ options, focusIndex, currentValue, cwd, confirming = false, onPick, onConfirm, onCancelConfirm, }) {
|
|
20
|
+
if (confirming)
|
|
21
|
+
return _jsx(AutoReviewConfirm, { onConfirm: onConfirm, onCancel: onCancelConfirm });
|
|
16
22
|
return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('permission-picker-title') }) }), _jsx(Select, { options: options.map(option => ({
|
|
17
23
|
value: option.value,
|
|
18
|
-
label: option.value ===
|
|
19
|
-
? t('permission-preset-
|
|
20
|
-
: option
|
|
21
|
-
|
|
22
|
-
: option.value === 'danger-full-access'
|
|
23
|
-
? t('permission-preset-full-access')
|
|
24
|
-
: option.name,
|
|
25
|
-
description: option.value === 'read-only'
|
|
26
|
-
? t('permission-preset-readonly-desc')
|
|
27
|
-
: option.value === 'workspace-write'
|
|
28
|
-
? t('permission-preset-workspace-write-desc')
|
|
29
|
-
: option.value === 'danger-full-access'
|
|
30
|
-
? t('permission-preset-full-access-desc')
|
|
31
|
-
: option.description ?? option.name,
|
|
24
|
+
label: option.value === PERMISSION_PRESET_AUTO
|
|
25
|
+
? _jsxs(_Fragment, { children: [permissionPresetLabel(option), " ", _jsx(Text, { color: "warning", children: t('permission-preset-exp-tag') })] })
|
|
26
|
+
: permissionPresetLabel(option),
|
|
27
|
+
description: permissionPresetDescription(option),
|
|
32
28
|
})), focusIndex: focusIndex, selectedValue: currentValue, onPick: onPick ? index => onPick(index) : undefined }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) }), _jsx(Text, { dimColor: true, children: t('permission-root-hint', { cwd }) })] }) }));
|
|
33
29
|
}
|
|
30
|
+
const AUTO_CONFIRM_POINTS = [
|
|
31
|
+
'permission-auto-confirm-session',
|
|
32
|
+
'permission-auto-confirm-sandbox',
|
|
33
|
+
'permission-auto-confirm-cost',
|
|
34
|
+
'permission-auto-confirm-risk',
|
|
35
|
+
];
|
|
36
|
+
function AutoReviewConfirm({ onConfirm, onCancel, }) {
|
|
37
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "warning", bold: true, children: t('permission-auto-confirm-title') }) }), AUTO_CONFIRM_POINTS.map(key => (_jsxs(Box, { children: [_jsx(Text, { children: "\u00B7 " }), _jsx(Box, { flexShrink: 1, children: _jsx(Text, { children: t(key) }) })] }, key))), onConfirm !== undefined && onCancel !== undefined && (_jsx(Box, { marginTop: 1, children: _jsx(Select, { options: [
|
|
38
|
+
{ value: 'enable', label: t('permission-auto-confirm-enable') },
|
|
39
|
+
{ value: 'back', label: t('permission-auto-confirm-back') },
|
|
40
|
+
], focusIndex: 0, selectedValue: undefined, onPick: index => (index === 0 ? onConfirm() : onCancel()) }) }))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('permission-auto-confirm-actions') }) })] }));
|
|
41
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PluginInstallStep } from '../dsh-adapter/plugin-install.js';
|
|
3
|
+
/**
|
|
4
|
+
* `/plugin install <spec>`: the pane that asks what the flow cannot answer on
|
|
5
|
+
* its own (Stage C-4).
|
|
6
|
+
*
|
|
7
|
+
* The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
|
|
8
|
+
* into the transcript as it happens — the inspection, pnpm's phases, the result
|
|
9
|
+
* — so this pane only carries the two things a person must decide before that:
|
|
10
|
+
* gate 1's pre-install notice and gate 3's trust confirmation. It also renders
|
|
11
|
+
* the two "decide and retry" steps (unapproved build scripts, an incompatible
|
|
12
|
+
* version), which are the same kind of question.
|
|
13
|
+
*
|
|
14
|
+
* Presentational only: the step state lives in Chat, keys are handled there
|
|
15
|
+
* (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
|
|
16
|
+
*/
|
|
17
|
+
export declare function PluginInstallPane({ step, busy }: {
|
|
18
|
+
step: PluginInstallStep;
|
|
19
|
+
busy: boolean;
|
|
20
|
+
}): React.ReactNode;
|
|
21
|
+
//# sourceMappingURL=PluginInstallPane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PluginInstallPane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginInstallPane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,iBAAiB,EAAqB,MAAM,kCAAkC,CAAA;AAqB5F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAgF7G"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { Box, Text } from '../ui.js';
|
|
4
|
+
import { cleanRenderText, NOTICE_CELLS } from '../channel/sanitize.js';
|
|
5
|
+
import { HintLine } from './design-system/HintLine.js';
|
|
6
|
+
import { LoadingState } from './design-system/LoadingState.js';
|
|
7
|
+
import { Pane } from './design-system/Pane.js';
|
|
8
|
+
/** Foreign text on its way to the screen: control sequences stripped, bounded. */
|
|
9
|
+
const clean = (value) => cleanRenderText(value, NOTICE_CELLS);
|
|
10
|
+
/**
|
|
11
|
+
* The target's identity is the subject of the confirmation, and it is foreign
|
|
12
|
+
* text like everything else here: the name comes from the package's own
|
|
13
|
+
* manifest, so it can carry newlines or thousands of cells. Bounded to what a
|
|
14
|
+
* line can show — at 50 columns an unbounded name buries the title and the key
|
|
15
|
+
* hints, which are exactly what the person needs to answer the question.
|
|
16
|
+
*/
|
|
17
|
+
const TARGET_CELLS = 80;
|
|
18
|
+
/**
|
|
19
|
+
* `/plugin install <spec>`: the pane that asks what the flow cannot answer on
|
|
20
|
+
* its own (Stage C-4).
|
|
21
|
+
*
|
|
22
|
+
* The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
|
|
23
|
+
* into the transcript as it happens — the inspection, pnpm's phases, the result
|
|
24
|
+
* — so this pane only carries the two things a person must decide before that:
|
|
25
|
+
* gate 1's pre-install notice and gate 3's trust confirmation. It also renders
|
|
26
|
+
* the two "decide and retry" steps (unapproved build scripts, an incompatible
|
|
27
|
+
* version), which are the same kind of question.
|
|
28
|
+
*
|
|
29
|
+
* Presentational only: the step state lives in Chat, keys are handled there
|
|
30
|
+
* (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
|
|
31
|
+
*/
|
|
32
|
+
export function PluginInstallPane({ step, busy }) {
|
|
33
|
+
if (busy) {
|
|
34
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsx(Box, { marginTop: 1, children: _jsx(LoadingState, { message: t('plugins-install-installing') }) })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-cancel') }) })] }));
|
|
35
|
+
}
|
|
36
|
+
if (step.kind === 'confirm') {
|
|
37
|
+
const { artifact, trust, notice } = step;
|
|
38
|
+
const spec = artifact.name === undefined
|
|
39
|
+
? t('plugins-install-unidentified')
|
|
40
|
+
: cleanRenderText(`${artifact.name}${artifact.version === undefined ? '' : `@${artifact.version}`}`, TARGET_CELLS);
|
|
41
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }) }), _jsx(Text, { children: t('plugins-install-configure', {
|
|
42
|
+
spec,
|
|
43
|
+
kind: artifact.kind,
|
|
44
|
+
bundle: artifact.bundle === true ? 'bundle' : artifact.bundle === false ? 'not a bundle' : 'unknown',
|
|
45
|
+
}) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [trust.kind === 'third-party' && _jsx(Text, { children: t('plugins-install-trust-third-party') }), notice.kind === 'declared' && _jsx(Text, { dimColor: true, children: t('plugins-install-notice-declared') }), notice.kind === 'undeclared' && _jsx(Text, { children: t('plugins-install-notice-undeclared') }), notice.kind === 'invalid' && _jsx(Text, { children: t('plugins-install-notice-invalid', { err: notice.error }) }), notice.kind === 'unjudged' && _jsx(Text, { children: t('plugins-install-notice-unjudged') })] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-confirm') }) })] }));
|
|
46
|
+
}
|
|
47
|
+
if (step.kind === 'build-blocked') {
|
|
48
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-builds-title') }), step.builds.map(build => _jsx(Text, { dimColor: true, children: ` ${clean(build)}` }, build))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-builds') }) })] }));
|
|
49
|
+
}
|
|
50
|
+
if (step.kind === 'incompatible') {
|
|
51
|
+
return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-incompatible-title') }), step.packages.map(entry => _jsx(Text, { dimColor: true, children: describe(entry) }, `${entry.name}@${entry.version}`))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-exemptions-title') }), exemptionLines(step.exemptions).map((line, index) => _jsx(Text, { dimColor: true, children: line }, index))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-incompatible') }) })] }));
|
|
52
|
+
}
|
|
53
|
+
// `done` never renders: its lines are already in the transcript, so Chat
|
|
54
|
+
// closes the pane instead of leaving an empty box behind.
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* One package the running host refuses, with the peers it fails.
|
|
59
|
+
*
|
|
60
|
+
* Every field here is foreign text — a package name, a version, a peer range
|
|
61
|
+
* the author wrote — and the pane is a render path like any other, so each one
|
|
62
|
+
* goes through the same sanitizer the rest of the interface uses before it can
|
|
63
|
+
* reach the screen.
|
|
64
|
+
*/
|
|
65
|
+
function describe(entry) {
|
|
66
|
+
const peers = Object.entries(entry.peers)
|
|
67
|
+
.map(([name, range]) => `${clean(name)} ${clean(range)}`)
|
|
68
|
+
.join(', ');
|
|
69
|
+
return ` ${clean(entry.name)}@${clean(entry.version)} (running ${clean(entry.runtimeVersion)}${peers === '' ? '' : `; needs ${peers}`})`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The profile's compatibility file as rows. The file maps `package@version` to
|
|
73
|
+
* the runtime versions exempted for it, and a corrupt one answers warnings
|
|
74
|
+
* instead — both shapes are the person's business here, because this is the
|
|
75
|
+
* step where they decide whether to add another. The file is user-editable and
|
|
76
|
+
* carries whatever somebody typed, so its rows are sanitized too.
|
|
77
|
+
*/
|
|
78
|
+
function exemptionLines(exemptions) {
|
|
79
|
+
const rows = Object.entries(exemptions.exemptions)
|
|
80
|
+
.map(([packageVersion, runtimes]) => ` ${clean(packageVersion)} → ${runtimes.map(runtime => clean(runtime)).join(', ')}`);
|
|
81
|
+
if (rows.length === 0 && exemptions.warnings.length === 0)
|
|
82
|
+
return [` ${t('plugins-info-registries-none')}`];
|
|
83
|
+
return [...rows, ...exemptions.warnings.map(warning => ` ${clean(warning)}`)];
|
|
84
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PluginManageStep } from '../dsh-adapter/plugin-manage.js';
|
|
3
|
+
/**
|
|
4
|
+
* `/plugin remove | enable | disable`: the pane that asks what the flow cannot
|
|
5
|
+
* answer on its own (Stage C-5).
|
|
6
|
+
*
|
|
7
|
+
* The flow (`dsh-adapter/plugin-manage.ts`) writes every line of the action into
|
|
8
|
+
* the transcript — what it resolved, why it refused, what the service answered —
|
|
9
|
+
* so this pane only carries the one thing a person must decide before the write.
|
|
10
|
+
* Unlike the install pane there is no progress, no cancellation and no retry:
|
|
11
|
+
* each action is a single call that settles once.
|
|
12
|
+
*
|
|
13
|
+
* Presentational only, and the same three parts as its install sibling
|
|
14
|
+
* (`PluginInstallPane`): the pane, the facts that make the question answerable,
|
|
15
|
+
* and the key hints. Keys are handled in Chat (Enter answers, Esc closes).
|
|
16
|
+
*/
|
|
17
|
+
export declare function PluginManagePane({ step, busy }: {
|
|
18
|
+
step: PluginManageStep;
|
|
19
|
+
busy: boolean;
|
|
20
|
+
}): React.ReactNode;
|
|
21
|
+
//# sourceMappingURL=PluginManagePane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PluginManagePane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginManagePane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,iCAAiC,CAAA;AAiB3F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAqD3G"}
|