@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.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 +171 -124
- package/bin/dsh-tui.js +748 -22
- package/cordis.patch.yml +38 -10
- package/cordis.yml +2 -0
- package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/session-projection.js +2 -0
- package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +5 -1
- package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
- package/lib/types/adapter/kernel/host-facade.js +1 -0
- package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
- package/lib/types/adapter/kernel/replay.js +3 -0
- package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
- package/lib/types/adapter/kernel/runtime.js +2 -0
- package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
- package/lib/types/adapter/kernel/slices/workspace.js +1 -0
- package/lib/types/adapter/ports/channel-ui.d.ts +22 -2
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +66 -0
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
- package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
- package/lib/types/adapter/ports/workspace.d.ts +2 -0
- package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.js +10 -2
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +1 -0
- package/lib/types/components/ContextBarView.d.ts +15 -7
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +26 -22
- package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
- package/lib/types/components/ImagePreviewOverlay.js +11 -5
- package/lib/types/components/Markdown.d.ts +11 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +20 -2
- package/lib/types/components/MermaidDiagram.d.ts +13 -0
- package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
- package/lib/types/components/MermaidDiagram.js +61 -0
- package/lib/types/components/MessageList.d.ts +26 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +72 -7
- package/lib/types/components/PageMargin.d.ts +1 -1
- package/lib/types/components/PromptInput.d.ts +37 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +243 -28
- package/lib/types/components/ScrollbarGutter.d.ts +20 -5
- package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
- package/lib/types/components/ScrollbarGutter.js +88 -10
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +30 -28
- package/lib/types/components/Tooltip.d.ts.map +1 -1
- package/lib/types/components/Tooltip.js +45 -7
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +5 -7
- package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
- package/lib/types/components/messages/useImageInspection.js +19 -9
- package/lib/types/components/promptDraftCache.d.ts +102 -0
- package/lib/types/components/promptDraftCache.d.ts.map +1 -0
- package/lib/types/components/promptDraftCache.js +76 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
- package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
- package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +52 -5
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
- package/lib/types/dsh-adapter/bundled-presets.js +80 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +52 -29
- package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
- package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding.js +78 -18
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
- package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +29 -19
- package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/reports.js +4 -12
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +2 -2
- package/lib/types/dsh-adapter/channel/session-resume.d.ts +11 -2
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +291 -94
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
- package/lib/types/dsh-adapter/channel/state.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +1 -1
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +6 -12
- package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +67 -6
- package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
- package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/messages.js +15 -0
- package/lib/types/dsh-adapter/compat/settings.d.ts +33 -0
- package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/settings.js +43 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/shell.js +11 -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 +15 -6
- package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
- package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
- package/lib/types/dsh-adapter/ide-channel.js +556 -0
- package/lib/types/dsh-adapter/index.d.ts +18 -3
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +32 -5
- package/lib/types/dsh-adapter/plugin.d.ts +5 -2
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +173 -42
- package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
- package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/preset-resolution.js +10 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessionTree.js +3 -2
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +6 -5
- package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
- package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
- package/lib/types/dsh-adapter/workspaces.js +116 -0
- package/lib/types/effortPrefs.d.ts +15 -3
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +37 -3
- package/lib/types/homePrefs.d.ts +15 -0
- package/lib/types/homePrefs.d.ts.map +1 -0
- package/lib/types/homePrefs.js +53 -0
- package/lib/types/i18n.d.ts +257 -296
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +78 -84
- package/lib/types/ink/colorize.d.ts +10 -0
- package/lib/types/ink/colorize.d.ts.map +1 -1
- package/lib/types/ink/colorize.js +21 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +12 -1
- package/lib/types/ink/dom.d.ts +1 -0
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +36 -1
- package/lib/types/ink/output.d.ts +10 -1
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +109 -17
- package/lib/types/ink/render-border.d.ts +6 -1
- package/lib/types/ink/render-border.d.ts.map +1 -1
- package/lib/types/ink/render-border.js +25 -9
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +48 -6
- package/lib/types/ink/renderer.d.ts +6 -0
- package/lib/types/ink/renderer.d.ts.map +1 -1
- package/lib/types/ink/renderer.js +2 -1
- package/lib/types/ink/selection.d.ts +60 -0
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +129 -0
- package/lib/types/ink/sixel-graphics.d.ts +19 -1
- package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
- package/lib/types/ink/sixel-graphics.js +124 -12
- package/lib/types/ink/terminal-image.d.ts +18 -1
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal.d.ts +17 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +20 -1
- package/lib/types/screens/Chat.d.ts +17 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +284 -72
- package/lib/types/screens/SessionSupervisor.d.ts +84 -0
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/SessionSupervisor.js +350 -0
- package/lib/types/screens/SessionTree.js +2 -2
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +32 -9
- package/lib/types/screens/StatusLine.d.ts +13 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +36 -17
- package/lib/types/screens/StatusMetrics.d.ts +79 -22
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +153 -88
- package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
- package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/model.js +69 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
- package/lib/types/sessionMounts.d.ts +272 -0
- package/lib/types/sessionMounts.d.ts.map +1 -0
- package/lib/types/sessionMounts.js +706 -0
- package/lib/types/sessions/format.d.ts.map +1 -1
- package/lib/types/sessions/format.js +4 -1
- package/lib/types/sessions/resumeFailure.d.ts +38 -0
- package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
- package/lib/types/sessions/resumeFailure.js +58 -0
- package/lib/types/terminal-utils/mermaid.d.ts +44 -0
- package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
- package/lib/types/terminal-utils/mermaid.js +83 -0
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +175 -19
- package/lib/types/tuiDisplayPrefs.d.ts +7 -9
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +31 -28
- package/lib/types/update.d.ts +61 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +194 -0
- package/lib/types/utils/imageResize.d.ts +90 -0
- package/lib/types/utils/imageResize.d.ts.map +1 -0
- package/lib/types/utils/imageResize.js +272 -0
- package/lib/types/utils/keymap.d.ts +5 -1
- package/lib/types/utils/keymap.d.ts.map +1 -1
- package/lib/types/utils/keymap.js +23 -0
- package/lib/types/workspaces.d.ts +2 -1
- package/lib/types/workspaces.d.ts.map +1 -1
- package/lib/types/workspaces.js +1 -1
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
- package/package.json +120 -103
- package/presets/liangshen/.dsh-tui-managed.json +1 -1
- package/presets/liangshen/agent.cordis.yml +15 -0
- package/lib/types/screens/AgentView.d.ts +0 -23
- package/lib/types/screens/AgentView.d.ts.map +0 -1
- package/lib/types/screens/AgentView.js +0 -546
- package/lib/types/screens/SessionBrowser.d.ts +0 -42
- package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
- package/lib/types/screens/SessionBrowser.js +0 -911
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publishes this TUI process's mounted-session set to the cross-process
|
|
3
|
+
* ledger ({@link ../../sessionMounts.js}).
|
|
4
|
+
*
|
|
5
|
+
* A TUI terminal hosts several agent sessions at once — the attached one plus
|
|
6
|
+
* every parked background session — and two processes driving the same
|
|
7
|
+
* session log would interleave writes into one append-only transcript. The
|
|
8
|
+
* ledger is what lets another TUI see "this session is already mounted" and
|
|
9
|
+
* refuse it, so the published set has to cover EVERY live agent in this
|
|
10
|
+
* process, not just the attached one.
|
|
11
|
+
*
|
|
12
|
+
* Reading the agent registry is what makes that automatic, and the small timer
|
|
13
|
+
* is what keeps it honest: agents are created from more than seven paths
|
|
14
|
+
* (`/new`, `/resume`, `/bg`, fork, rewind, model switch, boot attach), so an
|
|
15
|
+
* announce-at-each-call-site design would silently drop a session the day
|
|
16
|
+
* someone adds an eighth. Deriving the set from the registry has exactly one
|
|
17
|
+
* place to be right.
|
|
18
|
+
*
|
|
19
|
+
* Publishing is NOT a liveness witness: {@link ../../sessionMounts.js} decides
|
|
20
|
+
* liveness from the owner's pid alone, so a late or missed publish cannot keep
|
|
21
|
+
* a dead process's claim alive and there is no timestamp here to expire. The
|
|
22
|
+
* timer's only job is to keep the published SET current, and it is deliberately
|
|
23
|
+
* unref'd: it must never be the reason a quitting TUI stays alive. Teardown
|
|
24
|
+
* removes the record outright so a clean exit frees its sessions immediately.
|
|
25
|
+
*
|
|
26
|
+
* Registered through the host's single teardown funnel by the caller, so both
|
|
27
|
+
* the interval and the ledger record are released exactly once.
|
|
28
|
+
*
|
|
29
|
+
* @module
|
|
30
|
+
*/
|
|
31
|
+
import { clearOwnMounts, publishMounts } from '../sessionMounts.js';
|
|
32
|
+
/**
|
|
33
|
+
* How often the mounted set is republished. One small file write, not tied to
|
|
34
|
+
* any render frame; it bounds how long a peer can read a set that predates a
|
|
35
|
+
* session this process just mounted.
|
|
36
|
+
*/
|
|
37
|
+
const PUBLISH_INTERVAL_MS = 15_000;
|
|
38
|
+
/**
|
|
39
|
+
* Collect the session ids this process currently has mounted: every live agent
|
|
40
|
+
* the registry knows about, minus sub-agent runs.
|
|
41
|
+
*
|
|
42
|
+
* Sub-agents are excluded because they are not independently mountable: they
|
|
43
|
+
* are a parent session's own work, they never appear as `/resume` rows, and
|
|
44
|
+
* claiming their ids would make the parent look occupied to a TUI that only
|
|
45
|
+
* wants to read the parent.
|
|
46
|
+
* @param ctx - The plugin context, for the agent registry.
|
|
47
|
+
* @returns Session ids as strings.
|
|
48
|
+
*/
|
|
49
|
+
export function mountedSessionIds(ctx) {
|
|
50
|
+
const roster = ctx.get('agents');
|
|
51
|
+
const ids = [];
|
|
52
|
+
for (const agent of roster?.list?.() ?? []) {
|
|
53
|
+
if (agent.session.header.origin === 'subagent')
|
|
54
|
+
continue;
|
|
55
|
+
const id = String(agent.id);
|
|
56
|
+
if (id.length > 0)
|
|
57
|
+
ids.push(id);
|
|
58
|
+
}
|
|
59
|
+
return ids;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Start publishing this process's mounted sessions.
|
|
63
|
+
*
|
|
64
|
+
* The first publish runs synchronously so a session mounted during boot is
|
|
65
|
+
* claimed before the user can reach a second terminal.
|
|
66
|
+
* @param ctx - The plugin context, for the agent registry.
|
|
67
|
+
* @returns A disposer that stops publishing and releases the claim.
|
|
68
|
+
*/
|
|
69
|
+
export function startSessionMountHeartbeat(ctx) {
|
|
70
|
+
let stopped = false;
|
|
71
|
+
const beat = () => {
|
|
72
|
+
if (stopped)
|
|
73
|
+
return;
|
|
74
|
+
try {
|
|
75
|
+
publishMounts(mountedSessionIds(ctx));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// PUBLISHING is best-effort; DECIDING is not. A beat that cannot write
|
|
79
|
+
// costs announcement until the next one, and must not disturb this
|
|
80
|
+
// session — while the paths that grant a mount refuse outright when they
|
|
81
|
+
// cannot read the ledger, because that is the one error nothing can
|
|
82
|
+
// repair afterwards.
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
beat();
|
|
86
|
+
const timer = setInterval(beat, PUBLISH_INTERVAL_MS);
|
|
87
|
+
// Never let the publisher hold the process open: quitting the TUI must not
|
|
88
|
+
// wait for a timer that exists only to describe a process that is leaving.
|
|
89
|
+
timer.unref?.();
|
|
90
|
+
return () => {
|
|
91
|
+
stopped = true;
|
|
92
|
+
clearInterval(timer);
|
|
93
|
+
try {
|
|
94
|
+
clearOwnMounts();
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// A leftover record is ignored once this pid is gone.
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionTree.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/sessionTree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAiE,MAAM,qCAAqC,CAAA;AAC9J,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAC9J;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"sessionTree.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/sessionTree.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCompactionCheckpointSource, toolResultPayload } from './compat/messages.js';
|
|
1
2
|
export const TREE_FILTERS = ['default', 'no-tools', 'user-only', 'all'];
|
|
2
3
|
/**
|
|
3
4
|
* Confirm-time preview for a USER-message pick: how much of its branch the
|
|
@@ -345,7 +346,7 @@ export function extractEntries(sessionId, events) {
|
|
|
345
346
|
switch (event.type) {
|
|
346
347
|
case 'user/message': {
|
|
347
348
|
const source = event.data.source;
|
|
348
|
-
if (source
|
|
349
|
+
if (isCompactionCheckpointSource(source)) {
|
|
349
350
|
const summary = textOf(event.data.content);
|
|
350
351
|
push({
|
|
351
352
|
seq: event.seq,
|
|
@@ -408,7 +409,7 @@ export function extractEntries(sessionId, events) {
|
|
|
408
409
|
const entry = entries[index];
|
|
409
410
|
entries[index] = {
|
|
410
411
|
...entry,
|
|
411
|
-
toolStatus: event.data.error
|
|
412
|
+
toolStatus: event.data.error !== undefined || toolResultPayload(event.data.message).isError ? 'error' : 'ok',
|
|
412
413
|
};
|
|
413
414
|
openTools.delete(event.data.message.source.callId);
|
|
414
415
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/subagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"subagents.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/subagents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAElE,OAAO,KAAK,EAAE,aAAa,EAAsC,kBAAkB,EAAE,gBAAgB,EAAsB,MAAM,kCAAkC,CAAA;AACnK,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AAiBnK,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,OAAO,CAA2C;IAE1D,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,QAAQ;IAOhB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAa,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,IAAI;IA0B1G,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAMpD,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAE5D,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAA2B,GAAG,IAAI;IA0BpF,8DAA8D;IAC9D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IASlC;mFAC+E;IAC/E,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI;IA+BjE,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,eAAe;IAyBvB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAmDrD,6EAA6E;IAC7E,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI;IAO7D,2EAA2E;IAC3E,OAAO,CAAC,SAAS;IAUjB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IASvF,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAU3J,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,SAAc,GAAG,IAAI;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAC9C,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAc,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAE1E,OAAO,CAAC,MAAM;IAcd;;sEAEkE;IAClE,KAAK,IAAI,IAAI;IAOb,QAAQ,IAAI,aAAa,EAAE;IAC3B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAC/C,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAC3C,OAAO,CAAC,MAAM;CACf"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toolResultPayload } from './compat/messages.js';
|
|
1
2
|
const MAX_OUTPUT_EVENTS = 160;
|
|
2
3
|
const MAX_OUTPUT_LINES = 160;
|
|
3
4
|
export class SubagentActivityStore {
|
|
@@ -208,15 +209,15 @@ export class SubagentActivityStore {
|
|
|
208
209
|
const state = this.states.get(agentId);
|
|
209
210
|
const tool = callId !== undefined ? state?.toolCalls.find(entry => entry.id === callId) : undefined;
|
|
210
211
|
if (tool) {
|
|
211
|
-
|
|
212
|
+
const payload = toolResultPayload(data.message);
|
|
213
|
+
tool.status = data.error !== undefined || payload.isError ? 'failed' : 'completed';
|
|
212
214
|
tool.endedAt = Date.now();
|
|
213
215
|
if (data.error !== undefined)
|
|
214
216
|
tool.error = String(data.error);
|
|
217
|
+
else if (payload.isError)
|
|
218
|
+
tool.error = this.previewOf(payload.content);
|
|
215
219
|
else {
|
|
216
|
-
|
|
217
|
-
tool.resultPreview = block !== undefined && block.type === 'tool-result'
|
|
218
|
-
? this.previewOf(block.content)
|
|
219
|
-
: undefined;
|
|
220
|
+
tool.resultPreview = this.previewOf(payload.content);
|
|
220
221
|
}
|
|
221
222
|
this.notify();
|
|
222
223
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TuiWorkspaceTarget, TuiWorkspaceCommand, TuiWorkspaceCommandResult } from '../adapter/ports/channel-workspace.js';
|
|
2
|
-
export type { TuiWorkspaceTarget, TuiWorkspaceKind, TuiWorkspaceCommand, TuiWorkspaceCommandResult, TuiWorkspaceChoice } from '../adapter/ports/channel-workspace.js';
|
|
1
|
+
import type { TuiWorkspaceTarget, TuiWorkspaceCommand, TuiWorkspaceCommandResult, TuiWorkspaceEntry } from '../adapter/ports/channel-workspace.js';
|
|
2
|
+
export type { TuiWorkspaceTarget, TuiWorkspaceKind, TuiWorkspaceCommand, TuiWorkspaceCommandResult, TuiWorkspaceChoice, TuiWorkspaceEntry } from '../adapter/ports/channel-workspace.js';
|
|
3
3
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
4
4
|
export interface TuiCommandShell {
|
|
5
5
|
resolve(request: {
|
|
@@ -45,9 +45,39 @@ export interface TuiWorkspaceHost {
|
|
|
45
45
|
describe(cwd: string): TuiWorkspaceTarget;
|
|
46
46
|
commandShell(cwd: string): Promise<TuiCommandShell | undefined>;
|
|
47
47
|
rename(cwd: string, title: string): Promise<TuiWorkspaceTarget>;
|
|
48
|
+
/** Drop a workspace registration (never the directory or its session logs). */
|
|
49
|
+
remove(cwd: string): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* The durable ledger's own listing, in its own order.
|
|
52
|
+
*
|
|
53
|
+
* Unlike `list`, this merges nothing and appends nothing: it is the set of
|
|
54
|
+
* registrations the sidebar manages, including entries with no sessions and
|
|
55
|
+
* entries whose directory has disappeared.
|
|
56
|
+
*/
|
|
57
|
+
listRegistry(): Promise<readonly TuiWorkspaceEntry[]>;
|
|
48
58
|
commands(): readonly Pick<TuiWorkspaceCommand, 'name' | 'aliases' | 'description'>[];
|
|
49
59
|
runCommand(name: string, input: string, cwd: string, signal?: AbortSignal): Promise<TuiWorkspaceCommandResult | undefined>;
|
|
50
60
|
}
|
|
61
|
+
/** Registry-backed list surface for the workspace home screen. */
|
|
62
|
+
type RegistryWorkspaceEntry = TuiWorkspaceEntry;
|
|
63
|
+
/**
|
|
64
|
+
* Enumerate the durable workspace registry, in its own display order.
|
|
65
|
+
*
|
|
66
|
+
* The sidebar needs the *registry* (every workspace the user ever registered,
|
|
67
|
+
* including ones with no sessions yet), not the session-derived grouping the
|
|
68
|
+
* `/resume` browser builds. Order, ids and titles come from the ledger;
|
|
69
|
+
* `sessionCount` is filled in by the caller (the adapter holds no session
|
|
70
|
+
* index), and `present` is derived here.
|
|
71
|
+
*/
|
|
72
|
+
export declare function listRegistryWorkspaces(runtime: TuiWorkspaceRuntime | undefined): Promise<readonly RegistryWorkspaceEntry[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Remove a workspace registration by path. Sessions and the directory survive:
|
|
75
|
+
* only the ledger entry goes away, so the sessions reappear as ungrouped.
|
|
76
|
+
*
|
|
77
|
+
* @returns True when a record was removed, false when no record owned `cwd`
|
|
78
|
+
* (or the ledger is unmounted).
|
|
79
|
+
*/
|
|
80
|
+
export declare function removeRegistryWorkspace(runtime: TuiWorkspaceRuntime | undefined, cwd: string, owner?: object): Promise<boolean>;
|
|
51
81
|
declare module '@deepseek-ai/cordis' {
|
|
52
82
|
interface Context {
|
|
53
83
|
tuiWorkspaces: TuiWorkspaceRuntime;
|
|
@@ -66,6 +96,19 @@ export declare class TuiWorkspaceRuntime extends Service {
|
|
|
66
96
|
describe(cwd: string): TuiWorkspaceTarget;
|
|
67
97
|
commandShell(cwd: string): Promise<TuiCommandShell | undefined>;
|
|
68
98
|
rename(cwd: string, title: string): Promise<TuiWorkspaceTarget>;
|
|
99
|
+
/**
|
|
100
|
+
* Drop a workspace registration; the directory and session logs survive.
|
|
101
|
+
*
|
|
102
|
+
* Plugin-facing, and therefore bound by the SAME rule as {@link rename}: a
|
|
103
|
+
* live calling activation is required, and the target must be a cwd one of
|
|
104
|
+
* that activation's own providers vouches for. Without both, a plugin that
|
|
105
|
+
* never owned the workspace 鈥?including one whose fiber was already disposed
|
|
106
|
+
* and whose caller context is a retained handle 鈥?could delete a host
|
|
107
|
+
* registration. Shadow policy alone is not caller authentication.
|
|
108
|
+
*/
|
|
109
|
+
remove(cwd: string): Promise<boolean>;
|
|
110
|
+
/** The durable ledger's own listing, in its own order. */
|
|
111
|
+
listRegistry(): Promise<readonly TuiWorkspaceEntry[]>;
|
|
69
112
|
commands(): readonly Pick<TuiWorkspaceCommand, 'name' | 'aliases' | 'description'>[];
|
|
70
113
|
runCommand(name: string, input: string, cwd: string, signal?: AbortSignal): Promise<TuiWorkspaceCommandResult | undefined>;
|
|
71
114
|
private notifyProviderWaiters;
|
|
@@ -74,7 +117,7 @@ export declare class TuiWorkspaceRuntime extends Service {
|
|
|
74
117
|
export declare function getHostWorkspaceRuntime(runtime: TuiWorkspaceRuntime | undefined): TuiWorkspaceHost | undefined;
|
|
75
118
|
/** Local-only fallback for direct embedders that call createChannel() without
|
|
76
119
|
* mounting the optional workspace registry/provider service. */
|
|
77
|
-
export declare function createLocalWorkspaceRuntime(): Pick<TuiWorkspaceRuntime, 'list' | 'resolve' | 'describe' | 'commandShell' | 'rename' | 'commands' | 'runCommand'>;
|
|
120
|
+
export declare function createLocalWorkspaceRuntime(): Pick<TuiWorkspaceRuntime, 'list' | 'resolve' | 'describe' | 'commandShell' | 'rename' | 'remove' | 'listRegistry' | 'commands' | 'runCommand'>;
|
|
78
121
|
export declare function localWorkspaceUri(path: string): string;
|
|
79
122
|
/** Resolve a native absolute path or the standard file URL form. */
|
|
80
123
|
export declare function parseLocalWorkspaceReference(reference: string): TuiWorkspaceTarget | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAoB,mBAAmB,EAAE,yBAAyB,EAAsB,MAAM,uCAAuC,CAAA;
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/workspaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,90 @@ import { Service } from '@deepseek-ai/cordis';
|
|
|
10
10
|
import { activationFiber, bindCallerEffect, compositionRoot, concreteService, requirePluginCaller } from './host-access.js';
|
|
11
11
|
import { assertCapabilityShadowPolicy, } from '../adapter/kernel/runtime.js';
|
|
12
12
|
import { adapterRuntimeFor } from '../adapter/kernel/runtime-context.js';
|
|
13
|
+
/**
|
|
14
|
+
* Enumerate the durable workspace registry, in its own display order.
|
|
15
|
+
*
|
|
16
|
+
* The sidebar needs the *registry* (every workspace the user ever registered,
|
|
17
|
+
* including ones with no sessions yet), not the session-derived grouping the
|
|
18
|
+
* `/resume` browser builds. Order, ids and titles come from the ledger;
|
|
19
|
+
* `sessionCount` is filled in by the caller (the adapter holds no session
|
|
20
|
+
* index), and `present` is derived here.
|
|
21
|
+
*/
|
|
22
|
+
export async function listRegistryWorkspaces(runtime) {
|
|
23
|
+
if (runtime === undefined)
|
|
24
|
+
return [];
|
|
25
|
+
const registry = workspaceRegistry(runtime);
|
|
26
|
+
if (registry === undefined)
|
|
27
|
+
return [];
|
|
28
|
+
const out = [];
|
|
29
|
+
for (const workspace of registry.list()) {
|
|
30
|
+
let present = true;
|
|
31
|
+
try {
|
|
32
|
+
present = (await workspace.status?.()) !== 'missing-dir';
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// An unreadable status is not evidence of absence.
|
|
36
|
+
present = true;
|
|
37
|
+
}
|
|
38
|
+
out.push({
|
|
39
|
+
id: String(workspace.id),
|
|
40
|
+
path: workspace.path,
|
|
41
|
+
title: workspace.title,
|
|
42
|
+
present,
|
|
43
|
+
sessionCount: 0,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Remove a workspace registration by path. Sessions and the directory survive:
|
|
50
|
+
* only the ledger entry goes away, so the sessions reappear as ungrouped.
|
|
51
|
+
*
|
|
52
|
+
* @returns True when a record was removed, false when no record owned `cwd`
|
|
53
|
+
* (or the ledger is unmounted).
|
|
54
|
+
*/
|
|
55
|
+
export async function removeRegistryWorkspace(runtime, cwd, owner) {
|
|
56
|
+
if (runtime === undefined)
|
|
57
|
+
return false;
|
|
58
|
+
const registry = workspaceRegistry(runtime);
|
|
59
|
+
if (registry === undefined)
|
|
60
|
+
return false;
|
|
61
|
+
const workspace = registry.list().find(candidate => sameCwd(candidate.path, cwd));
|
|
62
|
+
if (workspace === undefined)
|
|
63
|
+
return false;
|
|
64
|
+
// The durable ledger is host-owned: a plugin may only drop a registration
|
|
65
|
+
// for a cwd one of ITS OWN providers still vouches for. `owner === undefined`
|
|
66
|
+
// is the host facade's own call (the sidebar's remove action).
|
|
67
|
+
if (owner !== undefined && !ownsWorkspace(runtime, owner, cwd)) {
|
|
68
|
+
throw new Error('workspace is not owned by the calling activation');
|
|
69
|
+
}
|
|
70
|
+
return registry.delete(workspace.id);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Whether a calling activation's own providers still vouch for `cwd`.
|
|
74
|
+
*
|
|
75
|
+
* This is the same evidence `renameWorkspace` accepts, and the only ownership
|
|
76
|
+
* fact the local ledger records 鈥?the registry entry itself carries no creator.
|
|
77
|
+
* A provider `describe()` that returns a target means the cwd belongs to that
|
|
78
|
+
* provider's scheme, so the activation behind it is the one entitled to mutate
|
|
79
|
+
* the registration.
|
|
80
|
+
* @param runtime - The workspace service.
|
|
81
|
+
* @param owner - Live activation fiber of the caller.
|
|
82
|
+
* @param cwd - Directory to test.
|
|
83
|
+
* @returns True when one of the caller's providers owns `cwd`.
|
|
84
|
+
*/
|
|
85
|
+
function ownsWorkspace(runtime, owner, cwd) {
|
|
86
|
+
for (const provider of providersFor(workspaceStateFor(runtime), owner)) {
|
|
87
|
+
try {
|
|
88
|
+
if (provider.describe(cwd) !== undefined)
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// A provider that throws on describe vouches for nothing.
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
13
97
|
export const name = 'dsh-tui-workspaces';
|
|
14
98
|
/** Bound every provider promise so one plugin cannot park workspace flows. */
|
|
15
99
|
export const WORKSPACE_PROVIDER_TIMEOUT_MS = 2000;
|
|
@@ -53,6 +137,11 @@ export class TuiWorkspaceRuntime extends Service {
|
|
|
53
137
|
assertCapabilityShadowPolicy('host.workspaces.rename', state.runtime.mode, state.runtime.slices);
|
|
54
138
|
return renameWorkspace(runtime, cwd, title, undefined);
|
|
55
139
|
},
|
|
140
|
+
remove: (cwd) => {
|
|
141
|
+
assertCapabilityShadowPolicy('host.workspaces.remove', state.runtime.mode, state.runtime.slices);
|
|
142
|
+
return removeRegistryWorkspace(runtime, cwd);
|
|
143
|
+
},
|
|
144
|
+
listRegistry: () => listRegistryWorkspaces(runtime),
|
|
56
145
|
commands: () => workspaceCommands(runtime, undefined),
|
|
57
146
|
runCommand: (name, input, cwd, signal) => {
|
|
58
147
|
assertCapabilityShadowPolicy('host.workspaces.runCommand', state.runtime.mode, state.runtime.slices);
|
|
@@ -107,6 +196,27 @@ export class TuiWorkspaceRuntime extends Service {
|
|
|
107
196
|
const owner = workspaceCaller(this, 'tuiWorkspaces.rename');
|
|
108
197
|
return renameWorkspace(this, cwd, title, owner);
|
|
109
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Drop a workspace registration; the directory and session logs survive.
|
|
201
|
+
*
|
|
202
|
+
* Plugin-facing, and therefore bound by the SAME rule as {@link rename}: a
|
|
203
|
+
* live calling activation is required, and the target must be a cwd one of
|
|
204
|
+
* that activation's own providers vouches for. Without both, a plugin that
|
|
205
|
+
* never owned the workspace 鈥?including one whose fiber was already disposed
|
|
206
|
+
* and whose caller context is a retained handle 鈥?could delete a host
|
|
207
|
+
* registration. Shadow policy alone is not caller authentication.
|
|
208
|
+
*/
|
|
209
|
+
async remove(cwd) {
|
|
210
|
+
assertCapabilityShadowPolicy('host.workspaces.remove', workspaceStateFor(this).runtime.mode, workspaceStateFor(this).runtime.slices);
|
|
211
|
+
const owner = workspaceCaller(this, 'tuiWorkspaces.remove');
|
|
212
|
+
return removeRegistryWorkspace(this, cwd, owner);
|
|
213
|
+
}
|
|
214
|
+
/** The durable ledger's own listing, in its own order. */
|
|
215
|
+
async listRegistry() {
|
|
216
|
+
assertCapabilityShadowPolicy('host.workspaces.list', workspaceStateFor(this).runtime.mode, workspaceStateFor(this).runtime.slices);
|
|
217
|
+
workspaceCaller(this, 'tuiWorkspaces.listRegistry');
|
|
218
|
+
return listRegistryWorkspaces(this);
|
|
219
|
+
}
|
|
110
220
|
commands() {
|
|
111
221
|
assertCapabilityShadowPolicy('host.workspaces.commands', workspaceStateFor(this).runtime.mode, workspaceStateFor(this).runtime.slices);
|
|
112
222
|
const owner = workspaceCaller(this, 'tuiWorkspaces.commands');
|
|
@@ -376,6 +486,12 @@ export function createLocalWorkspaceRuntime() {
|
|
|
376
486
|
async rename() {
|
|
377
487
|
throw new Error('workspace registry is unavailable');
|
|
378
488
|
},
|
|
489
|
+
async remove() {
|
|
490
|
+
return false;
|
|
491
|
+
},
|
|
492
|
+
async listRegistry() {
|
|
493
|
+
return [];
|
|
494
|
+
},
|
|
379
495
|
commands() {
|
|
380
496
|
return [];
|
|
381
497
|
},
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* `/effort` (slider or `/effort <id>`; `/effort status` reports the current
|
|
4
4
|
* level) — note Shift+Tab cycles session modes (default/plan/full), not
|
|
5
5
|
* effort levels. The choice lands here so the next boot starts on it. The
|
|
6
|
-
* file is best-effort
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* file is best-effort; a level the current route's tier list does not offer
|
|
7
|
+
* falls back to the nearest LOWER tier (nearestLowerEffort, never up) with a
|
|
8
|
+
* loud notice — a missing/corrupt file falls back to the provider default.
|
|
9
9
|
*/
|
|
10
10
|
/**
|
|
11
11
|
* The persisted reasoning-effort id, or undefined when unset or invalid.
|
|
@@ -26,6 +26,18 @@ export declare function readEffortPref(dir?: string): string | undefined;
|
|
|
26
26
|
* @returns The winning level id, or undefined for the adapter default.
|
|
27
27
|
*/
|
|
28
28
|
export declare function resolveEffortDefault(settingsDefault: string | undefined, configured: string | undefined, persisted: string | undefined): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a preferred effort tier against a route's available tiers when the
|
|
31
|
+
* exact tier is absent: pick the NEAREST LOWER standard tier that the route
|
|
32
|
+
* offers (max→high, high→low, …). Only-down, never-up — a user who prefers
|
|
33
|
+
* `low` on a route without it must not be pushed to `high`. Unknown tier ids
|
|
34
|
+
* (custom route tiers outside the standard order) never participate: an
|
|
35
|
+
* unknown preference yields undefined, an unknown candidate is skipped.
|
|
36
|
+
* @param preferred - The preferred tier id (exact match short-circuits).
|
|
37
|
+
* @param available - Tier ids the current route offers.
|
|
38
|
+
* @returns The tier id to apply, or undefined to keep the model default.
|
|
39
|
+
*/
|
|
40
|
+
export declare function nearestLowerEffort(preferred: string, available: readonly string[]): string | undefined;
|
|
29
41
|
/**
|
|
30
42
|
* Persist the chosen reasoning-effort id (best effort).
|
|
31
43
|
* @param effort - Adapter-owned effort id to persist.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effortPrefs.d.ts","sourceRoot":"","sources":["../../src/effortPrefs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAkB,GAAG,MAAM,GAAG,SAAS,CAS1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,SAAS,CAEpB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQhF"}
|
|
1
|
+
{"version":3,"file":"effortPrefs.d.ts","sourceRoot":"","sources":["../../src/effortPrefs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAkB,GAAG,MAAM,GAAG,SAAS,CAS1E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,MAAM,GAAG,SAAS,CAEpB;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAgBtG;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAkB,GAAG,OAAO,CAQhF"}
|
package/lib/types/effortPrefs.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* `/effort` (slider or `/effort <id>`; `/effort status` reports the current
|
|
4
4
|
* level) — note Shift+Tab cycles session modes (default/plan/full), not
|
|
5
5
|
* effort levels. The choice lands here so the next boot starts on it. The
|
|
6
|
-
* file is best-effort
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* file is best-effort; a level the current route's tier list does not offer
|
|
7
|
+
* falls back to the nearest LOWER tier (nearestLowerEffort, never up) with a
|
|
8
|
+
* loud notice — a missing/corrupt file falls back to the provider default.
|
|
9
9
|
*/
|
|
10
10
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
@@ -43,6 +43,40 @@ export function readEffortPref(dir = PREFS_DIR) {
|
|
|
43
43
|
export function resolveEffortDefault(settingsDefault, configured, persisted) {
|
|
44
44
|
return settingsDefault ?? configured ?? persisted;
|
|
45
45
|
}
|
|
46
|
+
/** Standard effort-tier order, weakest to strongest. */
|
|
47
|
+
const EFFORT_TIER_ORDER = ['off', 'low', 'medium', 'high', 'max'];
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a preferred effort tier against a route's available tiers when the
|
|
50
|
+
* exact tier is absent: pick the NEAREST LOWER standard tier that the route
|
|
51
|
+
* offers (max→high, high→low, …). Only-down, never-up — a user who prefers
|
|
52
|
+
* `low` on a route without it must not be pushed to `high`. Unknown tier ids
|
|
53
|
+
* (custom route tiers outside the standard order) never participate: an
|
|
54
|
+
* unknown preference yields undefined, an unknown candidate is skipped.
|
|
55
|
+
* @param preferred - The preferred tier id (exact match short-circuits).
|
|
56
|
+
* @param available - Tier ids the current route offers.
|
|
57
|
+
* @returns The tier id to apply, or undefined to keep the model default.
|
|
58
|
+
*/
|
|
59
|
+
export function nearestLowerEffort(preferred, available) {
|
|
60
|
+
if (preferred === '' || available.length === 0)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (available.includes(preferred))
|
|
63
|
+
return preferred;
|
|
64
|
+
const preferredRank = EFFORT_TIER_ORDER.indexOf(preferred);
|
|
65
|
+
if (preferredRank <= 0)
|
|
66
|
+
return undefined; // unknown id, or 'off' has nothing lower
|
|
67
|
+
let result;
|
|
68
|
+
let resultRank = -1;
|
|
69
|
+
for (const candidate of available) {
|
|
70
|
+
const rank = EFFORT_TIER_ORDER.indexOf(candidate);
|
|
71
|
+
if (rank < 0 || rank >= preferredRank)
|
|
72
|
+
continue;
|
|
73
|
+
if (rank > resultRank) {
|
|
74
|
+
result = candidate;
|
|
75
|
+
resultRank = rank;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
46
80
|
/**
|
|
47
81
|
* Persist the chosen reasoning-effort id (best effort).
|
|
48
82
|
* @param effort - Adapter-owned effort id to persist.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface HomePrefs {
|
|
2
|
+
/** True once the workspace home has been shown as the landing screen. */
|
|
3
|
+
seen?: boolean;
|
|
4
|
+
}
|
|
5
|
+
/** Read the persisted landing preference; an unreadable file reads as unset. */
|
|
6
|
+
export declare function readHomePrefs(): HomePrefs;
|
|
7
|
+
/**
|
|
8
|
+
* Record that the workspace home has been shown.
|
|
9
|
+
*
|
|
10
|
+
* @returns True when the preference was durably written; false when the data
|
|
11
|
+
* directory is not writable (the caller stays silent — see the module note).
|
|
12
|
+
*/
|
|
13
|
+
export declare function markHomeSeen(): boolean;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=homePrefs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"homePrefs.d.ts","sourceRoot":"","sources":["../../src/homePrefs.ts"],"names":[],"mappings":"AA0BA,UAAU,SAAS;IACjB,yEAAyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,gFAAgF;AAChF,wBAAgB,aAAa,IAAI,SAAS,CASzC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAQtC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Landing-screen preference for the TUI's workspace home screen.
|
|
3
|
+
*
|
|
4
|
+
* A one-key preference under `~/.dsh-tui/home.json`, deliberately NOT a cordis
|
|
5
|
+
* config value: "has this installation shown the user the workspace home on a
|
|
6
|
+
* fresh launch yet" is per-machine UI state, like the lang and tray
|
|
7
|
+
* preferences next to it — not a deployment choice a cordis.yml row should own.
|
|
8
|
+
*
|
|
9
|
+
* The rule it enables is one-shot: the FIRST ordinary launch (no explicit
|
|
10
|
+
* `--resume`, no workspace target) lands on the workspace home instead of a
|
|
11
|
+
* blank conversation, because that is the launch where "which project am I
|
|
12
|
+
* working on" has no answer yet. After that the chat screen is the landing
|
|
13
|
+
* surface again, and the home screen stays reachable as a screen.
|
|
14
|
+
*
|
|
15
|
+
* A preference file that cannot be read or written is never fatal: the worst
|
|
16
|
+
* outcome is one extra home screen, or a chat screen where the home was
|
|
17
|
+
* expected. Both are recoverable with a single keypress.
|
|
18
|
+
*
|
|
19
|
+
* @module @deepseek-harness-tui/dsh-tui/homePrefs
|
|
20
|
+
*/
|
|
21
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import { DATA_DIR } from './utils/paths.js';
|
|
24
|
+
const PREFS_FILE = join(DATA_DIR, 'home.json');
|
|
25
|
+
/** Read the persisted landing preference; an unreadable file reads as unset. */
|
|
26
|
+
export function readHomePrefs() {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(readFileSync(PREFS_FILE, 'utf8'));
|
|
29
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
30
|
+
return {};
|
|
31
|
+
const seen = parsed.seen;
|
|
32
|
+
return typeof seen === 'boolean' ? { seen } : {};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Record that the workspace home has been shown.
|
|
40
|
+
*
|
|
41
|
+
* @returns True when the preference was durably written; false when the data
|
|
42
|
+
* directory is not writable (the caller stays silent — see the module note).
|
|
43
|
+
*/
|
|
44
|
+
export function markHomeSeen() {
|
|
45
|
+
try {
|
|
46
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
47
|
+
writeFileSync(PREFS_FILE, `${JSON.stringify({ ...readHomePrefs(), seen: true }, null, 2)}\n`, 'utf8');
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|