@deepseek-harness-tui/dsh-tui 0.8.3 → 0.8.5
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 +29 -10
- package/bin/dsh-tui.js +50 -11
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
- package/dsh-ecosystem-spec/registry/README.md +14 -14
- package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
- package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
- package/lib/types/activityPrefs.d.ts +10 -0
- package/lib/types/activityPrefs.d.ts.map +1 -1
- package/lib/types/activityPrefs.js +17 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +1 -0
- 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 +8 -3
- package/lib/types/components/MessageList.d.ts +4 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +4 -4
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +1 -3
- package/lib/types/components/SplitDiffView.d.ts +3 -1
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +12 -5
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +10 -2
- package/lib/types/components/TipsPanel.d.ts +14 -0
- package/lib/types/components/TipsPanel.d.ts.map +1 -0
- package/lib/types/components/TipsPanel.js +37 -0
- package/lib/types/components/activityFrames.d.ts +7 -28
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +7 -84
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +4 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +14 -3
- package/lib/types/dsh-adapter/channel.d.ts +17 -0
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +169 -33
- package/lib/types/dsh-adapter/index.d.ts +5 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +19 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +176 -4
- package/lib/types/dsh-adapter/settings-sections.d.ts +13 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +31 -6
- package/lib/types/effortPrefs.d.ts +7 -6
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +7 -6
- package/lib/types/i18n.d.ts +42 -14
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +11 -4
- package/lib/types/ink/ink.d.ts +10 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +35 -1
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +15 -0
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +44 -7
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +109 -50
- package/lib/types/screens/StatusLine.d.ts +8 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +65 -42
- package/lib/types/settings-sections.d.ts +1 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/tips.d.ts +30 -0
- package/lib/types/tips.d.ts.map +1 -0
- package/lib/types/tips.js +575 -0
- package/lib/types/tuiDisplayPrefs.d.ts +47 -0
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -0
- package/lib/types/tuiDisplayPrefs.js +60 -0
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/command/LICENSE +21 -21
- package/node_modules/@dsh-std/command/README.md +26 -26
- package/node_modules/@dsh-std/command/README.zh.md +28 -28
- package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/command/package.json +22 -22
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/node_modules/@dsh-std/connection/README.md +42 -42
- package/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/node_modules/@dsh-std/connection/package.json +20 -20
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/core/LICENSE +21 -21
- package/node_modules/@dsh-std/core/README.md +13 -13
- package/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/core/package.json +21 -21
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/node_modules/@dsh-std/manifest/README.md +5 -5
- package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/manifest/package.json +20 -20
- package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/messages/LICENSE +21 -21
- package/node_modules/@dsh-std/messages/README.md +5 -5
- package/node_modules/@dsh-std/messages/README.zh.md +7 -7
- package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/messages/package.json +20 -20
- package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/node_modules/@dsh-std/presentation/README.md +27 -27
- package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/presentation/package.json +25 -25
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
- package/node_modules/@dsh-std/storage/LICENSE +21 -21
- package/node_modules/@dsh-std/storage/README.md +5 -5
- package/node_modules/@dsh-std/storage/README.zh.md +7 -7
- package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/storage/package.json +20 -20
- package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
- package/package.json +8 -3
- package/presets/liangshen/.dsh-tui-managed.json +1 -1
- package/presets/liangshen/agent.cordis.yml +7 -5
- package/presets/liangshen/custom-bash.mjs +184 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
|
@@ -24,7 +24,10 @@ import { homeDir, LEGACY_DATA_DIR } from '../utils/paths.js';
|
|
|
24
24
|
import { extractMentions } from '../utils/mentions.js';
|
|
25
25
|
import { t } from '../i18n.js';
|
|
26
26
|
import { modeDisplayName, resolveSessionModes } from '../sessionModes.js';
|
|
27
|
+
import { normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
|
|
27
28
|
import { ActivityTracker } from 'dsh-working-activity/status';
|
|
29
|
+
import { featureOn } from 'dsh-working-activity/config';
|
|
30
|
+
import { readActivityConfig } from '../activityPrefs.js';
|
|
28
31
|
import { attachSessionToWorkspace } from './workspace.js';
|
|
29
32
|
import { createLocalWorkspaceRuntime, getHostWorkspaceRuntime } from './workspaces.js';
|
|
30
33
|
import { getHostCommandTrees } from './command-trees.js';
|
|
@@ -968,6 +971,8 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
968
971
|
activityFrames: options.activityFrames,
|
|
969
972
|
diffLayout: options.diffLayout ?? 'auto',
|
|
970
973
|
thinkingFold: options.thinkingFold ?? 'preview',
|
|
974
|
+
toolBackground: normalizeToolBackground(options.toolBackground),
|
|
975
|
+
statusBar: normalizeStatusBar(options.statusBar),
|
|
971
976
|
activityEnabled: options.activity !== false,
|
|
972
977
|
contextBarEnabled: options.contextBar !== false,
|
|
973
978
|
agentPreset: options.agentPreset,
|
|
@@ -1140,14 +1145,12 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1140
1145
|
return 0;
|
|
1141
1146
|
// No keepInbox: the parked copies are dropped (their discard events
|
|
1142
1147
|
// retire the preview), then each text is re-queued as a fresh
|
|
1143
|
-
// followup.
|
|
1144
|
-
//
|
|
1145
|
-
//
|
|
1146
|
-
//
|
|
1147
|
-
// starts the new turn.
|
|
1148
|
+
// followup. dsh-agent's cancel-convergence wake latch accepts this
|
|
1149
|
+
// wake immediately after cancel and starts it once the aborted turn
|
|
1150
|
+
// retires; waiting for whenIdle is unsafe because it also follows
|
|
1151
|
+
// replacement work and may never settle.
|
|
1148
1152
|
agent.cancel({ kind: 'user' });
|
|
1149
1153
|
const token = ++interruptSeq;
|
|
1150
|
-
const whenIdle = agent.whenIdle;
|
|
1151
1154
|
const deliver = () => {
|
|
1152
1155
|
// A second interrupt while the abort is still settling must not
|
|
1153
1156
|
// double-deliver: only the latest request's re-queue runs.
|
|
@@ -1161,14 +1164,10 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1161
1164
|
dispatchUserText(text, 'followup');
|
|
1162
1165
|
}
|
|
1163
1166
|
};
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
// Defensive: a wake while the driver still runs is ignored, so wait
|
|
1169
|
-
// for the abort to settle before re-queueing.
|
|
1170
|
-
setTimeout(deliver, 200);
|
|
1171
|
-
}
|
|
1167
|
+
// Let cancel finish its synchronous inbox bookkeeping before waking.
|
|
1168
|
+
// A microtask also coalesces two same-tick interrupts: only the latest
|
|
1169
|
+
// token survives, so the user's text is never sent twice.
|
|
1170
|
+
queueMicrotask(deliver);
|
|
1172
1171
|
return queued.length;
|
|
1173
1172
|
},
|
|
1174
1173
|
/**
|
|
@@ -1619,10 +1618,16 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1619
1618
|
streaming = undefined;
|
|
1620
1619
|
reasoning = undefined;
|
|
1621
1620
|
// Stale sealed/thinking bookkeeping belongs to the OLD agent's rows;
|
|
1622
|
-
// keep it out of the next turn's settle logs and revive cache.
|
|
1621
|
+
// keep it out of the next turn's settle logs and revive cache. Event
|
|
1622
|
+
// sequence numbers restart in the fresh session, so its dedupe ledgers
|
|
1623
|
+
// must not retain the old session's sequence ids.
|
|
1623
1624
|
sealedReasoning.length = 0;
|
|
1624
1625
|
lastReasoningRow = undefined;
|
|
1625
1626
|
toolCards.clear();
|
|
1627
|
+
handledAssistantMessages.clear();
|
|
1628
|
+
handledAssistantChunks.clear();
|
|
1629
|
+
assistantRowsByStep.clear();
|
|
1630
|
+
lastTextDelta.clear();
|
|
1626
1631
|
nextRowId = 0;
|
|
1627
1632
|
state.rows.length = 0;
|
|
1628
1633
|
// Goal/todo/title are session-scoped; the replay re-derives them for
|
|
@@ -1650,6 +1655,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1650
1655
|
state.tpsSamples = [];
|
|
1651
1656
|
state.lastUsage = undefined;
|
|
1652
1657
|
state.workingActivity = undefined;
|
|
1658
|
+
state.loadedContext = undefined;
|
|
1653
1659
|
state.contextWindow = undefined;
|
|
1654
1660
|
state.contextSegments = {
|
|
1655
1661
|
system: 0,
|
|
@@ -1843,6 +1849,8 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1843
1849
|
agent = handle.agent;
|
|
1844
1850
|
currentHandle = handle;
|
|
1845
1851
|
bindAgent();
|
|
1852
|
+
// Model-switch quip rides the fresh tracker (pi parity).
|
|
1853
|
+
activityTracker.onModelSwitch(model);
|
|
1846
1854
|
refreshCommandList();
|
|
1847
1855
|
void refreshLoadedContext();
|
|
1848
1856
|
void refreshSkillCommands();
|
|
@@ -1919,6 +1927,21 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1919
1927
|
state.thinkingFold = mode;
|
|
1920
1928
|
state.emit();
|
|
1921
1929
|
},
|
|
1930
|
+
setToolBackground(background) {
|
|
1931
|
+
const normalized = normalizeToolBackground(background);
|
|
1932
|
+
if (normalized === state.toolBackground)
|
|
1933
|
+
return;
|
|
1934
|
+
state.toolBackground = normalized;
|
|
1935
|
+
state.emit();
|
|
1936
|
+
},
|
|
1937
|
+
setStatusBar(config) {
|
|
1938
|
+
const next = normalizeStatusBar({ ...state.statusBar, ...config });
|
|
1939
|
+
const changed = Object.keys(next).some(key => next[key] !== state.statusBar[key]);
|
|
1940
|
+
if (!changed)
|
|
1941
|
+
return;
|
|
1942
|
+
state.statusBar = next;
|
|
1943
|
+
state.emit();
|
|
1944
|
+
},
|
|
1922
1945
|
setActivityFrames(name) {
|
|
1923
1946
|
if (!isPresetName(name)) {
|
|
1924
1947
|
state.notify(t('unknown-activity-preset', { name }), { color: 'error' });
|
|
@@ -2324,6 +2347,9 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
2324
2347
|
.compactNow(agent, signal)
|
|
2325
2348
|
.then((result) => {
|
|
2326
2349
|
state.notify(result ? t('compact-done') : t('compact-nothing'));
|
|
2350
|
+
// Compaction quip rides the next thinking rotation (pi parity).
|
|
2351
|
+
if (result)
|
|
2352
|
+
activityTracker.onCompact('done');
|
|
2327
2353
|
})
|
|
2328
2354
|
.catch((error) => {
|
|
2329
2355
|
state.notify(t('compact-failed', { err: error instanceof Error ? error.message : String(error) }), { color: 'error', timeoutMs: 8000 });
|
|
@@ -2989,6 +3015,39 @@ ${output}
|
|
|
2989
3015
|
let tpsStep;
|
|
2990
3016
|
/** Tool cards by callId, so tool/result can settle the running card. */
|
|
2991
3017
|
const toolCards = new Map();
|
|
3018
|
+
/**
|
|
3019
|
+
* Session events are delivered live and can also be replayed around a
|
|
3020
|
+
* reconnect. A repeated sealed message must not create a second assistant
|
|
3021
|
+
* row for the same durable sequence number.
|
|
3022
|
+
*/
|
|
3023
|
+
const handledAssistantMessages = new Set();
|
|
3024
|
+
const handledAssistantChunks = new Set();
|
|
3025
|
+
const assistantRowsByStep = new Map();
|
|
3026
|
+
const lastTextDelta = new Map();
|
|
3027
|
+
const stepKey = (turn, step) => `${turn}:${step}`;
|
|
3028
|
+
/** Append a stream delta idempotently. Providers normally send a pure
|
|
3029
|
+
* delta, but reconnect/proxy paths can resend a cumulative prefix or a
|
|
3030
|
+
* delta whose beginning overlaps the previous tail. Merge the overlap
|
|
3031
|
+
* instead of blindly concatenating it into the visible transcript. */
|
|
3032
|
+
const appendTextDelta = (row, delta) => {
|
|
3033
|
+
if (delta === '')
|
|
3034
|
+
return;
|
|
3035
|
+
if (lastTextDelta.get(row) === delta)
|
|
3036
|
+
return;
|
|
3037
|
+
lastTextDelta.set(row, delta);
|
|
3038
|
+
if (delta.startsWith(row.text)) {
|
|
3039
|
+
row.text = delta;
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
const maxOverlap = Math.min(row.text.length, delta.length, 4096);
|
|
3043
|
+
for (let size = maxOverlap; size > 0; size--) {
|
|
3044
|
+
if (row.text.endsWith(delta.slice(0, size))) {
|
|
3045
|
+
row.text += delta.slice(size);
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
row.text += delta;
|
|
3050
|
+
};
|
|
2992
3051
|
/** The host-plane tools registry (dsh-tools). Resolved once; absent in
|
|
2993
3052
|
* bare embedders — every presenter call soft-fails to undefined and the
|
|
2994
3053
|
* card falls back to raw text. */
|
|
@@ -3040,11 +3099,22 @@ ${output}
|
|
|
3040
3099
|
*/
|
|
3041
3100
|
const firstTextOf = (content) => (content ?? []).find(block => block.type === 'text')?.text.trim() ?? '';
|
|
3042
3101
|
const ensureStreaming = (seq) => {
|
|
3043
|
-
if (streaming
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3102
|
+
if (streaming !== undefined)
|
|
3103
|
+
return streaming;
|
|
3104
|
+
// A reconnect can replay the first delta after the sealed message was
|
|
3105
|
+
// already observed. Reuse that durable row instead of opening a second
|
|
3106
|
+
// assistant bubble for the same event sequence.
|
|
3107
|
+
const existing = seq === undefined
|
|
3108
|
+
? undefined
|
|
3109
|
+
: [...state.rows].reverse().find(row => row.kind === 'assistant' && row.seq === seq);
|
|
3110
|
+
if (existing !== undefined) {
|
|
3111
|
+
existing.streaming = true;
|
|
3112
|
+
streaming = existing;
|
|
3113
|
+
return existing;
|
|
3047
3114
|
}
|
|
3115
|
+
streaming = { id: nextRowId, kind: 'assistant', text: '', streaming: true, ...seq !== undefined ? { seq } : {} };
|
|
3116
|
+
nextRowId += 1;
|
|
3117
|
+
state.rows.push(streaming);
|
|
3048
3118
|
return streaming;
|
|
3049
3119
|
};
|
|
3050
3120
|
/** Latest reasoning row keyed by its (turn, step) — lets a resumed
|
|
@@ -3175,6 +3245,13 @@ ${output}
|
|
|
3175
3245
|
* using it would rebuild a second thinking block per step. */
|
|
3176
3246
|
let replaying = false;
|
|
3177
3247
|
const replayEvents = (events) => {
|
|
3248
|
+
// Event sequence numbers restart with a replacement session; reset the
|
|
3249
|
+
// idempotency ledger before replay so an old session cannot suppress a
|
|
3250
|
+
// legitimate message in the new transcript.
|
|
3251
|
+
handledAssistantMessages.clear();
|
|
3252
|
+
handledAssistantChunks.clear();
|
|
3253
|
+
assistantRowsByStep.clear();
|
|
3254
|
+
lastTextDelta.clear();
|
|
3178
3255
|
replaying = true;
|
|
3179
3256
|
try {
|
|
3180
3257
|
for (const event of prepareReplayEvents(events))
|
|
@@ -3262,6 +3339,9 @@ ${output}
|
|
|
3262
3339
|
break;
|
|
3263
3340
|
}
|
|
3264
3341
|
case 'assistant/chunk': {
|
|
3342
|
+
if (handledAssistantChunks.has(event.seq))
|
|
3343
|
+
break;
|
|
3344
|
+
handledAssistantChunks.add(event.seq);
|
|
3265
3345
|
const chunk = event.data.chunk;
|
|
3266
3346
|
if (chunk.type === 'text-delta') {
|
|
3267
3347
|
if (chunk.text) {
|
|
@@ -3269,13 +3349,20 @@ ${output}
|
|
|
3269
3349
|
// window (see foldLiveReasoning) — before this text grows the
|
|
3270
3350
|
// transcript and pushes the block into scrollback.
|
|
3271
3351
|
foldLiveReasoning('first text token');
|
|
3272
|
-
|
|
3273
|
-
|
|
3352
|
+
const key = stepKey(event.data.turn, event.data.step);
|
|
3353
|
+
const row = assistantRowsByStep.get(key) ?? ensureStreaming(event.seq);
|
|
3354
|
+
assistantRowsByStep.set(key, row);
|
|
3355
|
+
streaming = row;
|
|
3356
|
+
row.streaming = true;
|
|
3357
|
+
const before = row.text.length;
|
|
3358
|
+
appendTextDelta(row, chunk.text);
|
|
3359
|
+
state.responseChars += Math.max(0, row.text.length - before);
|
|
3274
3360
|
}
|
|
3275
3361
|
}
|
|
3276
3362
|
else if (chunk.type === 'reasoning-delta') {
|
|
3277
3363
|
if (chunk.text) {
|
|
3278
|
-
ensureReasoning(event.seq, event.data.turn, event.data.step)
|
|
3364
|
+
const row = ensureReasoning(event.seq, event.data.turn, event.data.step);
|
|
3365
|
+
appendTextDelta(row, chunk.text);
|
|
3279
3366
|
}
|
|
3280
3367
|
}
|
|
3281
3368
|
const step = tpsStep;
|
|
@@ -3296,6 +3383,9 @@ ${output}
|
|
|
3296
3383
|
break;
|
|
3297
3384
|
}
|
|
3298
3385
|
case 'assistant/message': {
|
|
3386
|
+
if (handledAssistantMessages.has(event.seq))
|
|
3387
|
+
break;
|
|
3388
|
+
handledAssistantMessages.add(event.seq);
|
|
3299
3389
|
const text = textOf(event.data.message.content);
|
|
3300
3390
|
// Replay without chunk deltas (prepareReplayEvents drops settled
|
|
3301
3391
|
// ones): rebuild the reasoning row from the sealed message's
|
|
@@ -3325,8 +3415,22 @@ ${output}
|
|
|
3325
3415
|
// anyway leaves an empty `●` bullet in the transcript. A pre-existing
|
|
3326
3416
|
// streaming row always has text (ensureStreaming is only reached on
|
|
3327
3417
|
// non-empty text deltas), so only create one when text arrives.
|
|
3328
|
-
|
|
3418
|
+
// Key the step→row ledger only when the event carries a durable
|
|
3419
|
+
// turn/step; a message without them must never collide onto a
|
|
3420
|
+
// previous step's row (a bare `undefined:undefined` key would make
|
|
3421
|
+
// every turn/step-less message reuse the FIRST one's assistant row).
|
|
3422
|
+
const msgTurn = event.data.turn;
|
|
3423
|
+
const msgStep = event.data.step;
|
|
3424
|
+
const msgKey = msgTurn !== undefined && msgStep !== undefined
|
|
3425
|
+
? stepKey(msgTurn, msgStep)
|
|
3426
|
+
: undefined;
|
|
3427
|
+
const row = (msgKey !== undefined ? assistantRowsByStep.get(msgKey) : undefined) ?? streaming ??
|
|
3428
|
+
(text
|
|
3429
|
+
? ([...state.rows].reverse().find(candidate => candidate.kind === 'assistant' && candidate.seq === event.seq) ?? ensureStreaming(event.seq))
|
|
3430
|
+
: undefined);
|
|
3329
3431
|
if (row !== undefined) {
|
|
3432
|
+
if (msgKey !== undefined)
|
|
3433
|
+
assistantRowsByStep.set(msgKey, row);
|
|
3330
3434
|
row.time = event.time;
|
|
3331
3435
|
if (text)
|
|
3332
3436
|
row.text = text;
|
|
@@ -3622,11 +3726,36 @@ ${output}
|
|
|
3622
3726
|
// Live subscription list and activity timer, rebound to every replacement
|
|
3623
3727
|
// agent so no status from the previous session can leak across a swap.
|
|
3624
3728
|
let agentSubscriptions = [];
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3729
|
+
/** Tracker knobs + custom actions from the persisted pi-style config
|
|
3730
|
+
* (`~/.dsh-tui/working-activity.json`); a missing file means lively
|
|
3731
|
+
* defaults (all eggs on). */
|
|
3732
|
+
const activityPrefsSnapshot = () => {
|
|
3733
|
+
const cfg = readActivityConfig();
|
|
3734
|
+
if (cfg === undefined) {
|
|
3735
|
+
return { config: { phrases: true, detailLimit: 40, showIdle: false } };
|
|
3736
|
+
}
|
|
3737
|
+
return {
|
|
3738
|
+
config: {
|
|
3739
|
+
phrases: featureOn(cfg, 'phrases'),
|
|
3740
|
+
detailLimit: 40,
|
|
3741
|
+
showIdle: false,
|
|
3742
|
+
features: {
|
|
3743
|
+
rareEggs: featureOn(cfg, 'rareEggs'),
|
|
3744
|
+
weekend: featureOn(cfg, 'weekend'),
|
|
3745
|
+
holidays: featureOn(cfg, 'holidays'),
|
|
3746
|
+
nightPhrases: featureOn(cfg, 'nightPhrases'),
|
|
3747
|
+
},
|
|
3748
|
+
customPhrases: cfg.customPhrases,
|
|
3749
|
+
showTokPerSec: cfg.showTokPerSec,
|
|
3750
|
+
workRemindAt: cfg.workRemindAt,
|
|
3751
|
+
},
|
|
3752
|
+
customActions: cfg.customActions,
|
|
3753
|
+
};
|
|
3754
|
+
};
|
|
3755
|
+
let activityTracker = (() => {
|
|
3756
|
+
const prefs = activityPrefsSnapshot();
|
|
3757
|
+
return new ActivityTracker(prefs.config, Date.now, prefs.customActions);
|
|
3758
|
+
})();
|
|
3630
3759
|
let activityTickTimer;
|
|
3631
3760
|
const stopActivityTick = () => {
|
|
3632
3761
|
if (activityTickTimer === undefined)
|
|
@@ -3648,11 +3777,8 @@ ${output}
|
|
|
3648
3777
|
for (const dispose of agentSubscriptions)
|
|
3649
3778
|
dispose();
|
|
3650
3779
|
stopActivityTick();
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
detailLimit: 40,
|
|
3654
|
-
showIdle: false,
|
|
3655
|
-
});
|
|
3780
|
+
const prefs = activityPrefsSnapshot();
|
|
3781
|
+
activityTracker = new ActivityTracker(prefs.config, Date.now, prefs.customActions);
|
|
3656
3782
|
activityTracker.onAgentStatus(agent.status);
|
|
3657
3783
|
renderWorkingActivity();
|
|
3658
3784
|
activityTickTimer = setInterval(() => {
|
|
@@ -3748,6 +3874,14 @@ ${output}
|
|
|
3748
3874
|
// publish never throws into this arm.
|
|
3749
3875
|
messageObserver?.publish(session, event);
|
|
3750
3876
|
activityTracker.onSessionEvent(event);
|
|
3877
|
+
// Interrupt quip: an aborted/interrupted turn ends the round; the
|
|
3878
|
+
// comeback copy shows on the next thinking rotation (pi parity).
|
|
3879
|
+
if (event.type === 'turn/end') {
|
|
3880
|
+
const reason = event.data.reason;
|
|
3881
|
+
if (reason?.kind === 'aborted' || reason?.kind === 'interrupted') {
|
|
3882
|
+
activityTracker.onInterrupted();
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3751
3885
|
renderWorkingActivity();
|
|
3752
3886
|
// Mode-affecting atoms fold into the Shift+Tab mode indicator the
|
|
3753
3887
|
// moment they land (whether appended by cycleMode or by hand).
|
|
@@ -3815,6 +3949,8 @@ ${output}
|
|
|
3815
3949
|
// only show a branch for sessions this install actually used — which
|
|
3816
3950
|
// is exactly what the column claims.
|
|
3817
3951
|
noteBranch(agent.session.id, branch);
|
|
3952
|
+
// Feed the working line so git tools can show ` · git <branch>`.
|
|
3953
|
+
activityTracker.onGitBranch(branch);
|
|
3818
3954
|
state.emit();
|
|
3819
3955
|
}
|
|
3820
3956
|
})
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { Context } from '@deepseek-ai/cordis';
|
|
10
10
|
import Schema from '@deepseek-ai/schemastery';
|
|
11
11
|
import type { SessionModeSpec } from '../sessionModes.js';
|
|
12
|
+
import { type StatusBarConfig, type ToolBackground } from '../tuiDisplayPrefs.js';
|
|
12
13
|
export declare const name = "dsh-tui";
|
|
13
14
|
export declare const inject: string[];
|
|
14
15
|
/**
|
|
@@ -70,6 +71,10 @@ export interface Config {
|
|
|
70
71
|
* preview and folds each step when it settles; `full` keeps thinking
|
|
71
72
|
* expanded until the whole turn ends. Editable live from `/settings`. */
|
|
72
73
|
thinkingFold?: 'preview' | 'full';
|
|
74
|
+
/** Tool-card background strength; defaults to no added background. */
|
|
75
|
+
toolBackground?: ToolBackground;
|
|
76
|
+
/** Status-footer field visibility and compact presentation preferences. */
|
|
77
|
+
statusBar?: Partial<StatusBarConfig>;
|
|
73
78
|
/** Shift+Tab session-mode cycle (array order IS the cycle order; index 0
|
|
74
79
|
* is the unmarked base mode). Each entry bundles any subset of the
|
|
75
80
|
* `plan`/`sandbox`/`approval` atoms; absent → the built-in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAsB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAErG,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,sEAAsE;IACtE,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAA;IACpC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA8ChC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Schema from '@deepseek-ai/schemastery';
|
|
2
|
+
import { DEFAULT_STATUS_BAR } from '../tuiDisplayPrefs.js';
|
|
2
3
|
export const name = 'dsh-tui';
|
|
3
4
|
// `tuiWorkspaces` must stay OUT of this code-level inject (issue #183): the
|
|
4
5
|
// dsh CLI resolves the bundle's cordis.patch.yml from the FIRST copy of this
|
|
@@ -29,6 +30,24 @@ export const Config = Schema.object({
|
|
|
29
30
|
preset: Schema.string().required(false),
|
|
30
31
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
31
32
|
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
33
|
+
toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
|
|
34
|
+
statusBar: Schema.object({
|
|
35
|
+
compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
|
|
36
|
+
model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
|
|
37
|
+
thinking: Schema.boolean().default(DEFAULT_STATUS_BAR.thinking),
|
|
38
|
+
cwd: Schema.boolean().default(DEFAULT_STATUS_BAR.cwd),
|
|
39
|
+
contextUsage: Schema.boolean().default(DEFAULT_STATUS_BAR.contextUsage),
|
|
40
|
+
cache: Schema.boolean().default(DEFAULT_STATUS_BAR.cache),
|
|
41
|
+
tokens: Schema.boolean().default(DEFAULT_STATUS_BAR.tokens),
|
|
42
|
+
tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
|
|
43
|
+
gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
|
|
44
|
+
sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
|
|
45
|
+
mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
|
|
46
|
+
contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
|
|
47
|
+
activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
|
|
48
|
+
trajectory: Schema.boolean().default(DEFAULT_STATUS_BAR.trajectory),
|
|
49
|
+
shortcutHint: Schema.boolean().default(DEFAULT_STATUS_BAR.shortcutHint),
|
|
50
|
+
}).default({ ...DEFAULT_STATUS_BAR }),
|
|
32
51
|
modes: Schema.array(Schema.object({
|
|
33
52
|
id: Schema.string(),
|
|
34
53
|
label: Schema.string().required(false),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAoCnC;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsyBvE;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV"}
|
|
@@ -23,6 +23,7 @@ import { clearResumeTarget, writeResumeTarget } from '../sessionHistory.js';
|
|
|
23
23
|
import { resolveSessionCwd } from '../utils/workspaceRoot.js';
|
|
24
24
|
import { checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isVersionNewer, resolveDshProfileName, resolveTuiUpdateTarget, updateTuiAndRestart } from '../update.js';
|
|
25
25
|
import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
|
|
26
|
+
import { DEFAULT_STATUS_BAR, normalizeStatusBar, normalizeToolBackground } from '../tuiDisplayPrefs.js';
|
|
26
27
|
import { detectLegacyEnv, migrateLegacyDataDir, RENAMED_ENV } from '../utils/paths.js';
|
|
27
28
|
import { Chat } from '../screens/Chat.js';
|
|
28
29
|
import { getHostDialogStore } from './dialogs.js';
|
|
@@ -326,6 +327,8 @@ export async function apply(ctx, config) {
|
|
|
326
327
|
// screen edits this key live through the dsh-tui namespace.
|
|
327
328
|
diffLayout: config.diffLayout,
|
|
328
329
|
thinkingFold: config.thinkingFold,
|
|
330
|
+
toolBackground: config.toolBackground,
|
|
331
|
+
statusBar: config.statusBar,
|
|
329
332
|
handle,
|
|
330
333
|
});
|
|
331
334
|
// Register the dsh-tui settings namespace so the /settings screen can
|
|
@@ -336,6 +339,24 @@ export async function apply(ctx, config) {
|
|
|
336
339
|
const scope = settingsCtx.settings.register(settingsNamespace('dsh-tui'), Schema.object({
|
|
337
340
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
338
341
|
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
342
|
+
toolBackground: Schema.union(['none', 'subtle', 'strong']).default('none'),
|
|
343
|
+
statusBar: Schema.object({
|
|
344
|
+
compact: Schema.boolean().default(DEFAULT_STATUS_BAR.compact),
|
|
345
|
+
model: Schema.boolean().default(DEFAULT_STATUS_BAR.model),
|
|
346
|
+
thinking: Schema.boolean().default(DEFAULT_STATUS_BAR.thinking),
|
|
347
|
+
cwd: Schema.boolean().default(DEFAULT_STATUS_BAR.cwd),
|
|
348
|
+
contextUsage: Schema.boolean().default(DEFAULT_STATUS_BAR.contextUsage),
|
|
349
|
+
cache: Schema.boolean().default(DEFAULT_STATUS_BAR.cache),
|
|
350
|
+
tokens: Schema.boolean().default(DEFAULT_STATUS_BAR.tokens),
|
|
351
|
+
tps: Schema.boolean().default(DEFAULT_STATUS_BAR.tps),
|
|
352
|
+
gitBranch: Schema.boolean().default(DEFAULT_STATUS_BAR.gitBranch),
|
|
353
|
+
sessionTitle: Schema.boolean().default(DEFAULT_STATUS_BAR.sessionTitle),
|
|
354
|
+
mode: Schema.boolean().default(DEFAULT_STATUS_BAR.mode),
|
|
355
|
+
contextBar: Schema.boolean().default(DEFAULT_STATUS_BAR.contextBar),
|
|
356
|
+
activity: Schema.boolean().default(DEFAULT_STATUS_BAR.activity),
|
|
357
|
+
trajectory: Schema.boolean().default(DEFAULT_STATUS_BAR.trajectory),
|
|
358
|
+
shortcutHint: Schema.boolean().default(DEFAULT_STATUS_BAR.shortcutHint),
|
|
359
|
+
}).default({ ...DEFAULT_STATUS_BAR }),
|
|
339
360
|
// No default on purpose: an unset `lang` keeps the field showing
|
|
340
361
|
// the effective language (see the section's format below) and lets
|
|
341
362
|
// cordis.yml / lang.json keep their precedence.
|
|
@@ -355,15 +376,17 @@ export async function apply(ctx, config) {
|
|
|
355
376
|
writeLangPref(value.lang);
|
|
356
377
|
}
|
|
357
378
|
};
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
const
|
|
379
|
+
// Display preferences ride the same namespace: /settings writes them
|
|
380
|
+
// live and future render consumers observe the channel version bump.
|
|
381
|
+
const applyDisplay = (value) => {
|
|
361
382
|
channel.setThinkingFold(value.thinkingFold ?? config.thinkingFold ?? 'preview');
|
|
383
|
+
channel.setToolBackground(normalizeToolBackground(value.toolBackground ?? config.toolBackground));
|
|
384
|
+
channel.setStatusBar(normalizeStatusBar(value.statusBar ?? config.statusBar));
|
|
362
385
|
};
|
|
363
386
|
const apply = (next) => {
|
|
364
387
|
applyLayout(next);
|
|
365
388
|
applyLang(next);
|
|
366
|
-
|
|
389
|
+
applyDisplay(next);
|
|
367
390
|
};
|
|
368
391
|
apply(scope.get());
|
|
369
392
|
scope.watch(next => {
|
|
@@ -379,6 +402,7 @@ export async function apply(ctx, config) {
|
|
|
379
402
|
const unregister = settingsSections.register({
|
|
380
403
|
ns: 'dsh-tui',
|
|
381
404
|
title: 'dsh-tui',
|
|
405
|
+
groups: [{ id: 'status-bar', title: 'Status bar', descriptions: { zh: '底栏设置' } }],
|
|
382
406
|
fields: [
|
|
383
407
|
{
|
|
384
408
|
path: ['lang'],
|
|
@@ -423,6 +447,154 @@ export async function apply(ctx, config) {
|
|
|
423
447
|
{ value: 'full', label: 'Full until turn end', descriptions: { zh: '展开至轮末' } },
|
|
424
448
|
],
|
|
425
449
|
},
|
|
450
|
+
{
|
|
451
|
+
path: ['toolBackground'],
|
|
452
|
+
label: 'Tool background',
|
|
453
|
+
descriptions: { zh: '工具卡背景' },
|
|
454
|
+
hint: 'Choose whether tool-call cards add no, subtle, or strong background emphasis.',
|
|
455
|
+
hintDescriptions: { zh: '选择工具调用卡片不添加、轻微或明显的背景强调。' },
|
|
456
|
+
kind: 'select',
|
|
457
|
+
options: [
|
|
458
|
+
{ value: 'none', label: 'None', descriptions: { zh: '无' } },
|
|
459
|
+
{ value: 'subtle', label: 'Subtle', descriptions: { zh: '轻微' } },
|
|
460
|
+
{ value: 'strong', label: 'Strong', descriptions: { zh: '明显' } },
|
|
461
|
+
],
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
path: ['statusBar', 'compact'],
|
|
465
|
+
label: 'Compact status bar',
|
|
466
|
+
descriptions: { zh: '紧凑状态栏' },
|
|
467
|
+
hint: 'Prefer the compact status presentation when terminal space allows.',
|
|
468
|
+
hintDescriptions: { zh: '终端空间允许时优先使用紧凑状态栏布局。' },
|
|
469
|
+
group: 'status-bar',
|
|
470
|
+
kind: 'boolean',
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
path: ['statusBar', 'model'],
|
|
474
|
+
label: 'Show model',
|
|
475
|
+
descriptions: { zh: '显示模型' },
|
|
476
|
+
hint: 'Show the live model id in the status bar.',
|
|
477
|
+
hintDescriptions: { zh: '在状态栏显示当前模型标识。' },
|
|
478
|
+
group: 'status-bar',
|
|
479
|
+
kind: 'boolean',
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
path: ['statusBar', 'thinking'],
|
|
483
|
+
label: 'Show thinking',
|
|
484
|
+
descriptions: { zh: '显示思考' },
|
|
485
|
+
hint: 'Show the live reasoning effort or thinking mode.',
|
|
486
|
+
hintDescriptions: { zh: '显示当前推理强度或思考模式。' },
|
|
487
|
+
group: 'status-bar',
|
|
488
|
+
kind: 'boolean',
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
path: ['statusBar', 'cwd'],
|
|
492
|
+
label: 'Show working directory',
|
|
493
|
+
descriptions: { zh: '显示工作目录' },
|
|
494
|
+
hint: 'Show the session working directory.',
|
|
495
|
+
hintDescriptions: { zh: '显示当前会话的工作目录。' },
|
|
496
|
+
group: 'status-bar',
|
|
497
|
+
kind: 'boolean',
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
path: ['statusBar', 'contextUsage'],
|
|
501
|
+
label: 'Show context usage',
|
|
502
|
+
descriptions: { zh: '显示上下文用量' },
|
|
503
|
+
hint: 'Show current context-window consumption.',
|
|
504
|
+
hintDescriptions: { zh: '显示当前上下文窗口占用情况。' },
|
|
505
|
+
group: 'status-bar',
|
|
506
|
+
kind: 'boolean',
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
path: ['statusBar', 'cache'],
|
|
510
|
+
label: 'Show cache',
|
|
511
|
+
descriptions: { zh: '显示缓存' },
|
|
512
|
+
hint: 'Show prompt-cache hit information.',
|
|
513
|
+
hintDescriptions: { zh: '显示提示词缓存命中信息。' },
|
|
514
|
+
group: 'status-bar',
|
|
515
|
+
kind: 'boolean',
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
path: ['statusBar', 'tokens'],
|
|
519
|
+
label: 'Show token totals',
|
|
520
|
+
descriptions: { zh: '显示 Token 总量' },
|
|
521
|
+
hint: 'Show running input and output token totals.',
|
|
522
|
+
hintDescriptions: { zh: '显示累计输入与输出 Token。' },
|
|
523
|
+
group: 'status-bar',
|
|
524
|
+
kind: 'boolean',
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
path: ['statusBar', 'tps'],
|
|
528
|
+
label: 'Show output speed',
|
|
529
|
+
descriptions: { zh: '显示输出速度' },
|
|
530
|
+
hint: 'Show live and recent tokens-per-second metrics.',
|
|
531
|
+
hintDescriptions: { zh: '显示实时及近期每秒 Token 指标。' },
|
|
532
|
+
group: 'status-bar',
|
|
533
|
+
kind: 'boolean',
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
path: ['statusBar', 'gitBranch'],
|
|
537
|
+
label: 'Show git branch',
|
|
538
|
+
descriptions: { zh: '显示 Git 分支' },
|
|
539
|
+
hint: 'Show the current git branch when available.',
|
|
540
|
+
hintDescriptions: { zh: '可用时显示当前 Git 分支。' },
|
|
541
|
+
group: 'status-bar',
|
|
542
|
+
kind: 'boolean',
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
path: ['statusBar', 'sessionTitle'],
|
|
546
|
+
label: 'Show session title',
|
|
547
|
+
descriptions: { zh: '显示会话标题' },
|
|
548
|
+
hint: 'Show the current session title.',
|
|
549
|
+
hintDescriptions: { zh: '显示当前会话标题。' },
|
|
550
|
+
group: 'status-bar',
|
|
551
|
+
kind: 'boolean',
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
path: ['statusBar', 'mode'],
|
|
555
|
+
label: 'Show session mode',
|
|
556
|
+
descriptions: { zh: '显示会话模式' },
|
|
557
|
+
hint: 'Show the active non-default session mode.',
|
|
558
|
+
hintDescriptions: { zh: '显示当前启用的非默认会话模式。' },
|
|
559
|
+
group: 'status-bar',
|
|
560
|
+
kind: 'boolean',
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
path: ['statusBar', 'contextBar'],
|
|
564
|
+
label: 'Show context progress bar',
|
|
565
|
+
descriptions: { zh: '显示上下文进度条' },
|
|
566
|
+
hint: 'Show the segmented context progress bar on its own footer row.',
|
|
567
|
+
hintDescriptions: { zh: '在底部单独一行显示分段上下文进度条。' },
|
|
568
|
+
group: 'status-bar',
|
|
569
|
+
kind: 'boolean',
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
path: ['statusBar', 'activity'],
|
|
573
|
+
label: 'Show activity summary',
|
|
574
|
+
descriptions: { zh: '显示活动摘要' },
|
|
575
|
+
hint: 'Show the idle working-activity summary.',
|
|
576
|
+
hintDescriptions: { zh: '显示空闲时的工作活动摘要。' },
|
|
577
|
+
group: 'status-bar',
|
|
578
|
+
kind: 'boolean',
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
path: ['statusBar', 'trajectory'],
|
|
582
|
+
label: 'Show trajectory strip',
|
|
583
|
+
descriptions: { zh: '显示轨迹条' },
|
|
584
|
+
hint: 'Show the animated mini trajectory strip at the footer edge.',
|
|
585
|
+
hintDescriptions: { zh: '在状态栏边缘显示动态迷你轨迹条。' },
|
|
586
|
+
group: 'status-bar',
|
|
587
|
+
kind: 'boolean',
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
path: ['statusBar', 'shortcutHint'],
|
|
591
|
+
label: 'Show shortcut reminder',
|
|
592
|
+
descriptions: { zh: '显示快捷键提示' },
|
|
593
|
+
hint: 'Control only the idle `? for shortcuts` reminder; pressing ? and the Esc shortcut hints are unaffected.',
|
|
594
|
+
hintDescriptions: { zh: '仅控制空闲时的 `? for shortcuts` 提示;按 ? 打开快捷键以及 Esc 快捷提示均不受影响。' },
|
|
595
|
+
group: 'status-bar',
|
|
596
|
+
kind: 'boolean',
|
|
597
|
+
},
|
|
426
598
|
],
|
|
427
599
|
});
|
|
428
600
|
ctx.effect(() => unregister);
|