@sagmans/dsh-tui 0.6.0 → 0.7.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.
Files changed (250) hide show
  1. package/.agents/skills/dsh-tui-dogfood/SKILL.md +83 -0
  2. package/.agents/skills/dsh-tui-dogfood/references/home-state.md +78 -0
  3. package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +133 -0
  4. package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +417 -0
  5. package/.agents/skills/dsh-tui-update-models/SKILL.md +121 -0
  6. package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +162 -0
  7. package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +178 -0
  8. package/README.md +99 -5
  9. package/lib/agent/present.d.ts.map +1 -1
  10. package/lib/agent/present.js +2 -1
  11. package/lib/agent/present.js.map +1 -1
  12. package/lib/cards/composition.d.ts +68 -0
  13. package/lib/cards/composition.d.ts.map +1 -0
  14. package/lib/cards/composition.js +117 -0
  15. package/lib/cards/composition.js.map +1 -0
  16. package/lib/cards/presenter.d.ts +23 -0
  17. package/lib/cards/presenter.d.ts.map +1 -0
  18. package/lib/cards/presenter.js +394 -0
  19. package/lib/cards/presenter.js.map +1 -0
  20. package/lib/cards/preview.d.ts +42 -0
  21. package/lib/cards/preview.d.ts.map +1 -0
  22. package/lib/cards/preview.js +51 -0
  23. package/lib/cards/preview.js.map +1 -0
  24. package/lib/cards.d.ts +12 -120
  25. package/lib/cards.d.ts.map +1 -1
  26. package/lib/cards.js +4 -556
  27. package/lib/cards.js.map +1 -1
  28. package/lib/compat/section.d.ts +29 -0
  29. package/lib/compat/section.d.ts.map +1 -0
  30. package/lib/compat/section.js +82 -0
  31. package/lib/compat/section.js.map +1 -0
  32. package/lib/config.d.ts +27 -2
  33. package/lib/config.d.ts.map +1 -1
  34. package/lib/config.js +61 -1
  35. package/lib/config.js.map +1 -1
  36. package/lib/contracts.d.ts +28 -0
  37. package/lib/contracts.d.ts.map +1 -1
  38. package/lib/fold-cursor.d.ts +8 -0
  39. package/lib/fold-cursor.d.ts.map +1 -1
  40. package/lib/fold-cursor.js +18 -0
  41. package/lib/fold-cursor.js.map +1 -1
  42. package/lib/gates/question-card.d.ts +77 -0
  43. package/lib/gates/question-card.d.ts.map +1 -0
  44. package/lib/gates/question-card.js +113 -0
  45. package/lib/gates/question-card.js.map +1 -0
  46. package/lib/gates/questions.d.ts +127 -0
  47. package/lib/gates/questions.d.ts.map +1 -0
  48. package/lib/gates/questions.js +418 -0
  49. package/lib/gates/questions.js.map +1 -0
  50. package/lib/gates.d.ts +1 -113
  51. package/lib/gates.d.ts.map +1 -1
  52. package/lib/gates.js +1 -484
  53. package/lib/gates.js.map +1 -1
  54. package/lib/index.d.ts +1 -0
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.js +343 -2602
  57. package/lib/index.js.map +1 -1
  58. package/lib/input/action-catalog.d.ts +74 -0
  59. package/lib/input/action-catalog.d.ts.map +1 -0
  60. package/lib/input/action-catalog.js +137 -0
  61. package/lib/input/action-catalog.js.map +1 -0
  62. package/lib/input/actions.d.ts +5 -81
  63. package/lib/input/actions.d.ts.map +1 -1
  64. package/lib/input/actions.js +4 -625
  65. package/lib/input/actions.js.map +1 -1
  66. package/lib/input/completion.d.ts +1 -1
  67. package/lib/input/completion.d.ts.map +1 -1
  68. package/lib/input/completion.js +2 -1
  69. package/lib/input/completion.js.map +1 -1
  70. package/lib/input/file-index.d.ts +40 -0
  71. package/lib/input/file-index.d.ts.map +1 -0
  72. package/lib/input/file-index.js +141 -0
  73. package/lib/input/file-index.js.map +1 -0
  74. package/lib/input/file-search.d.ts +1 -38
  75. package/lib/input/file-search.d.ts.map +1 -1
  76. package/lib/input/file-search.js +1 -487
  77. package/lib/input/file-search.js.map +1 -1
  78. package/lib/input/key-press.d.ts +57 -0
  79. package/lib/input/key-press.d.ts.map +1 -0
  80. package/lib/input/key-press.js +218 -0
  81. package/lib/input/key-press.js.map +1 -0
  82. package/lib/input/keymap-conflicts.d.ts +59 -0
  83. package/lib/input/keymap-conflicts.d.ts.map +1 -0
  84. package/lib/input/keymap-conflicts.js +292 -0
  85. package/lib/input/keymap-conflicts.js.map +1 -0
  86. package/lib/input/keymap-settings.js +1 -1
  87. package/lib/input/keymap-settings.js.map +1 -1
  88. package/lib/input/keymap.d.ts.map +1 -1
  89. package/lib/input/keymap.js +3 -1
  90. package/lib/input/keymap.js.map +1 -1
  91. package/lib/input/workspace-files.d.ts +10 -0
  92. package/lib/input/workspace-files.d.ts.map +1 -0
  93. package/lib/input/workspace-files.js +359 -0
  94. package/lib/input/workspace-files.js.map +1 -0
  95. package/lib/install-skills.d.ts +20 -0
  96. package/lib/install-skills.d.ts.map +1 -0
  97. package/lib/install-skills.js +198 -0
  98. package/lib/install-skills.js.map +1 -0
  99. package/lib/keys-command.d.ts +2 -1
  100. package/lib/keys-command.d.ts.map +1 -1
  101. package/lib/keys-command.js +2 -1
  102. package/lib/keys-command.js.map +1 -1
  103. package/lib/model-list.d.ts +37 -0
  104. package/lib/model-list.d.ts.map +1 -0
  105. package/lib/model-list.js +60 -0
  106. package/lib/model-list.js.map +1 -0
  107. package/lib/startup.d.ts +8 -0
  108. package/lib/startup.d.ts.map +1 -1
  109. package/lib/startup.js +120 -24
  110. package/lib/startup.js.map +1 -1
  111. package/lib/subagents.d.ts +7 -3
  112. package/lib/subagents.d.ts.map +1 -1
  113. package/lib/subagents.js +28 -4
  114. package/lib/subagents.js.map +1 -1
  115. package/lib/surface/appearance-preferences.d.ts +26 -0
  116. package/lib/surface/appearance-preferences.d.ts.map +1 -0
  117. package/lib/surface/appearance-preferences.js +139 -0
  118. package/lib/surface/appearance-preferences.js.map +1 -0
  119. package/lib/surface/appearance.d.ts +87 -0
  120. package/lib/surface/appearance.d.ts.map +1 -0
  121. package/lib/surface/appearance.js +353 -0
  122. package/lib/surface/appearance.js.map +1 -0
  123. package/lib/surface/background-work.d.ts +49 -0
  124. package/lib/surface/background-work.d.ts.map +1 -0
  125. package/lib/surface/background-work.js +146 -0
  126. package/lib/surface/background-work.js.map +1 -0
  127. package/lib/surface/commands.d.ts +80 -0
  128. package/lib/surface/commands.d.ts.map +1 -0
  129. package/lib/surface/commands.js +364 -0
  130. package/lib/surface/commands.js.map +1 -0
  131. package/lib/surface/modal-input.d.ts +58 -0
  132. package/lib/surface/modal-input.d.ts.map +1 -0
  133. package/lib/surface/modal-input.js +237 -0
  134. package/lib/surface/modal-input.js.map +1 -0
  135. package/lib/surface/model-choice.d.ts +54 -0
  136. package/lib/surface/model-choice.d.ts.map +1 -0
  137. package/lib/surface/model-choice.js +325 -0
  138. package/lib/surface/model-choice.js.map +1 -0
  139. package/lib/surface/preset-choice.d.ts +78 -0
  140. package/lib/surface/preset-choice.d.ts.map +1 -0
  141. package/lib/surface/preset-choice.js +163 -0
  142. package/lib/surface/preset-choice.js.map +1 -0
  143. package/lib/surface/prompt-input.d.ts +97 -0
  144. package/lib/surface/prompt-input.d.ts.map +1 -0
  145. package/lib/surface/prompt-input.js +215 -0
  146. package/lib/surface/prompt-input.js.map +1 -0
  147. package/lib/surface/prompt-memory.d.ts +76 -0
  148. package/lib/surface/prompt-memory.d.ts.map +1 -0
  149. package/lib/surface/prompt-memory.js +167 -0
  150. package/lib/surface/prompt-memory.js.map +1 -0
  151. package/lib/surface/session-lifecycle.d.ts +120 -0
  152. package/lib/surface/session-lifecycle.d.ts.map +1 -0
  153. package/lib/surface/session-lifecycle.js +321 -0
  154. package/lib/surface/session-lifecycle.js.map +1 -0
  155. package/lib/surface/session-picker.d.ts +39 -0
  156. package/lib/surface/session-picker.d.ts.map +1 -0
  157. package/lib/surface/session-picker.js +107 -0
  158. package/lib/surface/session-picker.js.map +1 -0
  159. package/lib/surface/session-view.d.ts +86 -0
  160. package/lib/surface/session-view.d.ts.map +1 -0
  161. package/lib/surface/session-view.js +215 -0
  162. package/lib/surface/session-view.js.map +1 -0
  163. package/lib/surface/staged-turns.d.ts +81 -0
  164. package/lib/surface/staged-turns.d.ts.map +1 -0
  165. package/lib/surface/staged-turns.js +206 -0
  166. package/lib/surface/staged-turns.js.map +1 -0
  167. package/lib/surface/terminal-lifecycle.d.ts +76 -0
  168. package/lib/surface/terminal-lifecycle.d.ts.map +1 -0
  169. package/lib/surface/terminal-lifecycle.js +222 -0
  170. package/lib/surface/terminal-lifecycle.js.map +1 -0
  171. package/lib/terminal-text/scan.d.ts +44 -0
  172. package/lib/terminal-text/scan.d.ts.map +1 -0
  173. package/lib/terminal-text/scan.js +195 -0
  174. package/lib/terminal-text/scan.js.map +1 -0
  175. package/lib/terminal-text/sgr.d.ts +32 -0
  176. package/lib/terminal-text/sgr.d.ts.map +1 -0
  177. package/lib/terminal-text/sgr.js +203 -0
  178. package/lib/terminal-text/sgr.js.map +1 -0
  179. package/lib/terminal-text.d.ts +1 -1
  180. package/lib/terminal-text.d.ts.map +1 -1
  181. package/lib/terminal-text.js +2 -379
  182. package/lib/terminal-text.js.map +1 -1
  183. package/lib/theme-command.js +2 -1
  184. package/lib/theme-command.js.map +1 -1
  185. package/lib/theme-defaults.d.ts +64 -0
  186. package/lib/theme-defaults.d.ts.map +1 -0
  187. package/lib/theme-defaults.js +248 -0
  188. package/lib/theme-defaults.js.map +1 -0
  189. package/lib/theme-resolver.d.ts +36 -0
  190. package/lib/theme-resolver.d.ts.map +1 -0
  191. package/lib/theme-resolver.js +112 -0
  192. package/lib/theme-resolver.js.map +1 -0
  193. package/lib/theme-schema.d.ts.map +1 -1
  194. package/lib/theme-schema.js +3 -2
  195. package/lib/theme-schema.js.map +1 -1
  196. package/lib/theme-settings.d.ts +5 -7
  197. package/lib/theme-settings.d.ts.map +1 -1
  198. package/lib/theme-settings.js +27 -19
  199. package/lib/theme-settings.js.map +1 -1
  200. package/lib/theme-tokens.d.ts +0 -89
  201. package/lib/theme-tokens.d.ts.map +1 -1
  202. package/lib/theme-tokens.js +0 -356
  203. package/lib/theme-tokens.js.map +1 -1
  204. package/lib/theme.d.ts +1 -1
  205. package/lib/theme.d.ts.map +1 -1
  206. package/lib/theme.js +2 -1
  207. package/lib/theme.js.map +1 -1
  208. package/lib/tool-display.d.ts.map +1 -1
  209. package/lib/tool-display.js +2 -1
  210. package/lib/tool-display.js.map +1 -1
  211. package/lib/transcript/message-content.d.ts +21 -0
  212. package/lib/transcript/message-content.d.ts.map +1 -0
  213. package/lib/transcript/message-content.js +61 -0
  214. package/lib/transcript/message-content.js.map +1 -0
  215. package/lib/transcript/tool-calls.d.ts +106 -0
  216. package/lib/transcript/tool-calls.d.ts.map +1 -0
  217. package/lib/transcript/tool-calls.js +254 -0
  218. package/lib/transcript/tool-calls.js.map +1 -0
  219. package/lib/transcript.d.ts +14 -55
  220. package/lib/transcript.d.ts.map +1 -1
  221. package/lib/transcript.js +31 -253
  222. package/lib/transcript.js.map +1 -1
  223. package/lib/ui/dock.d.ts +14 -2
  224. package/lib/ui/dock.d.ts.map +1 -1
  225. package/lib/ui/dock.js +52 -10
  226. package/lib/ui/dock.js.map +1 -1
  227. package/lib/ui/editor.d.ts.map +1 -1
  228. package/lib/ui/editor.js +2 -1
  229. package/lib/ui/editor.js.map +1 -1
  230. package/lib/ui/keymap-picker.d.ts +2 -1
  231. package/lib/ui/keymap-picker.d.ts.map +1 -1
  232. package/lib/ui/keymap-picker.js +1 -0
  233. package/lib/ui/keymap-picker.js.map +1 -1
  234. package/lib/ui/view/gate-card.d.ts +21 -0
  235. package/lib/ui/view/gate-card.d.ts.map +1 -0
  236. package/lib/ui/view/gate-card.js +104 -0
  237. package/lib/ui/view/gate-card.js.map +1 -0
  238. package/lib/ui/view/tool-card.d.ts +138 -0
  239. package/lib/ui/view/tool-card.d.ts.map +1 -0
  240. package/lib/ui/view/tool-card.js +413 -0
  241. package/lib/ui/view/tool-card.js.map +1 -0
  242. package/lib/ui/view/transcript-message.d.ts +62 -0
  243. package/lib/ui/view/transcript-message.d.ts.map +1 -0
  244. package/lib/ui/view/transcript-message.js +158 -0
  245. package/lib/ui/view/transcript-message.js.map +1 -0
  246. package/lib/ui/view.d.ts +80 -220
  247. package/lib/ui/view.d.ts.map +1 -1
  248. package/lib/ui/view.js +81 -675
  249. package/lib/ui/view.js.map +1 -1
  250. package/package.json +3 -1
