@sagmans/dsh-tui 0.1.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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/cordis.patch.yml +123 -0
  4. package/lib/agent/fork.d.ts +24 -0
  5. package/lib/agent/fork.d.ts.map +1 -0
  6. package/lib/agent/fork.js +25 -0
  7. package/lib/agent/fork.js.map +1 -0
  8. package/lib/agent/history.d.ts +78 -0
  9. package/lib/agent/history.d.ts.map +1 -0
  10. package/lib/agent/history.js +179 -0
  11. package/lib/agent/history.js.map +1 -0
  12. package/lib/agent/host.d.ts +58 -0
  13. package/lib/agent/host.d.ts.map +1 -0
  14. package/lib/agent/host.js +59 -0
  15. package/lib/agent/host.js.map +1 -0
  16. package/lib/agent/model.d.ts +61 -0
  17. package/lib/agent/model.d.ts.map +1 -0
  18. package/lib/agent/model.js +92 -0
  19. package/lib/agent/model.js.map +1 -0
  20. package/lib/agent/present.d.ts +12 -0
  21. package/lib/agent/present.d.ts.map +1 -0
  22. package/lib/agent/present.js +52 -0
  23. package/lib/agent/present.js.map +1 -0
  24. package/lib/agent/presets.d.ts +75 -0
  25. package/lib/agent/presets.d.ts.map +1 -0
  26. package/lib/agent/presets.js +117 -0
  27. package/lib/agent/presets.js.map +1 -0
  28. package/lib/agent/projections.d.ts +16 -0
  29. package/lib/agent/projections.d.ts.map +1 -0
  30. package/lib/agent/projections.js +31 -0
  31. package/lib/agent/projections.js.map +1 -0
  32. package/lib/agent/status.d.ts +46 -0
  33. package/lib/agent/status.d.ts.map +1 -0
  34. package/lib/agent/status.js +67 -0
  35. package/lib/agent/status.js.map +1 -0
  36. package/lib/cards.d.ts +88 -0
  37. package/lib/cards.d.ts.map +1 -0
  38. package/lib/cards.js +218 -0
  39. package/lib/cards.js.map +1 -0
  40. package/lib/compat/probe.d.ts +33 -0
  41. package/lib/compat/probe.d.ts.map +1 -0
  42. package/lib/compat/probe.js +74 -0
  43. package/lib/compat/probe.js.map +1 -0
  44. package/lib/config.d.ts +13 -0
  45. package/lib/config.d.ts.map +1 -0
  46. package/lib/config.js +49 -0
  47. package/lib/config.js.map +1 -0
  48. package/lib/contracts.d.ts +32 -0
  49. package/lib/contracts.d.ts.map +1 -0
  50. package/lib/contracts.js +2 -0
  51. package/lib/contracts.js.map +1 -0
  52. package/lib/export.d.ts +15 -0
  53. package/lib/export.d.ts.map +1 -0
  54. package/lib/export.js +52 -0
  55. package/lib/export.js.map +1 -0
  56. package/lib/gates.d.ts +85 -0
  57. package/lib/gates.d.ts.map +1 -0
  58. package/lib/gates.js +216 -0
  59. package/lib/gates.js.map +1 -0
  60. package/lib/identity.d.ts +33 -0
  61. package/lib/identity.d.ts.map +1 -0
  62. package/lib/identity.js +49 -0
  63. package/lib/identity.js.map +1 -0
  64. package/lib/index.d.ts +24 -0
  65. package/lib/index.d.ts.map +1 -0
  66. package/lib/index.js +1196 -0
  67. package/lib/index.js.map +1 -0
  68. package/lib/input/completion.d.ts +22 -0
  69. package/lib/input/completion.d.ts.map +1 -0
  70. package/lib/input/completion.js +27 -0
  71. package/lib/input/completion.js.map +1 -0
  72. package/lib/input/submission.d.ts +62 -0
  73. package/lib/input/submission.d.ts.map +1 -0
  74. package/lib/input/submission.js +80 -0
  75. package/lib/input/submission.js.map +1 -0
  76. package/lib/jobs.d.ts +64 -0
  77. package/lib/jobs.d.ts.map +1 -0
  78. package/lib/jobs.js +123 -0
  79. package/lib/jobs.js.map +1 -0
  80. package/lib/startup.d.ts +17 -0
  81. package/lib/startup.d.ts.map +1 -0
  82. package/lib/startup.js +67 -0
  83. package/lib/startup.js.map +1 -0
  84. package/lib/subagents.d.ts +74 -0
  85. package/lib/subagents.d.ts.map +1 -0
  86. package/lib/subagents.js +141 -0
  87. package/lib/subagents.js.map +1 -0
  88. package/lib/terminal/bell.d.ts +18 -0
  89. package/lib/terminal/bell.d.ts.map +1 -0
  90. package/lib/terminal/bell.js +16 -0
  91. package/lib/terminal/bell.js.map +1 -0
  92. package/lib/terminal/clipboard.d.ts +11 -0
  93. package/lib/terminal/clipboard.d.ts.map +1 -0
  94. package/lib/terminal/clipboard.js +18 -0
  95. package/lib/terminal/clipboard.js.map +1 -0
  96. package/lib/terminal/restore.d.ts +17 -0
  97. package/lib/terminal/restore.d.ts.map +1 -0
  98. package/lib/terminal/restore.js +43 -0
  99. package/lib/terminal/restore.js.map +1 -0
  100. package/lib/terminal/title.d.ts +22 -0
  101. package/lib/terminal/title.d.ts.map +1 -0
  102. package/lib/terminal/title.js +34 -0
  103. package/lib/terminal/title.js.map +1 -0
  104. package/lib/text.d.ts +19 -0
  105. package/lib/text.d.ts.map +1 -0
  106. package/lib/text.js +61 -0
  107. package/lib/text.js.map +1 -0
  108. package/lib/theme.d.ts +47 -0
  109. package/lib/theme.d.ts.map +1 -0
  110. package/lib/theme.js +84 -0
  111. package/lib/theme.js.map +1 -0
  112. package/lib/transcript.d.ts +91 -0
  113. package/lib/transcript.d.ts.map +1 -0
  114. package/lib/transcript.js +315 -0
  115. package/lib/transcript.js.map +1 -0
  116. package/lib/ui/dock.d.ts +36 -0
  117. package/lib/ui/dock.d.ts.map +1 -0
  118. package/lib/ui/dock.js +110 -0
  119. package/lib/ui/dock.js.map +1 -0
  120. package/lib/ui/markdown.d.ts +17 -0
  121. package/lib/ui/markdown.d.ts.map +1 -0
  122. package/lib/ui/markdown.js +35 -0
  123. package/lib/ui/markdown.js.map +1 -0
  124. package/lib/ui/picker.d.ts +103 -0
  125. package/lib/ui/picker.d.ts.map +1 -0
  126. package/lib/ui/picker.js +165 -0
  127. package/lib/ui/picker.js.map +1 -0
  128. package/lib/ui/rows.d.ts +30 -0
  129. package/lib/ui/rows.d.ts.map +1 -0
  130. package/lib/ui/rows.js +49 -0
  131. package/lib/ui/rows.js.map +1 -0
  132. package/lib/ui/status.d.ts +49 -0
  133. package/lib/ui/status.d.ts.map +1 -0
  134. package/lib/ui/status.js +90 -0
  135. package/lib/ui/status.js.map +1 -0
  136. package/lib/ui/view.d.ts +56 -0
  137. package/lib/ui/view.d.ts.map +1 -0
  138. package/lib/ui/view.js +184 -0
  139. package/lib/ui/view.js.map +1 -0
  140. package/lib/work.d.ts +39 -0
  141. package/lib/work.d.ts.map +1 -0
  142. package/lib/work.js +97 -0
  143. package/lib/work.js.map +1 -0
  144. package/package.json +109 -0
