@sagmans/dsh-tui 0.6.0 → 0.8.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/.agents/skills/dsh-tui-dogfood/SKILL.md +83 -0
- package/.agents/skills/dsh-tui-dogfood/references/home-state.md +78 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +133 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +417 -0
- package/.agents/skills/dsh-tui-update-models/SKILL.md +199 -0
- package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +292 -0
- package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +314 -0
- package/README.md +154 -27
- package/lib/agent/present.d.ts.map +1 -1
- package/lib/agent/present.js +2 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/cards/composition.d.ts +68 -0
- package/lib/cards/composition.d.ts.map +1 -0
- package/lib/cards/composition.js +117 -0
- package/lib/cards/composition.js.map +1 -0
- package/lib/cards/presenter.d.ts +23 -0
- package/lib/cards/presenter.d.ts.map +1 -0
- package/lib/cards/presenter.js +394 -0
- package/lib/cards/presenter.js.map +1 -0
- package/lib/cards/preview.d.ts +42 -0
- package/lib/cards/preview.d.ts.map +1 -0
- package/lib/cards/preview.js +51 -0
- package/lib/cards/preview.js.map +1 -0
- package/lib/cards.d.ts +12 -120
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +4 -556
- package/lib/cards.js.map +1 -1
- package/lib/compat/section.d.ts +29 -0
- package/lib/compat/section.d.ts.map +1 -0
- package/lib/compat/section.js +82 -0
- package/lib/compat/section.js.map +1 -0
- package/lib/config.d.ts +27 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +61 -1
- package/lib/config.js.map +1 -1
- package/lib/contracts.d.ts +28 -0
- package/lib/contracts.d.ts.map +1 -1
- package/lib/fold-cursor.d.ts +8 -0
- package/lib/fold-cursor.d.ts.map +1 -1
- package/lib/fold-cursor.js +18 -0
- package/lib/fold-cursor.js.map +1 -1
- package/lib/gates/question-card.d.ts +77 -0
- package/lib/gates/question-card.d.ts.map +1 -0
- package/lib/gates/question-card.js +113 -0
- package/lib/gates/question-card.js.map +1 -0
- package/lib/gates/questions.d.ts +127 -0
- package/lib/gates/questions.d.ts.map +1 -0
- package/lib/gates/questions.js +418 -0
- package/lib/gates/questions.js.map +1 -0
- package/lib/gates.d.ts +1 -113
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +1 -484
- package/lib/gates.js.map +1 -1
- package/lib/herdr/client.d.ts +8 -0
- package/lib/herdr/client.d.ts.map +1 -1
- package/lib/herdr/client.js +13 -1
- package/lib/herdr/client.js.map +1 -1
- package/lib/herdr/constants.d.ts +18 -0
- package/lib/herdr/constants.d.ts.map +1 -1
- package/lib/herdr/constants.js +18 -0
- package/lib/herdr/constants.js.map +1 -1
- package/lib/herdr/reporter.d.ts +20 -4
- package/lib/herdr/reporter.d.ts.map +1 -1
- package/lib/herdr/reporter.js +70 -20
- package/lib/herdr/reporter.js.map +1 -1
- package/lib/herdr/state.d.ts +10 -0
- package/lib/herdr/state.d.ts.map +1 -1
- package/lib/herdr/state.js +21 -4
- package/lib/herdr/state.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +348 -2602
- package/lib/index.js.map +1 -1
- package/lib/input/action-catalog.d.ts +74 -0
- package/lib/input/action-catalog.d.ts.map +1 -0
- package/lib/input/action-catalog.js +137 -0
- package/lib/input/action-catalog.js.map +1 -0
- package/lib/input/actions.d.ts +5 -81
- package/lib/input/actions.d.ts.map +1 -1
- package/lib/input/actions.js +4 -625
- package/lib/input/actions.js.map +1 -1
- package/lib/input/completion.d.ts +1 -1
- package/lib/input/completion.d.ts.map +1 -1
- package/lib/input/completion.js +2 -1
- package/lib/input/completion.js.map +1 -1
- package/lib/input/file-index.d.ts +40 -0
- package/lib/input/file-index.d.ts.map +1 -0
- package/lib/input/file-index.js +141 -0
- package/lib/input/file-index.js.map +1 -0
- package/lib/input/file-search.d.ts +1 -38
- package/lib/input/file-search.d.ts.map +1 -1
- package/lib/input/file-search.js +1 -487
- package/lib/input/file-search.js.map +1 -1
- package/lib/input/key-press.d.ts +57 -0
- package/lib/input/key-press.d.ts.map +1 -0
- package/lib/input/key-press.js +218 -0
- package/lib/input/key-press.js.map +1 -0
- package/lib/input/keymap-conflicts.d.ts +59 -0
- package/lib/input/keymap-conflicts.d.ts.map +1 -0
- package/lib/input/keymap-conflicts.js +292 -0
- package/lib/input/keymap-conflicts.js.map +1 -0
- package/lib/input/keymap-settings.js +1 -1
- package/lib/input/keymap-settings.js.map +1 -1
- package/lib/input/keymap.d.ts.map +1 -1
- package/lib/input/keymap.js +3 -1
- package/lib/input/keymap.js.map +1 -1
- package/lib/input/workspace-files.d.ts +10 -0
- package/lib/input/workspace-files.d.ts.map +1 -0
- package/lib/input/workspace-files.js +359 -0
- package/lib/input/workspace-files.js.map +1 -0
- package/lib/install-skills.d.ts +39 -0
- package/lib/install-skills.d.ts.map +1 -0
- package/lib/install-skills.js +273 -0
- package/lib/install-skills.js.map +1 -0
- package/lib/keys-command.d.ts +2 -1
- package/lib/keys-command.d.ts.map +1 -1
- package/lib/keys-command.js +2 -1
- package/lib/keys-command.js.map +1 -1
- package/lib/model-list.d.ts +37 -0
- package/lib/model-list.d.ts.map +1 -0
- package/lib/model-list.js +60 -0
- package/lib/model-list.js.map +1 -0
- package/lib/startup.d.ts +8 -0
- package/lib/startup.d.ts.map +1 -1
- package/lib/startup.js +120 -24
- package/lib/startup.js.map +1 -1
- package/lib/subagents.d.ts +7 -3
- package/lib/subagents.d.ts.map +1 -1
- package/lib/subagents.js +28 -4
- package/lib/subagents.js.map +1 -1
- package/lib/surface/appearance-preferences.d.ts +26 -0
- package/lib/surface/appearance-preferences.d.ts.map +1 -0
- package/lib/surface/appearance-preferences.js +139 -0
- package/lib/surface/appearance-preferences.js.map +1 -0
- package/lib/surface/appearance.d.ts +87 -0
- package/lib/surface/appearance.d.ts.map +1 -0
- package/lib/surface/appearance.js +353 -0
- package/lib/surface/appearance.js.map +1 -0
- package/lib/surface/background-work.d.ts +51 -0
- package/lib/surface/background-work.d.ts.map +1 -0
- package/lib/surface/background-work.js +172 -0
- package/lib/surface/background-work.js.map +1 -0
- package/lib/surface/commands.d.ts +82 -0
- package/lib/surface/commands.d.ts.map +1 -0
- package/lib/surface/commands.js +370 -0
- package/lib/surface/commands.js.map +1 -0
- package/lib/surface/modal-input.d.ts +59 -0
- package/lib/surface/modal-input.d.ts.map +1 -0
- package/lib/surface/modal-input.js +243 -0
- package/lib/surface/modal-input.js.map +1 -0
- package/lib/surface/model-choice.d.ts +54 -0
- package/lib/surface/model-choice.d.ts.map +1 -0
- package/lib/surface/model-choice.js +325 -0
- package/lib/surface/model-choice.js.map +1 -0
- package/lib/surface/preset-choice.d.ts +78 -0
- package/lib/surface/preset-choice.d.ts.map +1 -0
- package/lib/surface/preset-choice.js +163 -0
- package/lib/surface/preset-choice.js.map +1 -0
- package/lib/surface/prompt-input.d.ts +97 -0
- package/lib/surface/prompt-input.d.ts.map +1 -0
- package/lib/surface/prompt-input.js +215 -0
- package/lib/surface/prompt-input.js.map +1 -0
- package/lib/surface/prompt-memory.d.ts +76 -0
- package/lib/surface/prompt-memory.d.ts.map +1 -0
- package/lib/surface/prompt-memory.js +167 -0
- package/lib/surface/prompt-memory.js.map +1 -0
- package/lib/surface/session-lifecycle.d.ts +120 -0
- package/lib/surface/session-lifecycle.d.ts.map +1 -0
- package/lib/surface/session-lifecycle.js +324 -0
- package/lib/surface/session-lifecycle.js.map +1 -0
- package/lib/surface/session-picker.d.ts +39 -0
- package/lib/surface/session-picker.d.ts.map +1 -0
- package/lib/surface/session-picker.js +107 -0
- package/lib/surface/session-picker.js.map +1 -0
- package/lib/surface/session-view.d.ts +86 -0
- package/lib/surface/session-view.d.ts.map +1 -0
- package/lib/surface/session-view.js +215 -0
- package/lib/surface/session-view.js.map +1 -0
- package/lib/surface/staged-turns.d.ts +81 -0
- package/lib/surface/staged-turns.d.ts.map +1 -0
- package/lib/surface/staged-turns.js +206 -0
- package/lib/surface/staged-turns.js.map +1 -0
- package/lib/surface/terminal-lifecycle.d.ts +76 -0
- package/lib/surface/terminal-lifecycle.d.ts.map +1 -0
- package/lib/surface/terminal-lifecycle.js +222 -0
- package/lib/surface/terminal-lifecycle.js.map +1 -0
- package/lib/terminal-text/scan.d.ts +44 -0
- package/lib/terminal-text/scan.d.ts.map +1 -0
- package/lib/terminal-text/scan.js +195 -0
- package/lib/terminal-text/scan.js.map +1 -0
- package/lib/terminal-text/sgr.d.ts +32 -0
- package/lib/terminal-text/sgr.d.ts.map +1 -0
- package/lib/terminal-text/sgr.js +203 -0
- package/lib/terminal-text/sgr.js.map +1 -0
- package/lib/terminal-text.d.ts +1 -1
- package/lib/terminal-text.d.ts.map +1 -1
- package/lib/terminal-text.js +2 -379
- package/lib/terminal-text.js.map +1 -1
- package/lib/theme-command.js +2 -1
- package/lib/theme-command.js.map +1 -1
- package/lib/theme-defaults.d.ts +64 -0
- package/lib/theme-defaults.d.ts.map +1 -0
- package/lib/theme-defaults.js +248 -0
- package/lib/theme-defaults.js.map +1 -0
- package/lib/theme-files.d.ts +1 -1
- package/lib/theme-files.d.ts.map +1 -1
- package/lib/theme-files.js +1 -1
- package/lib/theme-files.js.map +1 -1
- package/lib/theme-resolver.d.ts +36 -0
- package/lib/theme-resolver.d.ts.map +1 -0
- package/lib/theme-resolver.js +112 -0
- package/lib/theme-resolver.js.map +1 -0
- package/lib/theme-schema.d.ts.map +1 -1
- package/lib/theme-schema.js +3 -2
- package/lib/theme-schema.js.map +1 -1
- package/lib/theme-settings.d.ts +5 -7
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +37 -21
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +0 -89
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +0 -356
- package/lib/theme-tokens.js.map +1 -1
- package/lib/theme.d.ts +1 -1
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +2 -1
- package/lib/theme.js.map +1 -1
- package/lib/tool-display.d.ts.map +1 -1
- package/lib/tool-display.js +2 -1
- package/lib/tool-display.js.map +1 -1
- package/lib/transcript/message-content.d.ts +21 -0
- package/lib/transcript/message-content.d.ts.map +1 -0
- package/lib/transcript/message-content.js +61 -0
- package/lib/transcript/message-content.js.map +1 -0
- package/lib/transcript/tool-calls.d.ts +106 -0
- package/lib/transcript/tool-calls.d.ts.map +1 -0
- package/lib/transcript/tool-calls.js +254 -0
- package/lib/transcript/tool-calls.js.map +1 -0
- package/lib/transcript.d.ts +14 -55
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +31 -253
- package/lib/transcript.js.map +1 -1
- package/lib/ui/dock.d.ts +14 -2
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +52 -10
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +2 -1
- package/lib/ui/editor.js.map +1 -1
- package/lib/ui/keymap-picker.d.ts +2 -1
- package/lib/ui/keymap-picker.d.ts.map +1 -1
- package/lib/ui/keymap-picker.js +1 -0
- package/lib/ui/keymap-picker.js.map +1 -1
- package/lib/ui/view/gate-card.d.ts +21 -0
- package/lib/ui/view/gate-card.d.ts.map +1 -0
- package/lib/ui/view/gate-card.js +104 -0
- package/lib/ui/view/gate-card.js.map +1 -0
- package/lib/ui/view/tool-card.d.ts +149 -0
- package/lib/ui/view/tool-card.d.ts.map +1 -0
- package/lib/ui/view/tool-card.js +429 -0
- package/lib/ui/view/tool-card.js.map +1 -0
- package/lib/ui/view/transcript-message.d.ts +62 -0
- package/lib/ui/view/transcript-message.d.ts.map +1 -0
- package/lib/ui/view/transcript-message.js +158 -0
- package/lib/ui/view/transcript-message.js.map +1 -0
- package/lib/ui/view.d.ts +105 -223
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +132 -679
- package/lib/ui/view.js.map +1 -1
- package/package.json +3 -1
- package/themes/violet-orbit.yaml +7 -5
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { createSessionHistory } from "../agent/history.js";
|
|
2
|
+
import { createToolPresenter } from "../agent/present.js";
|
|
3
|
+
import { FoldCursor, ViewGeneration, replayIfCurrent } from "../fold-cursor.js";
|
|
4
|
+
import { hintKeys } from "../input/actions.js";
|
|
5
|
+
import { TranscriptModel } from "../transcript.js";
|
|
6
|
+
import { WorkFold } from "../work.js";
|
|
7
|
+
/** What the back hint names when the reader has unbound the key it would advertise. */
|
|
8
|
+
const BACK_HINT_FALLBACK = 'ctrl+b';
|
|
9
|
+
/** What the reader presses to leave a view they did not open. */
|
|
10
|
+
export const backHint = (map) => `${hintKeys(map, 'surface.back') || BACK_HINT_FALLBACK} returns to this session`;
|
|
11
|
+
/**
|
|
12
|
+
* The transcript on screen: what is drawn, and never which agent is driven.
|
|
13
|
+
*
|
|
14
|
+
* The model, the work fold and the identity they are folded for are one owner
|
|
15
|
+
* because the reader's view is one thing: a durable event reaches both folds,
|
|
16
|
+
* and a switch of identity resets both. What this owner drives — the agent, its
|
|
17
|
+
* staged cutoff, and the terminal it paints — stays with the surface that
|
|
18
|
+
* composes it, so a reader can watch a child's conversation without moving the
|
|
19
|
+
* commands, the approvals, or the bell.
|
|
20
|
+
*/
|
|
21
|
+
export function createSessionView(ctx, ports) {
|
|
22
|
+
/**
|
|
23
|
+
* The agent scope the tool presenter resolves against.
|
|
24
|
+
*
|
|
25
|
+
* Tools are registered in the scoped world the session's preset mounts, so a
|
|
26
|
+
* card can only read its tool's own render intent while this names that
|
|
27
|
+
* agent. It follows whatever session the transcript is folding, because a
|
|
28
|
+
* child on screen reads through the child's scope, not the parent's.
|
|
29
|
+
*/
|
|
30
|
+
let presentScope;
|
|
31
|
+
const model = new TranscriptModel(createToolPresenter(ctx, () => presentScope));
|
|
32
|
+
const work = new WorkFold();
|
|
33
|
+
/** The session the transcript is showing, which can be one of its children. */
|
|
34
|
+
let viewedSession = ports.initialSession;
|
|
35
|
+
/** Only the newest transcript switch may finish an asynchronous stored-log read. */
|
|
36
|
+
const viewGeneration = new ViewGeneration();
|
|
37
|
+
/**
|
|
38
|
+
* The fold's place in the viewed session's durable sequence.
|
|
39
|
+
*
|
|
40
|
+
* A resumed session is folded while its agent's loop is already live, so the
|
|
41
|
+
* same event can reach the surface twice: once on the stream and once from the
|
|
42
|
+
* log the fold is reading. The sequence number every durable event carries is
|
|
43
|
+
* what tells the two apart.
|
|
44
|
+
*/
|
|
45
|
+
const foldCursor = new FoldCursor();
|
|
46
|
+
/** Every transcript reset revokes reads started for the previous view. */
|
|
47
|
+
const reset = () => {
|
|
48
|
+
const current = viewGeneration.begin();
|
|
49
|
+
model.reset();
|
|
50
|
+
work.reset();
|
|
51
|
+
return current;
|
|
52
|
+
};
|
|
53
|
+
/** Feed one durable event to everything that folds it. */
|
|
54
|
+
const applyEvent = (event) => {
|
|
55
|
+
model.apply(event);
|
|
56
|
+
work.apply(event);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Fold one durable event into the view, unless a staged cursor hides it.
|
|
60
|
+
*
|
|
61
|
+
* Undo never deletes, so the log keeps the hidden suffix; this filter is the
|
|
62
|
+
* one place the transcript and the log disagree about where the session ends.
|
|
63
|
+
*/
|
|
64
|
+
const applyDurable = (session, event) => {
|
|
65
|
+
const cut = ports.stagedCutoff();
|
|
66
|
+
if (cut !== undefined && session === ports.drivenSession() && typeof event.seq === 'number' && event.seq >= cut)
|
|
67
|
+
return;
|
|
68
|
+
if (foldCursor.accept(session, event))
|
|
69
|
+
applyEvent(event);
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Replay a stored session so a resumed run opens on the conversation the
|
|
73
|
+
* reader left, not on an empty screen: the durable log is the transcript.
|
|
74
|
+
*/
|
|
75
|
+
/**
|
|
76
|
+
* Fold one session's history into the transcript.
|
|
77
|
+
*
|
|
78
|
+
* A live session answers from memory, which is the only source that includes
|
|
79
|
+
* events not yet flushed and the only one that works for a child that has not
|
|
80
|
+
* materialized; a session this process is not running falls back to storage.
|
|
81
|
+
*/
|
|
82
|
+
const foldHistory = async (id, through, current = () => true) => {
|
|
83
|
+
// Resolved before the fold so every card reads its tool through the scope
|
|
84
|
+
// that actually registered it; a stored session nobody runs has none.
|
|
85
|
+
presentScope = ports.agentScope(id);
|
|
86
|
+
// Every fold starts a cleared transcript, so a session already known to the
|
|
87
|
+
// cursor is read from its first event rather than from where it left off.
|
|
88
|
+
foldCursor.reset();
|
|
89
|
+
const inMemory = ports.liveEvents(id);
|
|
90
|
+
if (inMemory !== undefined) {
|
|
91
|
+
const events = through === undefined ? inMemory : inMemory.slice(0, through);
|
|
92
|
+
for (const event of events)
|
|
93
|
+
applyDurable(id, event);
|
|
94
|
+
return events.length;
|
|
95
|
+
}
|
|
96
|
+
// Only a live session can be staged: undo acts on the agent this terminal
|
|
97
|
+
// drives, and a stored log has no cursor to hide a suffix from.
|
|
98
|
+
const history = createSessionHistory(ctx);
|
|
99
|
+
if (history === undefined)
|
|
100
|
+
return 0;
|
|
101
|
+
return replayIfCurrent(() => history.read(id), current, event => applyDurable(id, event));
|
|
102
|
+
};
|
|
103
|
+
const replayHistory = async (id) => {
|
|
104
|
+
try {
|
|
105
|
+
const folded = await foldHistory(id);
|
|
106
|
+
if (folded > 0)
|
|
107
|
+
model.notice(`replayed ${folded} events from the stored log`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
model.notice(`could not replay this session: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Show another session in the transcript without leaving this one.
|
|
115
|
+
*
|
|
116
|
+
* A delegation is an ordinary session, so the reader can read what a child is
|
|
117
|
+
* doing rather than only that it exists; the agent this terminal drives does
|
|
118
|
+
* not change, which keeps commands, approvals, and the bell where they were.
|
|
119
|
+
*/
|
|
120
|
+
const showSession = async (id) => {
|
|
121
|
+
const previous = viewedSession;
|
|
122
|
+
const current = reset();
|
|
123
|
+
viewedSession = id;
|
|
124
|
+
try {
|
|
125
|
+
await foldHistory(id, undefined, current);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (!current())
|
|
129
|
+
return;
|
|
130
|
+
model.notice(`could not read that session: ${error instanceof Error ? error.message : String(error)}`);
|
|
131
|
+
}
|
|
132
|
+
if (!current())
|
|
133
|
+
return;
|
|
134
|
+
const driven = ports.drivenSession();
|
|
135
|
+
const returned = id === driven && previous !== driven;
|
|
136
|
+
model.marker(returned ? 'back to the session this terminal drives' : `viewing ${id}`);
|
|
137
|
+
ports.render();
|
|
138
|
+
};
|
|
139
|
+
const showAgentSession = async () => {
|
|
140
|
+
await showSession(ports.drivenSession());
|
|
141
|
+
};
|
|
142
|
+
/** Every event of a session, from memory when this process runs it. */
|
|
143
|
+
const sessionEvents = async (id) => {
|
|
144
|
+
const inMemory = ports.liveEvents(id);
|
|
145
|
+
if (inMemory !== undefined)
|
|
146
|
+
return inMemory;
|
|
147
|
+
const history = createSessionHistory(ctx);
|
|
148
|
+
return history === undefined ? [] : history.read(id);
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Fold one durable event of the session on screen, and repaint.
|
|
152
|
+
*
|
|
153
|
+
* The caller filters on the identity it drives first: the surface state —
|
|
154
|
+
* activity, timer, title, bell, job board — belongs to that agent even while
|
|
155
|
+
* a child is on screen.
|
|
156
|
+
*/
|
|
157
|
+
const observe = (id, event) => {
|
|
158
|
+
if (id !== viewedSession)
|
|
159
|
+
return;
|
|
160
|
+
presentScope = ports.agentScope(id);
|
|
161
|
+
applyDurable(id, event);
|
|
162
|
+
ports.render();
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* The listeners that follow the viewed agent's own stream.
|
|
166
|
+
*
|
|
167
|
+
* The transcript belongs to the session on screen, while status, the bell,
|
|
168
|
+
* and the queue stay with the agent this terminal drives. A live delta or a
|
|
169
|
+
* failure folded into the wrong model would print one session's words as
|
|
170
|
+
* another's, and the durable copy that follows would never correct it.
|
|
171
|
+
*/
|
|
172
|
+
const agentListeners = () => [
|
|
173
|
+
ctx.on('agent/error', payload => {
|
|
174
|
+
if (payload.agent.id !== viewedSession)
|
|
175
|
+
return;
|
|
176
|
+
model.reportError(payload.error);
|
|
177
|
+
ports.render();
|
|
178
|
+
}),
|
|
179
|
+
ctx.on('agent/assistant-stream', payload => {
|
|
180
|
+
if (payload.agent.id !== viewedSession)
|
|
181
|
+
return;
|
|
182
|
+
if (payload.frame.type !== 'chunk')
|
|
183
|
+
return;
|
|
184
|
+
model.applyStreamChunk(payload.frame.chunk);
|
|
185
|
+
ports.render();
|
|
186
|
+
}),
|
|
187
|
+
];
|
|
188
|
+
return {
|
|
189
|
+
viewed: () => viewedSession,
|
|
190
|
+
viewingChild: () => viewedSession !== ports.drivenSession(),
|
|
191
|
+
notice: message => model.notice(message),
|
|
192
|
+
marker: text => model.marker(text),
|
|
193
|
+
reportError: error => model.reportError(error),
|
|
194
|
+
model,
|
|
195
|
+
workState: () => work.state(),
|
|
196
|
+
sessionEvents,
|
|
197
|
+
setPresentScope: scope => {
|
|
198
|
+
presentScope = scope;
|
|
199
|
+
},
|
|
200
|
+
clearPresentScope: () => {
|
|
201
|
+
presentScope = undefined;
|
|
202
|
+
},
|
|
203
|
+
reset,
|
|
204
|
+
setViewed: id => {
|
|
205
|
+
viewedSession = id;
|
|
206
|
+
},
|
|
207
|
+
fold: foldHistory,
|
|
208
|
+
replay: replayHistory,
|
|
209
|
+
show: showSession,
|
|
210
|
+
showDriven: showAgentSession,
|
|
211
|
+
observe,
|
|
212
|
+
agentListeners,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=session-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-view.js","sourceRoot":"","sources":["../../src/surface/session-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
2
|
+
import type { ForkEvent } from '../agent/fork.ts';
|
|
3
|
+
import type { ForkInheritance, TuiAgent } from '../agent/host.ts';
|
|
4
|
+
import { type UndoState } from '../agent/undo.ts';
|
|
5
|
+
/**
|
|
6
|
+
* The staged-turn policy: the cursor over the live log, and the prompts parked
|
|
7
|
+
* behind it.
|
|
8
|
+
*
|
|
9
|
+
* Undo never deletes a prompt. It moves a cursor over the closed turns, folds
|
|
10
|
+
* the transcript back to a cut that stops before the hidden ones, and hands the
|
|
11
|
+
* reader's own words back to the composer. A send while turns are hidden cannot
|
|
12
|
+
* continue in place — the model would then see the prompts the reader undid —
|
|
13
|
+
* so it branches from the visible prefix instead.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* What the staged-turn owner needs from the surface that composes it.
|
|
17
|
+
*
|
|
18
|
+
* Every read is taken at call time: the session, the draft, the queue and the
|
|
19
|
+
* agent in service all move while an undo settles an interrupt, and a captured
|
|
20
|
+
* copy would park the reader's draft in a session they already left.
|
|
21
|
+
*/
|
|
22
|
+
export interface StagedTurnPorts {
|
|
23
|
+
/** Whether the transcript shows a child, where neither command belongs. */
|
|
24
|
+
readonly viewingChild: () => boolean;
|
|
25
|
+
/** The session this terminal drives, which owns the only log a cursor counts. */
|
|
26
|
+
readonly activeSession: () => SessionId;
|
|
27
|
+
/** Every event of a session, which is what the turns are derived from. */
|
|
28
|
+
readonly sessionEvents: (id: SessionId) => Promise<readonly ForkEvent[]>;
|
|
29
|
+
/** Drop the folded transcript, so the next fold starts from nothing. */
|
|
30
|
+
readonly resetTranscript: () => void;
|
|
31
|
+
/** Fold the transcript to an event index, or over the whole log at the tip. */
|
|
32
|
+
readonly foldTranscript: (id: SessionId, cutoff: number | undefined) => Promise<unknown>;
|
|
33
|
+
/** The agent in service, which a plain send submits to and a staged one replaces. */
|
|
34
|
+
readonly drivingAgent: () => TuiAgent | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The lifecycle owner's one replacement boundary: stop the agent in service
|
|
37
|
+
* and let go of everything that projected it.
|
|
38
|
+
*/
|
|
39
|
+
readonly disposeOutgoing: () => Promise<void>;
|
|
40
|
+
/** Start the agent for a session, which is what a replacement joins. */
|
|
41
|
+
readonly openSession: (id: SessionId, resume: boolean, fork?: ForkInheritance) => Promise<TuiAgent>;
|
|
42
|
+
/** The prompts queued on the driven agent, which an interrupt would drop. */
|
|
43
|
+
readonly queuedPrompts: () => readonly string[];
|
|
44
|
+
/** Whether a bank exists to park into, which is how the reader's words survive. */
|
|
45
|
+
readonly canPark: () => boolean;
|
|
46
|
+
/** Park one prompt, in the order the queue replay needs. */
|
|
47
|
+
readonly parkPrompt: (text: string) => Promise<void>;
|
|
48
|
+
/** Whether a turn is open, which the cursor must not cut through. */
|
|
49
|
+
readonly turnRunning: () => boolean;
|
|
50
|
+
/** The text the bar holds, which is the reader's draft until this owner writes it. */
|
|
51
|
+
readonly draft: () => string;
|
|
52
|
+
/** Put text back in the bar. */
|
|
53
|
+
readonly writeDraft: (text: string) => void;
|
|
54
|
+
readonly notice: (message: string) => void;
|
|
55
|
+
readonly render: () => void;
|
|
56
|
+
}
|
|
57
|
+
/** The staged cursor and the operations the composer routes its commands to. */
|
|
58
|
+
export interface StagedTurns {
|
|
59
|
+
/** Event index the transcript must not fold past while turns are hidden. */
|
|
60
|
+
readonly stagedCutoff: () => number | undefined;
|
|
61
|
+
/** The cursor over this session's closed turns. */
|
|
62
|
+
readonly cursor: () => UndoState;
|
|
63
|
+
/** Whether an undo is settling an interrupt, so a second press cannot race it. */
|
|
64
|
+
readonly pending: () => boolean;
|
|
65
|
+
/**
|
|
66
|
+
* The cursor at the tip of the session just opened.
|
|
67
|
+
*
|
|
68
|
+
* A cursor counts the turns of one log, so a session that opens takes a fresh
|
|
69
|
+
* one; the cut goes with it, because a hidden count means nothing on a
|
|
70
|
+
* transcript nothing has been folded from.
|
|
71
|
+
*/
|
|
72
|
+
readonly sessionOpened: (id: SessionId) => void;
|
|
73
|
+
readonly undo: () => void;
|
|
74
|
+
readonly redo: () => void;
|
|
75
|
+
/** Send the reader's prompt, branching first when turns are hidden. */
|
|
76
|
+
readonly send: (text: string) => Promise<void>;
|
|
77
|
+
/** The turn/end the cursor may be waiting on, which the composer's listener hears. */
|
|
78
|
+
readonly turnSettled: () => void;
|
|
79
|
+
}
|
|
80
|
+
export declare function createStagedTurns(ports: StagedTurnPorts): StagedTurns;
|
|
81
|
+
//# sourceMappingURL=staged-turns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staged-turns.d.ts","sourceRoot":"","sources":["../../src/surface/staged-turns.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,EASL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,OAAO,CAAA;IACpC,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,MAAM,SAAS,CAAA;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CAAA;IACxE,wEAAwE;IACxE,QAAQ,CAAC,eAAe,EAAE,MAAM,IAAI,CAAA;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACxF,qFAAqF;IACrF,QAAQ,CAAC,YAAY,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAA;IACjD;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACnG,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,EAAE,MAAM,SAAS,MAAM,EAAE,CAAA;IAC/C,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAA;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAA;IACnC,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,CAAA;IAC5B,gCAAgC;IAChC,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAC5B;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,SAAS,CAAA;IAChC,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAA;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAA;IACzB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9C,sFAAsF;IACtF,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CACjC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,CA6MrE"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
3
|
+
import { hiddenTail, NO_UNDO, redoStep, resetUndo, turnsOf, UNDO_TURN_SETTLE_MS, undoStep, } from "../agent/undo.js";
|
|
4
|
+
export function createStagedTurns(ports) {
|
|
5
|
+
/** The staged cursor for the session this terminal drives. */
|
|
6
|
+
let cursor = NO_UNDO;
|
|
7
|
+
/** Event index the transcript must not fold past while turns are hidden. */
|
|
8
|
+
let cut;
|
|
9
|
+
/** Whether an undo is settling an interrupt, so a second press cannot race it. */
|
|
10
|
+
let pending = false;
|
|
11
|
+
/** Resolver for the turn/end an undo is waiting on, set only while waiting. */
|
|
12
|
+
let settled;
|
|
13
|
+
/** The closed turns of the session this terminal drives, newest last. */
|
|
14
|
+
const currentTurns = async () => turnsOf(await ports.sessionEvents(ports.activeSession()));
|
|
15
|
+
/** Fold the transcript through the staged cut, or the whole log at the tip. */
|
|
16
|
+
const redrawStaged = async () => {
|
|
17
|
+
ports.resetTranscript();
|
|
18
|
+
await ports.foldTranscript(ports.activeSession(), cut);
|
|
19
|
+
};
|
|
20
|
+
/** Park queued prompts one per bank entry, newest first so popping replays queue order. */
|
|
21
|
+
const parkQueued = async (queued) => {
|
|
22
|
+
for (const text of [...queued].reverse())
|
|
23
|
+
await ports.parkPrompt(text);
|
|
24
|
+
};
|
|
25
|
+
/** Wait for the interrupted turn to close, bounded so undo can give up honestly. */
|
|
26
|
+
const waitForTurnEnd = (timeoutMs) => new Promise(resolve => {
|
|
27
|
+
const timer = setTimeout(() => {
|
|
28
|
+
settled = undefined;
|
|
29
|
+
resolve(false);
|
|
30
|
+
}, timeoutMs);
|
|
31
|
+
settled = () => {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
settled = undefined;
|
|
34
|
+
resolve(true);
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Stop the running turn and empty the inbox so the cut lands on a closed
|
|
39
|
+
* turn/end; queued prompts are parked first because cancelling drops them.
|
|
40
|
+
*
|
|
41
|
+
* Returns undefined when the reader's words cannot be kept: a queue with no
|
|
42
|
+
* bank to park it in, or a turn that will not close. Both leave the cursor
|
|
43
|
+
* untouched, so the transcript keeps showing what the model actually saw; a
|
|
44
|
+
* number is how many queued prompts were parked before the turn was stopped.
|
|
45
|
+
*/
|
|
46
|
+
const settleForUndo = async () => {
|
|
47
|
+
const queued = ports.queuedPrompts();
|
|
48
|
+
if (!ports.turnRunning() && queued.length === 0)
|
|
49
|
+
return 0;
|
|
50
|
+
if (queued.length > 0 && !ports.canPark()) {
|
|
51
|
+
ports.notice('queued prompts have no stash to park in; undo cancelled');
|
|
52
|
+
ports.render();
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
ports.drivingAgent()?.interrupt();
|
|
56
|
+
if (queued.length > 0)
|
|
57
|
+
await parkQueued(queued);
|
|
58
|
+
if (ports.turnRunning() && !(await waitForTurnEnd(UNDO_TURN_SETTLE_MS))) {
|
|
59
|
+
ports.notice('could not stop the turn; undo cancelled');
|
|
60
|
+
ports.render();
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return queued.length;
|
|
64
|
+
};
|
|
65
|
+
const runUndoCommand = () => {
|
|
66
|
+
if (pending)
|
|
67
|
+
return;
|
|
68
|
+
pending = true;
|
|
69
|
+
void (async () => {
|
|
70
|
+
if (ports.viewingChild()) {
|
|
71
|
+
ports.notice('undo works on the session this terminal drives · ctrl+b comes back');
|
|
72
|
+
ports.render();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const turns = await currentTurns();
|
|
76
|
+
if (cursor.hidden >= turns.length && !ports.turnRunning()) {
|
|
77
|
+
ports.notice('nothing to undo');
|
|
78
|
+
ports.render();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const draft = ports.draft();
|
|
82
|
+
// Text this state itself restored is not the reader's draft, so undoing
|
|
83
|
+
// again must not park it and end up with two copies.
|
|
84
|
+
const holdsDraft = draft !== '' && draft !== cursor.lastRestored;
|
|
85
|
+
if (holdsDraft && !ports.canPark()) {
|
|
86
|
+
ports.notice('the bar holds a draft and there is no stash to park it in; undo cancelled');
|
|
87
|
+
ports.render();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const parked = await settleForUndo();
|
|
91
|
+
if (parked === undefined)
|
|
92
|
+
return;
|
|
93
|
+
const settledTurns = await currentTurns();
|
|
94
|
+
const next = undoStep(cursor, settledTurns);
|
|
95
|
+
if (next === undefined) {
|
|
96
|
+
ports.notice('nothing to undo');
|
|
97
|
+
ports.render();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (holdsDraft) {
|
|
101
|
+
await ports.parkPrompt(draft);
|
|
102
|
+
ports.notice('the draft in the bar was parked in the stash');
|
|
103
|
+
}
|
|
104
|
+
cursor = next;
|
|
105
|
+
cut = hiddenTail(next, settledTurns)?.seedCount;
|
|
106
|
+
await redrawStaged();
|
|
107
|
+
ports.writeDraft(next.lastRestored);
|
|
108
|
+
// The parking count rides the undo notice: a notice of its own would be
|
|
109
|
+
// replaced before the frame could show it.
|
|
110
|
+
const parkedNote = parked === 0 ? '' : ` · ${parked} queued prompt${parked === 1 ? '' : 's'} parked in the stash`;
|
|
111
|
+
ports.notice(`undo · ${next.hidden} prompt${next.hidden === 1 ? '' : 's'} hidden${parkedNote} · prefix r redo`);
|
|
112
|
+
ports.render();
|
|
113
|
+
})()
|
|
114
|
+
.catch((error) => {
|
|
115
|
+
ports.notice(`undo failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
ports.render();
|
|
117
|
+
})
|
|
118
|
+
.finally(() => {
|
|
119
|
+
pending = false;
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const runRedoCommand = () => {
|
|
123
|
+
void (async () => {
|
|
124
|
+
if (ports.viewingChild()) {
|
|
125
|
+
ports.notice('redo works on the session this terminal drives · ctrl+b comes back');
|
|
126
|
+
ports.render();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const turns = await currentTurns();
|
|
130
|
+
const before = ports.draft();
|
|
131
|
+
const restored = cursor.lastRestored;
|
|
132
|
+
const next = redoStep(cursor, turns);
|
|
133
|
+
if (next === undefined) {
|
|
134
|
+
ports.notice('nothing to redo');
|
|
135
|
+
ports.render();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
cursor = next;
|
|
139
|
+
cut = hiddenTail(next, turns)?.seedCount;
|
|
140
|
+
await redrawStaged();
|
|
141
|
+
// A composer the reader edited is theirs; only text this state wrote is replaced.
|
|
142
|
+
if (before === restored)
|
|
143
|
+
ports.writeDraft(next.lastRestored);
|
|
144
|
+
ports.notice(next.hidden === 0
|
|
145
|
+
? 'redo · back at the newest prompt'
|
|
146
|
+
: `redo · ${next.hidden} prompt${next.hidden === 1 ? '' : 's'} hidden`);
|
|
147
|
+
ports.render();
|
|
148
|
+
})().catch((error) => {
|
|
149
|
+
ports.notice(`redo failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
150
|
+
ports.render();
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Send the reader's prompt, branching first when the transcript is staged.
|
|
155
|
+
*
|
|
156
|
+
* Context is derived from the log, so a send while turns are hidden has to
|
|
157
|
+
* continue in a child seeded with the visible prefix; submitting in place would
|
|
158
|
+
* show the model the prompts the reader undid. Every send passes through here so
|
|
159
|
+
* the branch has one commit point, not one per caller.
|
|
160
|
+
*/
|
|
161
|
+
const commitStagedSend = async (text) => {
|
|
162
|
+
try {
|
|
163
|
+
const previous = ports.drivingAgent();
|
|
164
|
+
if (previous === undefined) {
|
|
165
|
+
ports.notice('the agent is still starting; try again in a moment');
|
|
166
|
+
ports.render();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (cursor.hidden === 0) {
|
|
170
|
+
previous.submit(text);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const source = ports.activeSession();
|
|
174
|
+
const events = await ports.sessionEvents(source);
|
|
175
|
+
const turns = turnsOf(events);
|
|
176
|
+
const tail = hiddenTail(cursor, turns);
|
|
177
|
+
const seed = tail === undefined ? [] : events.slice(0, tail.seedCount);
|
|
178
|
+
const childId = SessionId(`tui-session-${randomUUID()}`);
|
|
179
|
+
await ports.disposeOutgoing();
|
|
180
|
+
const opened = await ports.openSession(childId, false, seed.length === 0 ? undefined : { from: source, events: seed });
|
|
181
|
+
ports.notice(`continuing in a new branch · ${source} keeps the undone turns`);
|
|
182
|
+
opened.submit(text);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
ports.notice(`could not send: ${error instanceof Error ? error.message : String(error)}`);
|
|
186
|
+
ports.render();
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
stagedCutoff: () => cut,
|
|
191
|
+
cursor: () => cursor,
|
|
192
|
+
pending: () => pending,
|
|
193
|
+
sessionOpened: id => {
|
|
194
|
+
cursor = resetUndo(id);
|
|
195
|
+
cut = undefined;
|
|
196
|
+
},
|
|
197
|
+
undo: runUndoCommand,
|
|
198
|
+
redo: runRedoCommand,
|
|
199
|
+
send: commitStagedSend,
|
|
200
|
+
// The turn/end the cursor may be waiting on, which only the composer hears.
|
|
201
|
+
turnSettled: () => {
|
|
202
|
+
settled?.();
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=staged-turns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staged-turns.js","sourceRoot":"","sources":["../../src/surface/staged-turns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ProcessTerminal } from '@earendil-works/pi-tui';
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
4
|
+
import { type HerdrReporter } from '../herdr/reporter.ts';
|
|
5
|
+
import { WarningSafeTui } from '../terminal/warning-screen.ts';
|
|
6
|
+
import type { FrameRow } from '../ui/frame.ts';
|
|
7
|
+
/**
|
|
8
|
+
* What the terminal's owner needs from the surface that composes it.
|
|
9
|
+
*
|
|
10
|
+
* Every read is taken at call time: a handoff, an exit, or a copied selection
|
|
11
|
+
* happens against whatever this terminal drives when it happens, and a captured
|
|
12
|
+
* copy would name the session the surface happened to open first.
|
|
13
|
+
*/
|
|
14
|
+
export interface TerminalLifecyclePorts {
|
|
15
|
+
/** A frame that could not be drawn reaches the transcript through here. */
|
|
16
|
+
readonly reportFrameError: (error: unknown) => void;
|
|
17
|
+
/** Say something the screen cannot: a failed handoff is one. */
|
|
18
|
+
readonly notice: (message: string) => void;
|
|
19
|
+
/** The rows the last frame drew, which is what a copied selection is read through. */
|
|
20
|
+
readonly copyRows: () => readonly FrameRow[];
|
|
21
|
+
/** The session this terminal drives, which is what an exit hint can offer back. */
|
|
22
|
+
readonly activeSession: () => SessionId;
|
|
23
|
+
/** Whether a session was really opened; a run that opened none has nothing to point at. */
|
|
24
|
+
readonly sessionOpened: () => boolean;
|
|
25
|
+
/** Whether a turn is open, which the title names once the screen comes back. */
|
|
26
|
+
readonly turnRunning: () => boolean;
|
|
27
|
+
/** Stop the clock that repaints a running turn; an exit does not wait for it. */
|
|
28
|
+
readonly stopClock: () => void;
|
|
29
|
+
/** Leave the process with the status the caller owns. */
|
|
30
|
+
readonly exit: (code: number) => void;
|
|
31
|
+
/** The draft the bar holds, which is what the reader's own editor is handed. */
|
|
32
|
+
readonly draftText: () => string;
|
|
33
|
+
/** Whether a question borrowed the bar, so an edited draft must wait behind it. */
|
|
34
|
+
readonly draftBorrowed: () => boolean;
|
|
35
|
+
/** Park an edited draft behind a borrowed bar instead of answering the question. */
|
|
36
|
+
readonly holdDraft: (text: string) => void;
|
|
37
|
+
/** Put an edited draft back into the bar. */
|
|
38
|
+
readonly writeDraft: (text: string) => void;
|
|
39
|
+
}
|
|
40
|
+
/** The handles and operations the composing surface routes to this owner. */
|
|
41
|
+
export interface TerminalLifecycle {
|
|
42
|
+
readonly terminal: ProcessTerminal;
|
|
43
|
+
readonly tui: WarningSafeTui;
|
|
44
|
+
/** The pane's agent row; the surface reports through it and this owner releases it. */
|
|
45
|
+
readonly herdr: HerdrReporter;
|
|
46
|
+
/**
|
|
47
|
+
* The surface's teardowns, in the order they were registered.
|
|
48
|
+
*
|
|
49
|
+
* The array is handed out rather than wrapped in a register function because
|
|
50
|
+
* the composing surface registers most of them, several by spreading a
|
|
51
|
+
* listener list: one array is what keeps a spread and a single push in the
|
|
52
|
+
* same order, and the unwind below reverses that one order.
|
|
53
|
+
*/
|
|
54
|
+
readonly disposers: Array<() => void>;
|
|
55
|
+
/** Write to the tty, but only while this surface owns it. */
|
|
56
|
+
readonly writeTerminal: (text: string) => void;
|
|
57
|
+
readonly handedOver: () => boolean;
|
|
58
|
+
readonly disposed: () => boolean;
|
|
59
|
+
readonly exited: () => boolean;
|
|
60
|
+
readonly requestExit: (code: number, reason?: string) => void;
|
|
61
|
+
/** Hand the draft to the reader's own editor and take back what it saved. */
|
|
62
|
+
readonly editDraft: () => void;
|
|
63
|
+
/** Register the supervisor signals that end this surface the way a quit does. */
|
|
64
|
+
readonly signalShutdown: () => () => void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The terminal's lifetime: the screen this surface owns, the way out of it, and
|
|
68
|
+
* the child that borrows it.
|
|
69
|
+
*
|
|
70
|
+
* Ownership is the whole subject: the alternate screen, the hooks that put the
|
|
71
|
+
* shell back, and the exit are one mechanism, and a second writer would not
|
|
72
|
+
* know that the reader's own editor holds the tty. The composer keeps the
|
|
73
|
+
* widgets; this owner keeps every byte written to the terminal.
|
|
74
|
+
*/
|
|
75
|
+
export declare function createTerminalLifecycle(ctx: Context, ports: TerminalLifecyclePorts): TerminalLifecycle;
|
|
76
|
+
//# sourceMappingURL=terminal-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-lifecycle.d.ts","sourceRoot":"","sources":["../../src/surface/terminal-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAO9E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACnD,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,SAAS,QAAQ,EAAE,CAAA;IAC5C,mFAAmF;IACnF,QAAQ,CAAC,aAAa,EAAE,MAAM,SAAS,CAAA;IACvC,2FAA2F;IAC3F,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAA;IACrC,gFAAgF;IAChF,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAA;IACnC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAA;IAC9B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,MAAM,MAAM,CAAA;IAChC,mFAAmF;IACnF,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAA;IACrC,oFAAoF;IACpF,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5C;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAA;IAC5B,uFAAuF;IACvF,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAA;IACrC,6DAA6D;IAC7D,QAAQ,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7D,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAA;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,MAAM,MAAM,IAAI,CAAA;CAC1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,sBAAsB,GAAG,iBAAiB,CAuMtG"}
|