@@ -0,0 +1,120 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { Agent } from '@deepseek-ai/dsh-agent';
3
+ import { SessionId } from '@deepseek-ai/dsh-session';
4
+ import { type ForkEvent } from '../agent/fork.ts';
5
+ import { type ForkInheritance, type TuiAgent } from '../agent/host.ts';
6
+ import type { HerdrReporter } from '../herdr/reporter.ts';
7
+ /** The session this process runs, as much of it as a driven read needs. */
8
+ export interface LiveSession {
9
+ /** The events this process holds unflushed, which storage alone does not. */
10
+ readonly snapshotEvents?: () => readonly ForkEvent[];
11
+ }
12
+ /**
13
+ * What the session's lifecycle owner needs from the surface that composes it.
14
+ *
15
+ * Every read is taken at call time: the session, the scrollback and the queue
16
+ * all move while a transition settles, and a captured copy would name the
17
+ * session this terminal drove before the reader moved.
18
+ */
19
+ export interface SessionLifecyclePorts {
20
+ /** The session this run was launched for; another is reached only by switching. */
21
+ readonly initialSession: SessionId;
22
+ /** The route this run was launched with: the model, and the provider it names. */
23
+ readonly model: string | undefined;
24
+ readonly provider: string | undefined;
25
+ /** Whether this run rings for a turn that ran long enough. */
26
+ readonly bell: boolean;
27
+ /** The mode a session takes, settled before the transcript is touched. */
28
+ readonly presetFor: (id: SessionId, resume: boolean, fork: ForkInheritance | undefined) => Promise<string | undefined>;
29
+ /** Install the session's own route; the world the preset mounts reads it back. */
30
+ readonly installModelChoice: (agentCtx: Context) => void;
31
+ /** Mount the mode a new session runs into the agent's own scope. */
32
+ readonly mountPreset: (agentCtx: Context, preset: string) => Promise<void>;
33
+ /** The live session this process runs, which is the only source holding the queue. */
34
+ readonly liveSession: (id: SessionId) => LiveSession | undefined;
35
+ /** Re-arm the bar's completion against the world the new agent mounted. */
36
+ readonly installCompletion: () => void;
37
+ /** Every event of a session, which a fork cut is derived from. */
38
+ readonly sessionEvents: (id: SessionId) => Promise<readonly ForkEvent[]>;
39
+ /** Show a session without folding it; the open owns the fold that follows. */
40
+ readonly setViewed: (id: SessionId) => void;
41
+ /** The scope a folded card reads its tool through. */
42
+ readonly setPresentScope: (scope: Agent | undefined) => void;
43
+ /** Drop that scope; the outgoing agent is torn down after it. */
44
+ readonly clearPresentScope: () => void;
45
+ readonly resetTranscript: () => void;
46
+ readonly replay: (id: SessionId) => Promise<void>;
47
+ readonly fold: (id: SessionId) => Promise<number>;
48
+ readonly notice: (message: string) => void;
49
+ readonly render: () => void;
50
+ /** The prompt memory's per-session reset, taken when a session is really opened. */
51
+ readonly promptMemorySessionOpened: () => void;
52
+ /** The staged owner's fresh cursor for the session just opened. */
53
+ readonly stagedSessionOpened: (id: SessionId) => void;
54
+ /** The turn/end an undo may be parked waiting for. */
55
+ readonly turnSettled: () => void;
56
+ /** The parent's catalog names the child; lifecycle events carry only its id. */
57
+ readonly acceptCatalog: (info: unknown) => void;
58
+ /** Drop the roster of the session a transition lets go of. */
59
+ readonly resetRoster: () => void;
60
+ /** A job the turn started may have settled while the reader watched elsewhere. */
61
+ readonly refreshJobs: () => void;
62
+ /** The pane's agent row, which hears the driver rather than each turn. */
63
+ readonly herdr: HerdrReporter;
64
+ /** Write to the tty, but only while this surface owns it. */
65
+ readonly writeTerminal: (text: string) => void;
66
+ /** Whether the exit has begun, which mutes the bell. */
67
+ readonly exiting: () => boolean;
68
+ /** The surface's teardowns, in the order they are registered. */
69
+ readonly disposers: Array<() => void>;
70
+ }
71
+ /** The agent this terminal drives, and every read or operation the composer takes from it. */
72
+ export interface SessionLifecycle {
73
+ /** The session this surface drives: commands, approvals, and the bell belong to it. */
74
+ readonly activeSession: () => SessionId;
75
+ /** The agent in service, or undefined while a transition creates the next one. */
76
+ readonly drivingAgent: () => TuiAgent | undefined;
77
+ /** Whether a turn is open, which the clock, the title and the bell read. */
78
+ readonly turnRunning: () => boolean;
79
+ /** What the running-state clock reports: a turn, and when it started. */
80
+ readonly activity: () => {
81
+ readonly running: boolean;
82
+ readonly startedAt: number | undefined;
83
+ };
84
+ /** Whether a session was really opened, which is what an exit hint can name. */
85
+ readonly sessionOpened: () => boolean;
86
+ /** The prompts queued on the driven agent, which an interrupt would drop. */
87
+ readonly queuedPrompts: () => readonly string[];
88
+ /** Stop the clock that repaints a running turn; an exit does not wait for it. */
89
+ readonly stopClock: () => void;
90
+ /**
91
+ * Stop the agent in service and let go of what it projected: the handle and its
92
+ * projections go before the world they name is torn down, and the stop is
93
+ * awaited so the next agent joins a surface nothing is still writing to.
94
+ */
95
+ readonly disposeOutgoing: () => Promise<void>;
96
+ /** Start the agent for a session, which is what a replacement joins. */
97
+ readonly openAgent: (id: SessionId, resume: boolean, fork?: ForkInheritance) => Promise<TuiAgent>;
98
+ /** Move the surface to another stored session without leaving the terminal. */
99
+ readonly switchSession: (id: SessionId) => Promise<void>;
100
+ /** Start a fresh session without leaving the terminal. */
101
+ readonly runNewCommand: (title: string) => void;
102
+ /** Compose this session's agent again without leaving the conversation. */
103
+ readonly runReloadCommand: () => void;
104
+ /**
105
+ * Branch this conversation and continue in the branch: a real session that
106
+ * inherits a prefix of this one, cut at the last completed turn because half an
107
+ * exchange is not a state to hand a model.
108
+ */
109
+ readonly runForkCommand: (title: string) => void;
110
+ /** Give this session a title. */
111
+ readonly runRenameCommand: (title: string) => void;
112
+ /** The driven half of one durable event; the caller folds the viewed half. */
113
+ readonly observe: (session: {
114
+ readonly id: SessionId;
115
+ }, event: ForkEvent) => void;
116
+ /** The listeners that follow the driver rather than each turn. */
117
+ readonly driverListeners: () => readonly (() => void)[];
118
+ }
119
+ export declare function createSessionLifecycle(ctx: Context, ports: SessionLifecyclePorts): SessionLifecycle;
120
+ //# sourceMappingURL=session-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-lifecycle.d.ts","sourceRoot":"","sources":["../../src/surface/session-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,321 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { SessionId } from '@deepseek-ai/dsh-session';
3
+ import { forkPoint } from "../agent/fork.js";
4
+ import { startAgent } from "../agent/host.js";
5
+ import { driverReportFor, sessionStartReason } from "../herdr/state.js";
6
+ import { pendingPrompts } from "../queue.js";
7
+ import { BELL, shouldRingBell } from "../terminal/bell.js";
8
+ import { windowTitle } from "../terminal/title.js";
9
+ /**
10
+ * The agent this terminal drives: its identity, its activity, and every
11
+ * transition that replaces it. One owner, because a replacement is one thing:
12
+ * the handle, the turn it ran, the scope its cards read through, the transcript
13
+ * folded from it, and its roster all move together.
14
+ */
15
+ /** How often the running-state clock repaints while a turn is open. */
16
+ const STATUS_TICK_MS = 1000;
17
+ export function createSessionLifecycle(ctx, ports) {
18
+ /** The session this surface drives: commands, approvals, and the bell belong to it. */
19
+ let activeSession = ports.initialSession;
20
+ /** The agent in service, or undefined while a transition creates the next one. */
21
+ let agent;
22
+ /** Whether a turn is open, which is what the clock repaints for. */
23
+ let turnOpen = false;
24
+ /** When the open turn started, which the status facts time it from. */
25
+ let turnStartedAt;
26
+ /** Whether a session was really opened, which is what an exit hint can name. */
27
+ let sessionOpened = false;
28
+ // The queue is read from the agent this terminal drives rather than from the
29
+ // session on screen, because it sits on the editor that submits to that agent.
30
+ const queuedPrompts = () => pendingPrompts(ctx, ports.liveSession(activeSession));
31
+ // Only a running turn has anything to say over time, so the clock stops with it.
32
+ const statusTicker = setInterval(() => {
33
+ if (turnOpen)
34
+ ports.render();
35
+ }, STATUS_TICK_MS);
36
+ ports.disposers.push(() => clearInterval(statusTicker));
37
+ const stopClock = () => clearInterval(statusTicker);
38
+ /**
39
+ * Let go of the agent in service and everything projected from it, handing the
40
+ * handle back to be stopped.
41
+ *
42
+ * `clearScope` is the path's, not this helper's: a replacement drops the
43
+ * outgoing scope before stopping its agent, and an open that folds history of
44
+ * its own relies on the scope it installs.
45
+ */
46
+ const letGoOfOutgoing = (clearScope) => {
47
+ const previous = agent;
48
+ agent = undefined;
49
+ turnOpen = false;
50
+ // The outgoing turn's clock dies with its agent; leaving it set would time
51
+ // the session being joined by work it never ran.
52
+ turnStartedAt = undefined;
53
+ if (clearScope)
54
+ ports.clearPresentScope();
55
+ ports.resetTranscript();
56
+ ports.resetRoster();
57
+ return previous;
58
+ };
59
+ const disposeOutgoing = async () => {
60
+ const previous = letGoOfOutgoing(true);
61
+ if (previous !== undefined)
62
+ await previous.dispose();
63
+ };
64
+ const openAgent = async (id, resume, fork) => {
65
+ // Settled before the transcript is touched, so a refusal leaves neither a
66
+ // half-replayed session nor a half-composed agent behind.
67
+ const preset = await ports.presetFor(id, resume, fork);
68
+ const handle = await startAgent(ctx, {
69
+ sessionId: id,
70
+ resume,
71
+ model: ports.model,
72
+ provider: ports.provider,
73
+ cwd: process.cwd(),
74
+ preset,
75
+ setup: async (agentCtx) => {
76
+ ports.installModelChoice(agentCtx);
77
+ if (preset !== undefined)
78
+ await ports.mountPreset(agentCtx, preset);
79
+ },
80
+ ...(fork === undefined ? {} : { fork }),
81
+ });
82
+ sessionOpened = true;
83
+ activeSession = id;
84
+ ports.setViewed(id);
85
+ agent = handle;
86
+ // A cursor counts the turns of one log; the session just opened has its own.
87
+ ports.stagedSessionOpened(id);
88
+ ports.promptMemorySessionOpened();
89
+ // agent/status is emitted on transitions only, so a driver that was
90
+ // already running when this surface attached — a resume that wakes
91
+ // straight away — would otherwise stay unreported until it stops. The
92
+ // status is read once here and settled before the session identity, so the
93
+ // report that carries the new session id states the driver's real phase
94
+ // rather than the one the previous session left behind.
95
+ ports.herdr.driver(handle.agent.status);
96
+ // The agent's own id is reported rather than the requested one: a resume can
97
+ // be answered by the session the log actually holds.
98
+ ports.herdr.session({
99
+ id: String(handle.sessionId),
100
+ cwd: process.cwd(),
101
+ reason: sessionStartReason({ forked: fork !== undefined, resumed: resume }),
102
+ });
103
+ // A session with no history to fold still has to present its first live
104
+ // card through the right scope, so the scope is set before any event can.
105
+ ports.setPresentScope(handle.agent);
106
+ // Replayed only once the agent exists, because the fold reads every card
107
+ // through the scope the preset mounted; a fold before that scope existed
108
+ // degraded each replayed card to a bare generic row. The agent's loop is
109
+ // live by now, so the fold and the stream race over the same events; the
110
+ // durable sequence number is what keeps one event from landing twice.
111
+ if (resume)
112
+ await ports.replay(id);
113
+ // A branch inherits the conversation the reader was already reading, so it
114
+ // opens on that history rather than on an empty screen.
115
+ if (fork !== undefined)
116
+ await ports.fold(id);
117
+ ports.disposers.push(() => {
118
+ void handle.dispose();
119
+ });
120
+ ports.installCompletion();
121
+ ports.notice(`session ${handle.sessionId}${resume ? ' (resumed)' : ''}`);
122
+ ports.render();
123
+ // Returned so a caller that replaced the handle can send through the new
124
+ // one without a fresh read of state TypeScript can no longer widen.
125
+ return handle;
126
+ };
127
+ const switchSession = async (id) => {
128
+ await disposeOutgoing();
129
+ await openAgent(id, true);
130
+ };
131
+ const runNewCommand = (title) => {
132
+ if (agent === undefined) {
133
+ ports.notice('the agent is still starting; try again in a moment');
134
+ ports.render();
135
+ return;
136
+ }
137
+ void (async () => {
138
+ const previous = letGoOfOutgoing(false);
139
+ if (previous !== undefined)
140
+ await previous.dispose();
141
+ await openAgent(SessionId(`tui-session-${randomUUID()}`), false);
142
+ if (title !== '')
143
+ runRenameCommand(title);
144
+ ports.notice('started a new session');
145
+ ports.render();
146
+ })().catch((error) => {
147
+ ports.notice(`could not start a session: ${error instanceof Error ? error.message : String(error)}`);
148
+ ports.render();
149
+ });
150
+ };
151
+ /**
152
+ * Compose this session's agent again without leaving the conversation: a
153
+ * preset's standing mount only re-reads its composition file for an agent that
154
+ * joins after the file changed, and the durable log is replayed afterwards, so
155
+ * the reader keeps the conversation they were reading.
156
+ */
157
+ const runReloadCommand = () => {
158
+ // A failed reload leaves no agent behind, so the command has to be usable
159
+ // again: the retry is what makes a broken composition file recoverable,
160
+ // while a surface that has opened no session yet is still starting.
161
+ if (agent === undefined && !sessionOpened) {
162
+ ports.notice('the agent is still starting; try again in a moment');
163
+ ports.render();
164
+ return;
165
+ }
166
+ const queued = queuedPrompts();
167
+ // Work the reader would lose is a decision, and the interrupt key already
168
+ // owns that decision: it stops the turn and hands queued words back to the
169
+ // bar. Reopening the session drops the inbox, so a reload that would take
170
+ // those words asks for the key instead of asking a question of its own.
171
+ if (turnOpen || queued.length > 0) {
172
+ ports.notice(queued.length > 0
173
+ ? `${queued.length} queued ${queued.length === 1 ? 'prompt' : 'prompts'} would be dropped — ctrl+c hands them back to the bar, then /reload`
174
+ : 'a turn is running — ctrl+c interrupts it first (delivered text is kept), then /reload');
175
+ ports.render();
176
+ return;
177
+ }
178
+ const id = activeSession;
179
+ void (async () => {
180
+ // The same transition a session switch takes, aimed at the session
181
+ // already open: dispose, then join its preset generation anew.
182
+ await switchSession(id);
183
+ ports.notice("reloaded this session's composition; the transcript was replayed");
184
+ ports.render();
185
+ })().catch((error) => {
186
+ const reason = error instanceof Error ? error.message : String(error);
187
+ ports.notice(`could not reload: ${reason} — fix the composition and /reload again`);
188
+ ports.render();
189
+ });
190
+ };
191
+ const runForkCommand = (title) => {
192
+ if (agent === undefined) {
193
+ ports.notice('the agent is still starting; try again in a moment');
194
+ ports.render();
195
+ return;
196
+ }
197
+ void (async () => {
198
+ const source = activeSession;
199
+ const events = await ports.sessionEvents(source);
200
+ const point = forkPoint(events);
201
+ if (point === undefined) {
202
+ ports.notice('nothing to fork yet: this session has no completed turn');
203
+ ports.render();
204
+ return;
205
+ }
206
+ const childId = SessionId(`tui-session-${randomUUID()}`);
207
+ const previous = letGoOfOutgoing(false);
208
+ if (previous !== undefined)
209
+ await previous.dispose();
210
+ await openAgent(childId, false, { from: source, events: events.slice(0, point.inheritedEvents) });
211
+ if (title !== '')
212
+ runRenameCommand(title);
213
+ ports.notice(`forked from ${source} at event ${point.boundarySeq} — ${point.inheritedEvents} inherited`);
214
+ ports.render();
215
+ })().catch((error) => {
216
+ ports.notice(`could not fork: ${error instanceof Error ? error.message : String(error)}`);
217
+ ports.render();
218
+ });
219
+ };
220
+ /**
221
+ * Give this session a title: it is what the resume picker shows, so a reader
222
+ * who has several sessions can name the one they are in.
223
+ */
224
+ const runRenameCommand = (title) => {
225
+ if (title === '') {
226
+ ports.notice('use /rename <title>; the title is what the resume picker shows');
227
+ ports.render();
228
+ return;
229
+ }
230
+ const session = ctx.get('sessions')?.get?.(activeSession);
231
+ const titles = ctx.get('sessionTitle');
232
+ if (session === undefined || typeof titles?.rename !== 'function') {
233
+ ports.notice('this profile has no session-title service, so this session cannot be renamed');
234
+ ports.render();
235
+ return;
236
+ }
237
+ try {
238
+ const accepted = titles.rename(session, title);
239
+ ports.notice(`session renamed to "${typeof accepted?.title === 'string' ? accepted.title : title}"`);
240
+ }
241
+ catch (error) {
242
+ ports.notice(`could not rename: ${error instanceof Error ? error.message : String(error)}`);
243
+ }
244
+ ports.render();
245
+ };
246
+ /**
247
+ * The driven half of one durable event.
248
+ *
249
+ * The surface state — activity, timer, title, bell, job board — belongs to the
250
+ * agent this terminal drives, even while a child is on screen.
251
+ */
252
+ const observe = (session, event) => {
253
+ if (session.id !== activeSession)
254
+ return;
255
+ // The parent's catalog names the child; lifecycle events carry only its id.
256
+ if (event.type === 'subagent/catalog') {
257
+ ports.acceptCatalog(event.data);
258
+ ports.render();
259
+ }
260
+ if (event.type === 'turn/start') {
261
+ turnOpen = true;
262
+ turnStartedAt = Date.now();
263
+ ports.writeTerminal(windowTitle(process.cwd(), 'working'));
264
+ }
265
+ if (event.type === 'turn/end') {
266
+ const ranFor = turnStartedAt === undefined ? 0 : Date.now() - turnStartedAt;
267
+ turnOpen = false;
268
+ turnStartedAt = undefined;
269
+ // An undo may be parked waiting for exactly this boundary.
270
+ ports.turnSettled();
271
+ ports.writeTerminal(windowTitle(process.cwd(), 'ready'));
272
+ if (shouldRingBell({ bell: ports.bell, ranForMs: ranFor, exiting: ports.exiting() }))
273
+ ports.writeTerminal(BELL);
274
+ // A job the turn started may have settled while the reader was watching
275
+ // something else, and nothing else refreshes a live board.
276
+ ports.refreshJobs();
277
+ }
278
+ // A claim or a discard changes what is queued, and that belongs to this
279
+ // session even while the transcript shows a child's conversation.
280
+ if (event.type === 'agent/inbox/spliced')
281
+ ports.render();
282
+ };
283
+ /** The name is cast so a rename in the harness cannot break this compilation. */
284
+ const listenFor = (name, handler) => ctx.on(name, handler);
285
+ /**
286
+ * The listeners that follow the driver rather than each turn: a run chaining
287
+ * turns through a pending inbox is one stretch of work, and a turn boundary
288
+ * inside it would read as done while the agent is still working; the turn
289
+ * events keep the title and the bell, the reader's own conversation.
290
+ */
291
+ const driverListeners = () => [
292
+ listenFor('agent/status', payload => {
293
+ // Read against the driven session at delivery time: the reader can switch
294
+ // sessions between two transitions, and the row must follow the one this
295
+ // terminal now drives.
296
+ const status = driverReportFor(payload, activeSession);
297
+ if (status === undefined)
298
+ return;
299
+ ports.herdr.driver(status);
300
+ }),
301
+ ];
302
+ return {
303
+ activeSession: () => activeSession,
304
+ drivingAgent: () => agent,
305
+ turnRunning: () => turnOpen,
306
+ activity: () => ({ running: turnOpen, startedAt: turnStartedAt }),
307
+ sessionOpened: () => sessionOpened,
308
+ queuedPrompts,
309
+ stopClock,
310
+ disposeOutgoing,
311
+ openAgent,
312
+ switchSession,
313
+ runNewCommand,
314
+ runReloadCommand,
315
+ runForkCommand,
316
+ runRenameCommand,
317
+ observe,
318
+ driverListeners,
319
+ };
320
+ }
321
+ //# sourceMappingURL=session-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../../src/surface/session-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,SAAS,EAAkB,MAAM,kBAAkB,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAuC,MAAM,kBAAkB,CAAA;AAElF,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAElD;;;;;GAKG;AAEH,uEAAuE;AACvE,MAAM,cAAc,GAAG,IAAI,CAAA;AAgH3B,MAAM,UAAU,sBAAsB,CAAC,GAAY,EAAE,KAA4B;IAC/E,uFAAuF;IACvF,IAAI,aAAa,GAAG,KAAK,CAAC,cAAc,CAAA;IACxC,kFAAkF;IAClF,IAAI,KAA2B,CAAA;IAC/B,oEAAoE;IACpE,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,uEAAuE;IACvE,IAAI,aAAiC,CAAA;IACrC,gFAAgF;IAChF,IAAI,aAAa,GAAG,KAAK,CAAA;IAEzB,6EAA6E;IAC7E,+EAA+E;IAC/E,MAAM,aAAa,GAAG,GAAsB,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;IAEpG,iFAAiF;IACjF,MAAM,YAAY,GAAmC,WAAW,CAAC,GAAG,EAAE;QACpE,IAAI,QAAQ;YAAE,KAAK,CAAC,MAAM,EAAE,CAAA;IAC9B,CAAC,EAAE,cAAc,CAAC,CAAA;IAClB,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAA;IAEvD,MAAM,SAAS,GAAG,GAAS,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;IAEzD;;;;;;;OAOG;IACH,MAAM,eAAe,GAAG,CAAC,UAAmB,EAAwB,EAAE;QACpE,MAAM,QAAQ,GAAG,KAAK,CAAA;QACtB,KAAK,GAAG,SAAS,CAAA;QACjB,QAAQ,GAAG,KAAK,CAAA;QAChB,2EAA2E;QAC3E,iDAAiD;QACjD,aAAa,GAAG,SAAS,CAAA;QACzB,IAAI,UAAU;YAAE,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzC,KAAK,CAAC,eAAe,EAAE,CAAA;QACvB,KAAK,CAAC,WAAW,EAAE,CAAA;QACnB,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAA;IAED,MAAM,eAAe,GAAG,KAAK,IAAmB,EAAE;QAChD,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QACtC,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAA;IACtD,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,KAAK,EAAE,EAAa,EAAE,MAAe,EAAE,IAAsB,EAAqB,EAAE;QACpG,0EAA0E;QAC1E,0DAA0D;QAC1D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE;YACnC,SAAS,EAAE,EAAE;YACb,MAAM;YACN,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,MAAM;YACN,KAAK,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;gBACtB,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAA;gBAClC,IAAI,MAAM,KAAK,SAAS;oBAAE,MAAM,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YACrE,CAAC;YACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;SACxC,CAAC,CAAA;QACF,aAAa,GAAG,IAAI,CAAA;QACpB,aAAa,GAAG,EAAE,CAAA;QAClB,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;QACnB,KAAK,GAAG,MAAM,CAAA;QACd,6EAA6E;QAC7E,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAA;QAC7B,KAAK,CAAC,yBAAyB,EAAE,CAAA;QACjC,oEAAoE;QACpE,mEAAmE;QACnE,sEAAsE;QACtE,2EAA2E;QAC3E,wEAAwE;QACxE,wDAAwD;QACxD,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACvC,6EAA6E;QAC7E,qDAAqD;QACrD,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;YAClB,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;YAC5B,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,KAAK,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;SAC5E,CAAC,CAAA;QACF,wEAAwE;QACxE,0EAA0E;QAC1E,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACnC,yEAAyE;QACzE,yEAAyE;QACzE,yEAAyE;QACzE,yEAAyE;QACzE,sEAAsE;QACtE,IAAI,MAAM;YAAE,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAClC,2EAA2E;QAC3E,wDAAwD;QACxD,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC5C,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE;YACxB,KAAK,MAAM,CAAC,OAAO,EAAE,CAAA;QACvB,CAAC,CAAC,CAAA;QACF,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,KAAK,CAAC,MAAM,CAAC,WAAW,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACxE,KAAK,CAAC,MAAM,EAAE,CAAA;QACd,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,KAAK,EAAE,EAAa,EAAiB,EAAE;QAC3D,MAAM,eAAe,EAAE,CAAA;QACvB,MAAM,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;IAC3B,CAAC,CAAA;IAED,MAAM,aAAa,GAAG,CAAC,KAAa,EAAQ,EAAE;QAC5C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAA;YAClE,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;YACvC,IAAI,QAAQ,KAAK,SAAS;gBAAE,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAA;YACpD,MAAM,SAAS,CAAC,SAAS,CAAC,eAAe,UAAU,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;YAChE,IAAI,KAAK,KAAK,EAAE;gBAAE,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACzC,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAA;YACrC,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC5B,KAAK,CAAC,MAAM,CAAC,8BAA8B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACpG,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED;;;;;OAKG;IACH,MAAM,gBAAgB,GAAG,GAAS,EAAE;QAClC,0EAA0E;QAC1E,wEAAwE;QACxE,oEAAoE;QACpE,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1C,KAAK,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAA;YAClE,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAA;QAC9B,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,MAAM,CACV,MAAM,CAAC,MAAM,GAAG,CAAC;gBACf,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,WAAW,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,qEAAqE;gBAC5I,CAAC,CAAC,uFAAuF,CAC5F,CAAA;YACD,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,MAAM,EAAE,GAAG,aAAa,CAAA;QACxB,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,mEAAmE;YACnE,+DAA+D;YAC/D,MAAM,aAAa,CAAC,EAAE,CAAC,CAAA;YACvB,KAAK,CAAC,MAAM,CAAC,kEAAkE,CAAC,CAAA;YAChF,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC5B,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACrE,KAAK,CAAC,MAAM,CAAC,qBAAqB,MAAM,0CAA0C,CAAC,CAAA;YACnF,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,cAAc,GAAG,CAAC,KAAa,EAAQ,EAAE;QAC7C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,CAAC,oDAAoD,CAAC,CAAA;YAClE,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,MAAM,MAAM,GAAG,aAAa,CAAA;YAC5B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;YAChD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;YAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,KAAK,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAA;gBACvE,KAAK,CAAC,MAAM,EAAE,CAAA;gBACd,OAAM;YACR,CAAC;YACD,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe,UAAU,EAAE,EAAE,CAAC,CAAA;YACxD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;YACvC,IAAI,QAAQ,KAAK,SAAS;gBAAE,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAA;YACpD,MAAM,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;YACjG,IAAI,KAAK,KAAK,EAAE;gBAAE,gBAAgB,CAAC,KAAK,CAAC,CAAA;YACzC,KAAK,CAAC,MAAM,CAAC,eAAe,MAAM,aAAa,KAAK,CAAC,WAAW,MAAM,KAAK,CAAC,eAAe,YAAY,CAAC,CAAA;YACxG,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YAC5B,KAAK,CAAC,MAAM,CAAC,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACzF,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED;;;OAGG;IACH,MAAM,gBAAgB,GAAG,CAAC,KAAa,EAAQ,EAAE;QAC/C,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACjB,KAAK,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAA;YAC9E,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAsD,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAA;QAC/G,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAA8F,CAAA;QACnI,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,MAAM,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;YAClE,KAAK,CAAC,MAAM,CAAC,8EAA8E,CAAC,CAAA;YAC5F,KAAK,CAAC,MAAM,EAAE,CAAA;YACd,OAAM;QACR,CAAC;QACD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAC9C,KAAK,CAAC,MAAM,CAAC,uBAAuB,OAAO,QAAQ,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAA;QACtG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,MAAM,CAAC,qBAAqB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC7F,CAAC;QACD,KAAK,CAAC,MAAM,EAAE,CAAA;IAChB,CAAC,CAAA;IAED;;;;;OAKG;IACH,MAAM,OAAO,GAAG,CAAC,OAAmC,EAAE,KAAgB,EAAQ,EAAE;QAC9E,IAAI,OAAO,CAAC,EAAE,KAAK,aAAa;YAAE,OAAM;QACxC,4EAA4E;QAC5E,IAAK,KAA0B,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC5D,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAC/B,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,QAAQ,GAAG,IAAI,CAAA;YACf,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC1B,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC,CAAA;QAC5D,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAA;YAC3E,QAAQ,GAAG,KAAK,CAAA;YAChB,aAAa,GAAG,SAAS,CAAA;YACzB,2DAA2D;YAC3D,KAAK,CAAC,WAAW,EAAE,CAAA;YACnB,KAAK,CAAC,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;YACxD,IAAI,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAAE,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;YAC/G,wEAAwE;YACxE,2DAA2D;YAC3D,KAAK,CAAC,WAAW,EAAE,CAAA;QACrB,CAAC;QACD,wEAAwE;QACxE,kEAAkE;QAClE,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB;YAAE,KAAK,CAAC,MAAM,EAAE,CAAA;IAC1D,CAAC,CAAA;IAED,iFAAiF;IACjF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,OAA8C,EAAgB,EAAE,CAC9F,GAAG,CAAC,EAAgG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAEtH;;;;;OAKG;IACH,MAAM,eAAe,GAAG,GAA4B,EAAE,CAAC;QACrD,SAAS,CAAC,cAAc,EAAE,OAAO,CAAC,EAAE;YAClC,0EAA0E;YAC1E,yEAAyE;YACzE,uBAAuB;YACvB,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;YACtD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAM;YAChC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC5B,CAAC,CAAC;KACH,CAAA;IAED,OAAO;QACL,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa;QAClC,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK;QACzB,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ;QAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;QACjE,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa;QAClC,aAAa;QACb,SAAS;QACT,eAAe;QACf,SAAS;QACT,aAAa;QACb,aAAa;QACb,gBAAgB;QAChB,cAAc;QACd,gBAAgB;QAChB,OAAO;QACP,eAAe;KAChB,CAAA;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import { SessionId } from '@deepseek-ai/dsh-session';
3
+ import type { Keymap } from '../input/actions.ts';
4
+ import { SessionPicker } from '../ui/picker.ts';
5
+ /**
6
+ * What the stored-session owner needs from the surface that composes it.
7
+ *
8
+ * The keys are read at call time, because a settings edit while the list is
9
+ * open moves the chords its hints name; the picker operation is a port rather
10
+ * than an import, because the keyboard's lifetime belongs to the surface.
11
+ */
12
+ export interface SessionPickerPorts {
13
+ readonly keymap: () => Keymap;
14
+ readonly notice: (text: string) => void;
15
+ readonly render: () => void;
16
+ /**
17
+ * Reject when this run cannot open that session under the mode it named.
18
+ *
19
+ * The composing surface owns what a mode is and which one this run named, so
20
+ * it decides when there is a disagreement to look for at all.
21
+ */
22
+ readonly validateStoredPreset: (id: string) => Promise<void>;
23
+ /** Take the keyboard for the list and answer with the id it settled on. */
24
+ readonly openPicker: (picker: SessionPicker, vet?: (id: string) => Promise<string | undefined>) => Promise<string | undefined>;
25
+ }
26
+ /** The one read the composing surface routes to this owner. */
27
+ export interface SessionPickerChoice {
28
+ /** Which stored session to open, or undefined when the reader asked for none. */
29
+ readonly chooseSession: () => Promise<SessionId | undefined>;
30
+ }
31
+ /**
32
+ * The stored sessions a bare `--resume` asks the reader to choose between.
33
+ *
34
+ * The list is drawn by id before any log is opened: reading every title first
35
+ * would make the picker as slow as the slowest session, and a session whose
36
+ * log this build cannot read is still one the reader may want back.
37
+ */
38
+ export declare function createSessionPicker(ctx: Context, ports: SessionPickerPorts): SessionPickerChoice;
39
+ //# sourceMappingURL=session-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-picker.d.ts","sourceRoot":"","sources":["../../src/surface/session-picker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAQpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAY/C;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,oBAAoB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,CACnB,MAAM,EAAE,aAAa,EACrB,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,KAC9C,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CACjC;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IAClC,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CAC7D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CA0FhG"}
@@ -0,0 +1,107 @@
1
+ import { SessionId } from '@deepseek-ai/dsh-session';
2
+ import { PICKER_LIMIT, createSessionHistory, readSessionTitle, } from "../agent/history.js";
3
+ import { SessionPicker } from "../ui/picker.js";
4
+ /**
5
+ * Titles read at once.
6
+ *
7
+ * Every title costs a log read, and the list is already on screen without them,
8
+ * so they are pipelined to keep the wait near the slowest log rather than the
9
+ * sum of them — bounded, because a hundred parallel reads is a disk storm the
10
+ * reader would feel elsewhere.
11
+ */
12
+ const TITLE_CONCURRENCY = 4;
13
+ /**
14
+ * The stored sessions a bare `--resume` asks the reader to choose between.
15
+ *
16
+ * The list is drawn by id before any log is opened: reading every title first
17
+ * would make the picker as slow as the slowest session, and a session whose
18
+ * log this build cannot read is still one the reader may want back.
19
+ */
20
+ export function createSessionPicker(ctx, ports) {
21
+ /** Title the listed sessions without making the reader wait for the slowest log. */
22
+ const loadTitles = async (history, sessions, titles) => {
23
+ const queue = [...sessions];
24
+ const worker = async () => {
25
+ for (;;) {
26
+ const next = queue.shift();
27
+ if (next === undefined)
28
+ return;
29
+ try {
30
+ const title = await readSessionTitle(history, next);
31
+ if (title === undefined)
32
+ continue;
33
+ titles.set(next.id, title);
34
+ ports.render();
35
+ }
36
+ catch {
37
+ // A log this build cannot read stays listed by id; the picker is not
38
+ // the place to explain storage, and one bad session is not the list.
39
+ }
40
+ }
41
+ };
42
+ await Promise.all(Array.from({ length: TITLE_CONCURRENCY }, worker));
43
+ };
44
+ /**
45
+ * The stored list, or undefined after telling the reader why there is none.
46
+ *
47
+ * No storage, an empty history, and a listing that throws all end the same way
48
+ * — there is nothing to pick from — and none of them is worth ending the run
49
+ * over, so each is a notice rather than a failure.
50
+ */
51
+ const storedSessions = async () => {
52
+ const history = createSessionHistory(ctx);
53
+ if (history === undefined) {
54
+ ports.notice('this profile has no session storage, so there is nothing to resume');
55
+ ports.render();
56
+ return undefined;
57
+ }
58
+ try {
59
+ const sessions = await history.list(PICKER_LIMIT);
60
+ if (sessions.length === 0) {
61
+ ports.notice('no stored sessions to resume');
62
+ ports.render();
63
+ return undefined;
64
+ }
65
+ return { history, sessions };
66
+ }
67
+ catch (error) {
68
+ ports.notice(`could not list stored sessions: ${error instanceof Error ? error.message : String(error)}`);
69
+ ports.render();
70
+ return undefined;
71
+ }
72
+ };
73
+ /**
74
+ * Why this run cannot open a stored session, or undefined when it can.
75
+ *
76
+ * A session runs the mode its own log recorded, so a `--preset` that
77
+ * disagrees with it can only be refused: the picker asks first so the refusal
78
+ * lands in the list rather than after the terminal has been handed back.
79
+ */
80
+ const refuseReason = async (id) => {
81
+ try {
82
+ await ports.validateStoredPreset(id);
83
+ return undefined;
84
+ }
85
+ catch (error) {
86
+ return error instanceof Error ? error.message : String(error);
87
+ }
88
+ };
89
+ /**
90
+ * Take the keyboard for a picker.
91
+ *
92
+ * The list is already in hand, so the picker is interactive immediately while
93
+ * the titles that make its rows recognizable stream in behind it.
94
+ */
95
+ const askForSession = async (history, sessions) => {
96
+ const titles = new Map();
97
+ void loadTitles(history, sessions, titles);
98
+ const picked = await ports.openPicker(new SessionPicker(sessions, () => titles, undefined, ports.keymap), refuseReason);
99
+ return picked === undefined ? undefined : SessionId(picked);
100
+ };
101
+ const chooseSession = async () => {
102
+ const listed = await storedSessions();
103
+ return listed === undefined ? undefined : askForSession(listed.history, listed.sessions);
104
+ };
105
+ return { chooseSession };
106
+ }
107
+ //# sourceMappingURL=session-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-picker.js","sourceRoot":"","sources":["../../src/surface/session-picker.ts"],"names":[],"mappings":"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"}