package/lib/theme.js ADDED
@@ -0,0 +1,84 @@
1
+ const RESET = '\u001B[0m';
2
+ function sgr(code, enabled) {
3
+ return enabled ? text => `\u001B[${code}m${text}${RESET}` : text => text;
4
+ }
5
+ /**
6
+ * Style markdown through the same palette as the rest of the surface.
7
+ *
8
+ * Code blocks stay unstyled on purpose: a fenced block is already set apart by
9
+ * its border and indentation, and coloring it would fight the reader's own
10
+ * terminal theme.
11
+ */
12
+ function markdownTheme(style) {
13
+ return {
14
+ heading: text => style.bold(style.accent(text)),
15
+ link: text => style.underline(style.accent(text)),
16
+ linkUrl: style.dim,
17
+ code: style.accent,
18
+ codeBlock: text => text,
19
+ codeBlockBorder: style.dim,
20
+ quote: style.dim,
21
+ quoteBorder: style.dim,
22
+ hr: style.dim,
23
+ listBullet: style.accent,
24
+ bold: style.bold,
25
+ italic: style.italic,
26
+ strikethrough: style.strike,
27
+ underline: style.underline,
28
+ };
29
+ }
30
+ function selectListTheme(dim, accent, bold) {
31
+ return {
32
+ selectedPrefix: accent,
33
+ selectedText: bold,
34
+ description: dim,
35
+ scrollInfo: dim,
36
+ noMatch: dim,
37
+ };
38
+ }
39
+ /**
40
+ * Whether styling is on, given the launch flag and the environment.
41
+ *
42
+ * `NO_COLOR` is a cross-tool convention (no-color.org): when it is present and
43
+ * not empty, a program that colors by default must not, regardless of its own
44
+ * flags. Honouring it means one environment variable turns styling off for
45
+ * every tool in a session, which is how a reader actually wants it to work.
46
+ */
47
+ export function colorEnabled(requested, env = process.env) {
48
+ const noColor = env.NO_COLOR;
49
+ return requested && (noColor === undefined || noColor === '');
50
+ }
51
+ /**
52
+ * Build the surface theme.
53
+ *
54
+ * Styling uses the standard 16 ANSI colors and terminal defaults rather than
55
+ * true-color values, so a light or dark terminal remaps the interface on its
56
+ * own and the surface needs no theme setting.
57
+ */
58
+ export function createTheme(color) {
59
+ const dim = sgr('2', color);
60
+ const bold = sgr('1', color);
61
+ const accent = sgr('36', color);
62
+ const warn = sgr('33', color);
63
+ const added = sgr('32', color);
64
+ const removed = sgr('31', color);
65
+ const italic = sgr('3', color);
66
+ const underline = sgr('4', color);
67
+ const strike = sgr('9', color);
68
+ return {
69
+ color,
70
+ glyphs: { user: '›', assistant: '⏺', tool: '⚒', notice: '·', reasoning: '▸', marker: '⧉' },
71
+ dim,
72
+ bold,
73
+ tool: warn,
74
+ notice: dim,
75
+ added,
76
+ removed,
77
+ marker: dim,
78
+ accent,
79
+ italic,
80
+ editor: { borderColor: dim, selectList: selectListTheme(dim, accent, bold) },
81
+ markdown: markdownTheme({ dim, bold, accent, italic, underline, strike }),
82
+ };
83
+ }
84
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { type ToolCard, type ToolPresenter } from './cards.ts';
2
+ /** One renderable transcript row. */
3
+ export type TranscriptEntry = {
4
+ readonly kind: 'user';
5
+ readonly text: string;
6
+ } | {
7
+ readonly kind: 'assistant';
8
+ readonly text: string;
9
+ } | {
10
+ readonly kind: 'notice';
11
+ readonly text: string;
12
+ } | {
13
+ readonly kind: 'marker';
14
+ readonly text: string;
15
+ } | {
16
+ readonly kind: 'tool';
17
+ readonly card: ToolCard;
18
+ } | {
19
+ readonly kind: 'reasoning';
20
+ readonly summary: string;
21
+ readonly body: string;
22
+ readonly live: boolean;
23
+ };
24
+ /** Reasoning kept per settled block, so one runaway thought cannot grow the transcript without bound. */
25
+ export declare const REASONING_CHAR_LIMIT = 20000;
26
+ /**
27
+ * Minimal durable-input shape the fold needs.
28
+ *
29
+ * The fold reads events structurally instead of importing a large event union:
30
+ * a terminal frontend only interprets the few fields it renders, and staying
31
+ * structural keeps this file pure and testable without a live session.
32
+ */
33
+ export interface FoldableEvent {
34
+ readonly type: string;
35
+ readonly data?: unknown;
36
+ }
37
+ /**
38
+ * Fold durable session events into readable rows, and hold the in-flight
39
+ * assistant text and reasoning apart from them.
40
+ *
41
+ * Durable events own the transcript: the live stream is decoration that a
42
+ * repaint or a resume can drop without changing what the reader sees. Tool
43
+ * rows come from the tool's own render intent, so the fold never learns a tool
44
+ * name.
45
+ */
46
+ export declare class TranscriptModel {
47
+ private readonly presenter?;
48
+ /** Clock for "how long has this been thinking"; injected so a test can pin it. */
49
+ private readonly now;
50
+ private readonly settled;
51
+ private readonly pending;
52
+ private live;
53
+ private liveReasoning;
54
+ private reasoningStartedAt;
55
+ constructor(presenter?: ToolPresenter | undefined,
56
+ /** Clock for "how long has this been thinking"; injected so a test can pin it. */
57
+ now?: () => number);
58
+ /** Rows to render: settled rows, the in-flight reasoning, then the in-flight text. */
59
+ entries(): readonly TranscriptEntry[];
60
+ /**
61
+ * How many rows are settled.
62
+ *
63
+ * Rows after this are the in-flight ones, rebuilt on every frame anyway, so a
64
+ * renderer can keep its cache to the part of the transcript that stopped
65
+ * changing.
66
+ */
67
+ settledCount(): number;
68
+ /** Whether any row exists, so a caller can decide to clear or redraw. */
69
+ isEmpty(): boolean;
70
+ reset(): void;
71
+ /** Append a surface-local line that is not part of the durable conversation. */
72
+ notice(text: string): void;
73
+ /** Mark a boundary in the conversation: compaction, or work that ran elsewhere. */
74
+ marker(text: string): void;
75
+ /** Apply one transient assistant-stream chunk. */
76
+ applyStreamChunk(chunk: unknown): void;
77
+ /** Report why a turn ended, except for the ordinary completion the reader already sees. */
78
+ private reportTurnEnd;
79
+ /** Report a live agent failure the durable log never carries as a message. */
80
+ reportError(error: unknown): void;
81
+ /**
82
+ * Settle the reasoning streamed so far into a row of its own.
83
+ *
84
+ * The row lands where the reasoning happened, which is before the answer it
85
+ * produced, so reading order still matches the order the model thought in.
86
+ */
87
+ private settleReasoning;
88
+ apply(event: FoldableEvent): void;
89
+ private settleToolResult;
90
+ }
91
+ //# sourceMappingURL=transcript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAEzF,qCAAqC;AACrC,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAE3G,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,QAAS,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CACxB;AA8DD;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAQxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC3B,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG;IATtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,kBAAkB,CAAoB;gBAG3B,SAAS,CAAC,EAAE,aAAa,YAAA;IAC1C,kFAAkF;IACjE,GAAG,GAAE,MAAM,MAAyB;IAGvD,sFAAsF;IACtF,OAAO,IAAI,SAAS,eAAe,EAAE;IAerC;;;;;;OAMG;IACH,YAAY,IAAI,MAAM;IAItB,yEAAyE;IACzE,OAAO,IAAI,OAAO;IAIlB,KAAK,IAAI,IAAI;IAQb,gFAAgF;IAChF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI1B,mFAAmF;IACnF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI1B,kDAAkD;IAClD,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAwBtC,2FAA2F;IAC3F,OAAO,CAAC,aAAa;IAiBrB,8EAA8E;IAC9E,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKjC;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAgBvB,KAAK,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAsEjC,OAAO,CAAC,gBAAgB;CAuCzB"}
@@ -0,0 +1,315 @@
1
+ import { cardFromLines, mergeCards } from "./cards.js";
2
+ /** Reasoning kept per settled block, so one runaway thought cannot grow the transcript without bound. */
3
+ export const REASONING_CHAR_LIMIT = 20_000;
4
+ function asRecord(value) {
5
+ return typeof value === 'object' && value !== null ? value : undefined;
6
+ }
7
+ function contentLinesOf(content) {
8
+ if (!Array.isArray(content))
9
+ return [];
10
+ const lines = [];
11
+ for (const block of content) {
12
+ const record = asRecord(block);
13
+ if (record === undefined)
14
+ continue;
15
+ // Any block that carries text counts; a tool-result block also holds its
16
+ // model-facing content one level deeper.
17
+ if (typeof record.text === 'string')
18
+ lines.push(...record.text.split('\n'));
19
+ if (Array.isArray(record.content))
20
+ lines.push(...contentLinesOf(record.content));
21
+ }
22
+ return lines;
23
+ }
24
+ function textOfContent(content) {
25
+ return contentLinesOf(content).join('\n');
26
+ }
27
+ function sourceKind(data) {
28
+ return asRecord(data.source)?.kind === 'user' ? 'user' : 'plugin';
29
+ }
30
+ function countLines(text) {
31
+ return text === '' ? 0 : text.split('\n').length;
32
+ }
33
+ function messageOf(value) {
34
+ const record = asRecord(value);
35
+ if (record === undefined)
36
+ return '';
37
+ if (typeof record.message === 'string')
38
+ return record.message;
39
+ if (typeof record.code === 'string')
40
+ return record.code;
41
+ return '';
42
+ }
43
+ /**
44
+ * Summarize an injected context block.
45
+ *
46
+ * Injected instructions can be thousands of lines and are rewritten by the
47
+ * model, not read by the human, so the row names the producer and its size and
48
+ * keeps one line of preview instead of pushing the conversation off screen.
49
+ */
50
+ function injectionSummary(data, text) {
51
+ const source = asRecord(data.source) ?? {};
52
+ const plugin = typeof source.plugin === 'string' ? source.plugin : 'plugin';
53
+ const lines = text.split('\n').filter(line => line.trim() !== '');
54
+ const first = lines[0]?.trim() ?? '';
55
+ const preview = first.length > 72 ? `${first.slice(0, 71)}…` : first;
56
+ return `injected ${plugin} · ${lines.length} lines${preview === '' ? '' : ` — ${preview}`}`;
57
+ }
58
+ /**
59
+ * Fold durable session events into readable rows, and hold the in-flight
60
+ * assistant text and reasoning apart from them.
61
+ *
62
+ * Durable events own the transcript: the live stream is decoration that a
63
+ * repaint or a resume can drop without changing what the reader sees. Tool
64
+ * rows come from the tool's own render intent, so the fold never learns a tool
65
+ * name.
66
+ */
67
+ export class TranscriptModel {
68
+ presenter;
69
+ now;
70
+ settled = [];
71
+ pending = new Map();
72
+ live = '';
73
+ liveReasoning = '';
74
+ reasoningStartedAt;
75
+ constructor(presenter,
76
+ /** Clock for "how long has this been thinking"; injected so a test can pin it. */
77
+ now = () => Date.now()) {
78
+ this.presenter = presenter;
79
+ this.now = now;
80
+ }
81
+ /** Rows to render: settled rows, the in-flight reasoning, then the in-flight text. */
82
+ entries() {
83
+ const entries = [...this.settled];
84
+ if (this.liveReasoning !== '') {
85
+ const ranFor = this.reasoningStartedAt === undefined ? undefined : this.now() - this.reasoningStartedAt;
86
+ entries.push({
87
+ kind: 'reasoning',
88
+ summary: `reasoning · ${this.liveReasoning.length} chars${ranFor === undefined ? '' : ` · ${Math.max(1, Math.round(ranFor / 1000))}s`} · streaming`,
89
+ body: this.liveReasoning,
90
+ live: true,
91
+ });
92
+ }
93
+ if (this.live !== '')
94
+ entries.push({ kind: 'assistant', text: this.live });
95
+ return entries;
96
+ }
97
+ /**
98
+ * How many rows are settled.
99
+ *
100
+ * Rows after this are the in-flight ones, rebuilt on every frame anyway, so a
101
+ * renderer can keep its cache to the part of the transcript that stopped
102
+ * changing.
103
+ */
104
+ settledCount() {
105
+ return this.settled.length;
106
+ }
107
+ /** Whether any row exists, so a caller can decide to clear or redraw. */
108
+ isEmpty() {
109
+ return this.settled.length === 0 && this.live === '' && this.liveReasoning === '';
110
+ }
111
+ reset() {
112
+ this.settled.length = 0;
113
+ this.pending.clear();
114
+ this.live = '';
115
+ this.liveReasoning = '';
116
+ this.reasoningStartedAt = undefined;
117
+ }
118
+ /** Append a surface-local line that is not part of the durable conversation. */
119
+ notice(text) {
120
+ this.settled.push({ kind: 'notice', text });
121
+ }
122
+ /** Mark a boundary in the conversation: compaction, or work that ran elsewhere. */
123
+ marker(text) {
124
+ this.settled.push({ kind: 'marker', text });
125
+ }
126
+ /** Apply one transient assistant-stream chunk. */
127
+ applyStreamChunk(chunk) {
128
+ const record = asRecord(chunk);
129
+ if (record === undefined)
130
+ return;
131
+ switch (record.type) {
132
+ case 'text-delta':
133
+ if (typeof record.text === 'string')
134
+ this.live += record.text;
135
+ return;
136
+ case 'reasoning-delta':
137
+ if (typeof record.text !== 'string')
138
+ return;
139
+ this.reasoningStartedAt ??= this.now();
140
+ this.liveReasoning += record.text;
141
+ return;
142
+ case 'block-end': {
143
+ const block = asRecord(record.block);
144
+ // A settled block supersedes the transient text it streamed.
145
+ if (block?.type === 'text')
146
+ this.live = '';
147
+ if (block?.type === 'reasoning')
148
+ this.settleReasoning();
149
+ return;
150
+ }
151
+ default:
152
+ return;
153
+ }
154
+ }
155
+ /** Report why a turn ended, except for the ordinary completion the reader already sees. */
156
+ reportTurnEnd(reason) {
157
+ const kind = typeof reason.kind === 'string' ? reason.kind : 'completed';
158
+ if (kind === 'completed')
159
+ return;
160
+ if (kind === 'error') {
161
+ const failure = messageOf(reason.error);
162
+ this.settled.push({ kind: 'notice', text: `turn failed: ${failure === '' ? 'model request failed' : failure}` });
163
+ return;
164
+ }
165
+ if (kind === 'aborted') {
166
+ const cause = asRecord(reason.reason);
167
+ const by = typeof cause?.kind === 'string' ? cause.kind : 'user';
168
+ this.settled.push({ kind: 'notice', text: `turn aborted (${by})` });
169
+ return;
170
+ }
171
+ this.settled.push({ kind: 'notice', text: `turn ended: ${kind}` });
172
+ }
173
+ /** Report a live agent failure the durable log never carries as a message. */
174
+ reportError(error) {
175
+ const text = error instanceof Error ? error.message : messageOf(error);
176
+ this.settled.push({ kind: 'notice', text: `error: ${text === '' ? 'agent failed' : text}` });
177
+ }
178
+ /**
179
+ * Settle the reasoning streamed so far into a row of its own.
180
+ *
181
+ * The row lands where the reasoning happened, which is before the answer it
182
+ * produced, so reading order still matches the order the model thought in.
183
+ */
184
+ settleReasoning() {
185
+ if (this.liveReasoning === '')
186
+ return;
187
+ const text = this.liveReasoning;
188
+ const ranFor = this.reasoningStartedAt === undefined ? undefined : this.now() - this.reasoningStartedAt;
189
+ this.liveReasoning = '';
190
+ this.reasoningStartedAt = undefined;
191
+ const lines = countLines(text);
192
+ const cut = text.length > REASONING_CHAR_LIMIT ? `\n… truncated at ${REASONING_CHAR_LIMIT} chars` : '';
193
+ this.settled.push({
194
+ kind: 'reasoning',
195
+ summary: `reasoning · ${lines} line${lines === 1 ? '' : 's'} · ${text.length} chars${ranFor === undefined ? '' : ` · ${Math.max(1, Math.round(ranFor / 1000))}s`}`,
196
+ body: text.slice(0, REASONING_CHAR_LIMIT) + cut,
197
+ live: false,
198
+ });
199
+ }
200
+ apply(event) {
201
+ const data = asRecord(event.data) ?? {};
202
+ switch (event.type) {
203
+ case 'user/message': {
204
+ const text = textOfContent(data.content);
205
+ if (text === '')
206
+ return;
207
+ this.settled.push(sourceKind(data) === 'user'
208
+ ? { kind: 'user', text }
209
+ : { kind: 'notice', text: injectionSummary(data, text) });
210
+ return;
211
+ }
212
+ case 'turn/end': {
213
+ this.reportTurnEnd(asRecord(data.reason) ?? {});
214
+ return;
215
+ }
216
+ case 'agent-preset/selected': {
217
+ // The log records the composition later turns ran under, so a reader
218
+ // who switched modes sees where the switch happened.
219
+ const selected = typeof data.agentPreset === 'string' ? data.agentPreset : '';
220
+ if (selected !== '')
221
+ this.marker(`preset → ${selected}`);
222
+ return;
223
+ }
224
+ case 'compaction/start': {
225
+ this.marker('compacting the conversation');
226
+ return;
227
+ }
228
+ case 'compaction/summary': {
229
+ const events = Array.isArray(data.shadowedSeqs) ? data.shadowedSeqs.length : 0;
230
+ const tokens = typeof data.shadowedTokenCount === 'number' ? data.shadowedTokenCount : undefined;
231
+ const size = tokens === undefined ? '' : ` (≈${tokens} tokens)`;
232
+ // The summary itself arrives as the user/message that follows, so this
233
+ // row only has to explain where the older history went.
234
+ this.marker(`compacted ${events} events${size}`);
235
+ return;
236
+ }
237
+ case 'assistant/attempt': {
238
+ // An attempt that settled without a message still has to explain itself.
239
+ const failure = data.error === undefined ? '' : messageOf(data.error);
240
+ if (failure !== '')
241
+ this.settled.push({ kind: 'notice', text: `request failed: ${failure}` });
242
+ return;
243
+ }
244
+ case 'assistant/message': {
245
+ const text = textOfContent(asRecord(data.message)?.content);
246
+ this.settleReasoning();
247
+ this.live = '';
248
+ if (text !== '')
249
+ this.settled.push({ kind: 'assistant', text });
250
+ return;
251
+ }
252
+ case 'tool/call': {
253
+ const name = typeof data.name === 'string' ? data.name : 'tool';
254
+ const argumentsJson = typeof data.arguments === 'string' ? data.arguments : '';
255
+ const card = this.presenter?.call(name, argumentsJson);
256
+ this.settled.push({
257
+ kind: 'tool',
258
+ // Without a presenter the row still has to say what ran and with what.
259
+ card: card ?? cardFromLines('generic', name, argumentsJson === '' ? [] : argumentsJson.split('\n'), false),
260
+ });
261
+ const callId = typeof data.callId === 'string' ? data.callId : '';
262
+ if (callId !== '')
263
+ this.pending.set(callId, { name, argumentsJson, index: this.settled.length - 1 });
264
+ return;
265
+ }
266
+ case 'tool/result': {
267
+ this.settleToolResult(data);
268
+ return;
269
+ }
270
+ default:
271
+ return;
272
+ }
273
+ }
274
+ settleToolResult(data) {
275
+ const message = asRecord(data.message);
276
+ const firstBlock = Array.isArray(message?.content) ? asRecord(message.content[0]) : undefined;
277
+ const callId = typeof firstBlock?.toolCallId === 'string' ? firstBlock.toolCallId : '';
278
+ const pending = callId === '' ? undefined : this.pending.get(callId);
279
+ if (callId !== '')
280
+ this.pending.delete(callId);
281
+ const name = pending?.name ?? 'tool';
282
+ const isError = message?.isError === true;
283
+ const result = this.presenter?.result(name, {
284
+ argumentsJson: pending?.argumentsJson ?? '',
285
+ content: message?.content,
286
+ isError,
287
+ meta: data.meta,
288
+ });
289
+ if (pending === undefined) {
290
+ // No matching call in this fold: a resumed transcript may start mid-call.
291
+ this.settled.push({
292
+ kind: 'tool',
293
+ card: result ?? cardFromLines('generic', name, contentLinesOf(message?.content), isError),
294
+ });
295
+ return;
296
+ }
297
+ const previous = this.settled[pending.index];
298
+ const call = previous !== undefined && previous.kind === 'tool' ? previous.card : undefined;
299
+ if (result === undefined) {
300
+ // No presenter answered: the model-facing content is still what happened,
301
+ // and a reader without it would see a tool row that never reported back.
302
+ const reported = contentLinesOf(message?.content);
303
+ const base = call ?? cardFromLines('generic', name, [], false);
304
+ this.settled[pending.index] = {
305
+ kind: 'tool',
306
+ card: reported.length === 0
307
+ ? { ...base, failed: isError }
308
+ : { ...cardFromLines(base.kind, base.title, reported, isError) },
309
+ };
310
+ return;
311
+ }
312
+ this.settled[pending.index] = { kind: 'tool', card: mergeCards(call, { ...result, failed: isError }) };
313
+ }
314
+ }
315
+ //# sourceMappingURL=transcript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../src/transcript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { type Component } from '@earendil-works/pi-tui';
2
+ import { type JobSummary } from '../jobs.ts';
3
+ import { type SubagentRun } from '../subagents.ts';
4
+ import type { TuiTheme } from '../theme.ts';
5
+ import type { WorkState } from '../work.ts';
6
+ /** Todo rows the dock keeps on screen; the rest become a count. */
7
+ export declare const DOCK_TODO_LIMIT = 4;
8
+ /**
9
+ * The dock above the editor: what the agent is working on right now.
10
+ *
11
+ * It renders nothing when there is nothing to say, so a plain conversation
12
+ * keeps its rows for the conversation.
13
+ */
14
+ export declare class WorkDock implements Component {
15
+ private readonly state;
16
+ private readonly theme;
17
+ /** Live background jobs: process state, not something a resume can replay. */
18
+ private readonly jobs;
19
+ /** Delegations this session started; also live state. */
20
+ private readonly subagents;
21
+ /** Clock for elapsed times, so a frame can be pinned in a test. */
22
+ private readonly now;
23
+ constructor(state: () => WorkState, theme: TuiTheme,
24
+ /** Live background jobs: process state, not something a resume can replay. */
25
+ jobs?: () => readonly JobSummary[],
26
+ /** Delegations this session started; also live state. */
27
+ subagents?: () => readonly SubagentRun[],
28
+ /** Clock for elapsed times, so a frame can be pinned in a test. */
29
+ now?: () => number);
30
+ invalidate(): void;
31
+ private pushTodos;
32
+ private pushSubagents;
33
+ private pushJobs;
34
+ render(width: number): string[];
35
+ }
36
+ //# sourceMappingURL=dock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dock.d.ts","sourceRoot":"","sources":["../../src/ui/dock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,wBAAwB,CAAA;AACxE,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAA;AACjF,OAAO,EAAyC,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAEzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtD,mEAAmE;AACnE,eAAO,MAAM,eAAe,IAAI,CAAA;AAchC;;;;;GAKG;AACH,qBAAa,QAAS,YAAW,SAAS;IAEtC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAPH,KAAK,EAAE,MAAM,SAAS,EACtB,KAAK,EAAE,QAAQ;IAChC,8EAA8E;IAC7D,IAAI,GAAE,MAAM,SAAS,UAAU,EAAa;IAC7D,yDAAyD;IACxC,SAAS,GAAE,MAAM,SAAS,WAAW,EAAa;IACnE,mEAAmE;IAClD,GAAG,GAAE,MAAM,MAAyB;IAGvD,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,QAAQ;IAgBhB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAuBhC"}