@mono-agent/tui 0.4.0 → 0.4.1

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 (124) hide show
  1. package/README.md +60 -10
  2. package/dist/bin/cli.d.ts +4 -1
  3. package/dist/bin/cli.d.ts.map +1 -1
  4. package/dist/bin/cli.js +36 -53
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/bin/mono-agent-tui.js +21 -10
  7. package/dist/bin/mono-agent-tui.js.map +1 -1
  8. package/dist/config/pane.d.ts +9 -9
  9. package/dist/config/pane.d.ts.map +1 -1
  10. package/dist/config/pane.js +15 -196
  11. package/dist/config/pane.js.map +1 -1
  12. package/dist/data/instances.d.ts +48 -0
  13. package/dist/data/instances.d.ts.map +1 -0
  14. package/dist/data/instances.js +101 -0
  15. package/dist/data/instances.js.map +1 -0
  16. package/dist/data/replay.d.ts +68 -0
  17. package/dist/data/replay.d.ts.map +1 -0
  18. package/dist/data/replay.js +149 -0
  19. package/dist/data/replay.js.map +1 -0
  20. package/dist/index.d.ts +10 -10
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +5 -5
  23. package/dist/index.js.map +1 -1
  24. package/dist/remote/client.d.ts +44 -0
  25. package/dist/remote/client.d.ts.map +1 -0
  26. package/dist/remote/client.js +173 -0
  27. package/dist/remote/client.js.map +1 -0
  28. package/dist/runtime/start.d.ts +11 -18
  29. package/dist/runtime/start.d.ts.map +1 -1
  30. package/dist/runtime/start.js +19 -33
  31. package/dist/runtime/start.js.map +1 -1
  32. package/dist/ui/app.d.ts +142 -0
  33. package/dist/ui/app.d.ts.map +1 -0
  34. package/dist/ui/app.js +586 -0
  35. package/dist/ui/app.js.map +1 -0
  36. package/dist/ui/components/event-list.d.ts +60 -0
  37. package/dist/ui/components/event-list.d.ts.map +1 -0
  38. package/dist/ui/components/event-list.js +369 -0
  39. package/dist/ui/components/event-list.js.map +1 -0
  40. package/dist/ui/components/status-bar.d.ts +65 -0
  41. package/dist/ui/components/status-bar.d.ts.map +1 -0
  42. package/dist/ui/components/status-bar.js +126 -0
  43. package/dist/ui/components/status-bar.js.map +1 -0
  44. package/dist/ui/components/tool-panel.d.ts +30 -0
  45. package/dist/ui/components/tool-panel.d.ts.map +1 -0
  46. package/dist/ui/components/tool-panel.js +59 -0
  47. package/dist/ui/components/tool-panel.js.map +1 -0
  48. package/dist/ui/components/transcript-cells.d.ts +49 -0
  49. package/dist/ui/components/transcript-cells.d.ts.map +1 -0
  50. package/dist/ui/components/transcript-cells.js +110 -0
  51. package/dist/ui/components/transcript-cells.js.map +1 -0
  52. package/dist/ui/format.d.ts +29 -0
  53. package/dist/ui/format.d.ts.map +1 -0
  54. package/dist/ui/format.js +105 -0
  55. package/dist/ui/format.js.map +1 -0
  56. package/dist/ui/theme.d.ts +25 -0
  57. package/dist/ui/theme.d.ts.map +1 -0
  58. package/dist/ui/theme.js +62 -0
  59. package/dist/ui/theme.js.map +1 -0
  60. package/dist/ui/turn-presenter.d.ts +72 -0
  61. package/dist/ui/turn-presenter.d.ts.map +1 -0
  62. package/dist/ui/turn-presenter.js +334 -0
  63. package/dist/ui/turn-presenter.js.map +1 -0
  64. package/dist/ui/views/chat.d.ts +128 -0
  65. package/dist/ui/views/chat.d.ts.map +1 -0
  66. package/dist/ui/views/chat.js +313 -0
  67. package/dist/ui/views/chat.js.map +1 -0
  68. package/dist/ui/views/config.d.ts +23 -0
  69. package/dist/ui/views/config.d.ts.map +1 -0
  70. package/dist/ui/views/config.js +87 -0
  71. package/dist/ui/views/config.js.map +1 -0
  72. package/dist/ui/views/picker.d.ts +17 -0
  73. package/dist/ui/views/picker.d.ts.map +1 -0
  74. package/dist/ui/views/picker.js +57 -0
  75. package/dist/ui/views/picker.js.map +1 -0
  76. package/dist/ui/views/replay-detail.d.ts +60 -0
  77. package/dist/ui/views/replay-detail.d.ts.map +1 -0
  78. package/dist/ui/views/replay-detail.js +328 -0
  79. package/dist/ui/views/replay-detail.js.map +1 -0
  80. package/dist/ui/views/replay.d.ts +74 -0
  81. package/dist/ui/views/replay.d.ts.map +1 -0
  82. package/dist/ui/views/replay.js +460 -0
  83. package/dist/ui/views/replay.js.map +1 -0
  84. package/package.json +9 -12
  85. package/dist/agent/message-stream.d.ts +0 -52
  86. package/dist/agent/message-stream.d.ts.map +0 -1
  87. package/dist/agent/message-stream.js +0 -110
  88. package/dist/agent/message-stream.js.map +0 -1
  89. package/dist/components/ChatPane.d.ts +0 -20
  90. package/dist/components/ChatPane.d.ts.map +0 -1
  91. package/dist/components/ChatPane.js +0 -142
  92. package/dist/components/ChatPane.js.map +0 -1
  93. package/dist/components/ConfigPane.d.ts +0 -12
  94. package/dist/components/ConfigPane.d.ts.map +0 -1
  95. package/dist/components/ConfigPane.js +0 -70
  96. package/dist/components/ConfigPane.js.map +0 -1
  97. package/dist/components/HelpOverlay.d.ts +0 -6
  98. package/dist/components/HelpOverlay.d.ts.map +0 -1
  99. package/dist/components/HelpOverlay.js +0 -18
  100. package/dist/components/HelpOverlay.js.map +0 -1
  101. package/dist/components/HistoryPane.d.ts +0 -9
  102. package/dist/components/HistoryPane.d.ts.map +0 -1
  103. package/dist/components/HistoryPane.js +0 -125
  104. package/dist/components/HistoryPane.js.map +0 -1
  105. package/dist/components/StatusBar.d.ts +0 -10
  106. package/dist/components/StatusBar.d.ts.map +0 -1
  107. package/dist/components/StatusBar.js +0 -15
  108. package/dist/components/StatusBar.js.map +0 -1
  109. package/dist/components/TuiApp.d.ts +0 -29
  110. package/dist/components/TuiApp.d.ts.map +0 -1
  111. package/dist/components/TuiApp.js +0 -81
  112. package/dist/components/TuiApp.js.map +0 -1
  113. package/dist/components/primitives/Badge.d.ts +0 -8
  114. package/dist/components/primitives/Badge.d.ts.map +0 -1
  115. package/dist/components/primitives/Badge.js +0 -14
  116. package/dist/components/primitives/Badge.js.map +0 -1
  117. package/dist/components/primitives/Spinner.d.ts +0 -6
  118. package/dist/components/primitives/Spinner.d.ts.map +0 -1
  119. package/dist/components/primitives/Spinner.js +0 -8
  120. package/dist/components/primitives/Spinner.js.map +0 -1
  121. package/dist/components/primitives/TranscriptLine.d.ts +0 -10
  122. package/dist/components/primitives/TranscriptLine.d.ts.map +0 -1
  123. package/dist/components/primitives/TranscriptLine.js +0 -15
  124. package/dist/components/primitives/TranscriptLine.js.map +0 -1
@@ -0,0 +1,313 @@
1
+ import { CombinedAutocompleteProvider, Container, Editor, Loader, Text } from "@earendil-works/pi-tui";
2
+ import { isAgentResponseCancelledError, } from "@mono-agent/agent-contracts";
3
+ import { editorTheme, styles } from "../theme.js";
4
+ import { NoticeCell, ThinkingCell, UserCell } from "../components/transcript-cells.js";
5
+ import { TurnPresenter } from "../turn-presenter.js";
6
+ /**
7
+ * The live chat surface: transcript, in-flight loader, editor, and the turn
8
+ * lifecycle (submit → TurnPresenter → settle). Esc aborts the in-flight turn.
9
+ */
10
+ export class ChatView extends Container {
11
+ editor;
12
+ transcript = new Container();
13
+ loader;
14
+ options;
15
+ responder;
16
+ /**
17
+ * Every not-yet-settled turn's controller — the in-flight one AND queued
18
+ * follow-ups (the harness queues per conversation). Esc aborts them all;
19
+ * tracking only the latest would orphan the turn that is actually running.
20
+ */
21
+ activeControllers = new Set();
22
+ turnCounter = 0;
23
+ thinkingExpandedFlag = false;
24
+ /**
25
+ * Session-scoped model override set via `/model`. When present, each turn's
26
+ * request carries `metadata.tui.model` so the harness runs that turn against
27
+ * the chosen model (a fresh provider session) instead of the agent default.
28
+ */
29
+ modelOverride;
30
+ /**
31
+ * The connected agent's own default model (from `/v1/info`), tracked so
32
+ * clearing the override has something correct to repaint the status bar
33
+ * to -- otherwise it would fall back to whatever string was last painted,
34
+ * which is the just-cleared override itself. Set via {@link setDefaultModel}.
35
+ */
36
+ defaultModel;
37
+ /**
38
+ * Session-scoped effort override set via `/effort`. When present, each turn's
39
+ * request carries `metadata.tui.effort` so the harness runs that turn at the
40
+ * chosen reasoning effort instead of the agent default. Mirrors
41
+ * {@link modelOverride}; the two are independent and can be set together.
42
+ */
43
+ effortOverride;
44
+ /**
45
+ * The connected agent's own default effort (from `/v1/info`), tracked so
46
+ * clearing the override repaints the status bar to it (not the just-cleared
47
+ * override string). Mirror of {@link defaultModel}; set via {@link setDefaultEffort}.
48
+ */
49
+ defaultEffort;
50
+ constructor(options) {
51
+ super();
52
+ this.options = options;
53
+ this.loader = new Loader(options.tui, styles.accent, styles.muted, "working…");
54
+ this.editor = new Editor(options.tui, editorTheme);
55
+ this.editor.setAutocompleteProvider(new CombinedAutocompleteProvider([...options.slashCommands], process.cwd()));
56
+ this.editor.onSubmit = (text) => {
57
+ this.handleSubmit(text);
58
+ };
59
+ this.addChild(this.transcript);
60
+ this.addChild(this.editor);
61
+ }
62
+ setResponder(responder) {
63
+ this.responder = responder;
64
+ }
65
+ /**
66
+ * Set (model string) or clear (`undefined`) the session model override, and
67
+ * reflect it on the status bar immediately: the model segment shows the
68
+ * chosen model with an `(override)` tag, cleared back to the connected
69
+ * agent's own default (via {@link setDefaultModel}, not the last override
70
+ * string) on `undefined`. The override applies from the next turn onward.
71
+ */
72
+ setModelOverride(model) {
73
+ this.modelOverride = model;
74
+ this.options.statusBar.setModel(model ?? this.defaultModel);
75
+ this.options.statusBar.setModelOverridden(model !== undefined);
76
+ this.options.tui.requestRender();
77
+ }
78
+ /** The active session override, or `undefined` — drives the picker's `(current)` marker. */
79
+ getModelOverride() {
80
+ return this.modelOverride;
81
+ }
82
+ /**
83
+ * Set (effort string) or clear (`undefined`) the session effort override, and
84
+ * reflect it on the status bar immediately: the effort segment shows the
85
+ * chosen level with an `(override)` tag, cleared back to the connected agent's
86
+ * own default (via {@link setDefaultEffort}, not the last override string) on
87
+ * `undefined`. The override applies from the next turn onward. Independent of
88
+ * {@link setModelOverride} — both can be active at once.
89
+ */
90
+ setEffortOverride(effort) {
91
+ this.effortOverride = effort;
92
+ this.options.statusBar.setEffort(effort ?? this.defaultEffort);
93
+ this.options.statusBar.setEffortOverridden(effort !== undefined);
94
+ this.options.tui.requestRender();
95
+ }
96
+ /** The active session effort override, or `undefined` — drives the picker's `(current)` marker. */
97
+ getEffortOverride() {
98
+ return this.effortOverride;
99
+ }
100
+ /**
101
+ * Record the connected agent's own default model (from `/v1/info`), so a
102
+ * later `setModelOverride(undefined)` knows what to repaint the status bar
103
+ * to. When no override is currently active, also repaints immediately --
104
+ * this is how a fresh `/v1/info` snapshot (e.g. after switching agents)
105
+ * reaches the status bar's model segment.
106
+ */
107
+ setDefaultModel(model) {
108
+ this.defaultModel = model;
109
+ if (this.modelOverride === undefined) {
110
+ this.options.statusBar.setModel(model);
111
+ this.options.tui.requestRender();
112
+ }
113
+ }
114
+ /**
115
+ * Record the connected agent's own default effort (from `/v1/info`), so a
116
+ * later `setEffortOverride(undefined)` knows what to repaint the status bar
117
+ * to. When no override is currently active, repaints immediately — this is
118
+ * how a fresh `/v1/info` snapshot (e.g. after switching agents) reaches the
119
+ * status bar's effort segment. Mirror of {@link setDefaultModel}.
120
+ */
121
+ setDefaultEffort(effort) {
122
+ this.defaultEffort = effort;
123
+ if (this.effortOverride === undefined) {
124
+ this.options.statusBar.setEffort(effort);
125
+ this.options.tui.requestRender();
126
+ }
127
+ }
128
+ /**
129
+ * Whether the editor's buffer is empty. Drives app.ts's chat exception to
130
+ * global tab/`?`: with nothing to lose, both act as global shortcuts (view
131
+ * cycling, help); with unsubmitted text, they pass through to the editor
132
+ * (autocomplete completion / literal `?`) unchanged.
133
+ */
134
+ isEditorEmpty() {
135
+ return this.editor.getText().length === 0;
136
+ }
137
+ hasActiveTurn() {
138
+ return this.activeControllers.size > 0;
139
+ }
140
+ /** Esc: abort every unsettled turn (in-flight + queued). Returns true when there was one. */
141
+ cancelActiveTurn() {
142
+ if (this.activeControllers.size === 0) {
143
+ return false;
144
+ }
145
+ for (const controller of this.activeControllers) {
146
+ controller.abort();
147
+ }
148
+ // Belt and braces for remote responders: socket teardown cancels the turn
149
+ // server-side too, but an explicit cancel also clears queued follow-ups.
150
+ this.responder?.cancel?.(this.options.conversationId, "tui_cancel");
151
+ return true;
152
+ }
153
+ toggleThinkingExpanded() {
154
+ this.thinkingExpandedFlag = !this.thinkingExpandedFlag;
155
+ for (const child of this.transcript.children) {
156
+ if (child instanceof ThinkingCell) {
157
+ child.setExpanded(this.thinkingExpandedFlag);
158
+ }
159
+ }
160
+ this.options.statusBar.setEphemeral(this.thinkingExpandedFlag ? "thinking expanded" : "thinking collapsed");
161
+ this.options.tui.requestRender();
162
+ }
163
+ addNotice(message, kind = "warning") {
164
+ this.transcript.addChild(new NoticeCell(message, kind));
165
+ this.options.tui.requestRender();
166
+ }
167
+ addInfo(text) {
168
+ this.transcript.addChild(new Text(styles.muted(text), 1, 0));
169
+ this.options.tui.requestRender();
170
+ }
171
+ handleSubmit(raw) {
172
+ const text = raw.trim();
173
+ if (text.length === 0) {
174
+ return;
175
+ }
176
+ this.editor.setText("");
177
+ this.editor.addToHistory(text);
178
+ if (text.startsWith("/")) {
179
+ const [command = "", ...rest] = text.slice(1).split(/\s+/u);
180
+ if (this.options.onSlashCommand(command.toLowerCase(), rest.join(" "))) {
181
+ return;
182
+ }
183
+ }
184
+ void this.runTurn(text);
185
+ }
186
+ async runTurn(text) {
187
+ if (this.responder === undefined) {
188
+ this.addNotice("Not connected to an agent — /agents to pick one.", "error");
189
+ return;
190
+ }
191
+ if (this.activeControllers.size > 0) {
192
+ // LiveSessionManager queues per conversation; let the user know.
193
+ this.options.statusBar.setEphemeral("turn in flight — message queued after it");
194
+ }
195
+ this.turnCounter += 1;
196
+ const turnId = `tui-${Date.now()}-${this.turnCounter}`;
197
+ this.transcript.addChild(new UserCell(text));
198
+ this.options.history?.append({
199
+ id: `${turnId}-user`,
200
+ role: "user",
201
+ text,
202
+ timestamp: Date.now(),
203
+ conversationId: this.options.conversationId,
204
+ });
205
+ const controller = new AbortController();
206
+ const presenter = new TurnPresenter({
207
+ transcript: this.transcript,
208
+ statusBar: this.options.statusBar,
209
+ requestRender: () => this.options.tui.requestRender(),
210
+ thinkingExpanded: () => this.thinkingExpandedFlag,
211
+ ...(this.options.flushIntervalMs === undefined ? {} : { flushIntervalMs: this.options.flushIntervalMs }),
212
+ ...(this.modelOverride === undefined ? {} : { requestedModelOverride: this.modelOverride }),
213
+ });
214
+ this.activeControllers.add(controller);
215
+ this.setLoading(true);
216
+ // metadata.tui carries whichever session overrides are active; when both are
217
+ // clear it is omitted entirely so the turn runs the agent's own defaults.
218
+ const tuiMetadata = {
219
+ ...(this.modelOverride === undefined ? {} : { model: this.modelOverride }),
220
+ ...(this.effortOverride === undefined ? {} : { effort: this.effortOverride }),
221
+ };
222
+ let status = "ok";
223
+ try {
224
+ const response = await this.responder.respond({
225
+ conversationId: this.options.conversationId,
226
+ text,
227
+ abortSignal: controller.signal,
228
+ metadata: {
229
+ source: "tui",
230
+ ...(Object.keys(tuiMetadata).length === 0 ? {} : { tui: tuiMetadata }),
231
+ },
232
+ }, presenter);
233
+ if (response.text !== undefined) {
234
+ await presenter.finish(response.text);
235
+ }
236
+ this.applyFinishMetadata(response.metadata);
237
+ }
238
+ catch (error) {
239
+ if (isAgentResponseCancelledError(error) || controller.signal.aborted) {
240
+ status = "cancelled";
241
+ this.addNotice("Turn cancelled.", "warning");
242
+ }
243
+ else {
244
+ status = "error";
245
+ const message = error instanceof Error ? error.message : String(error);
246
+ this.options.logger?.error?.("tui.turn.failed", { message });
247
+ this.addNotice(message, "error");
248
+ }
249
+ }
250
+ finally {
251
+ this.activeControllers.delete(controller);
252
+ if (this.activeControllers.size === 0) {
253
+ this.setLoading(false);
254
+ }
255
+ presenter.settle();
256
+ this.options.statusBar.setEphemeral("");
257
+ const answer = presenter.assistantText();
258
+ if (answer.length > 0 || status !== "ok") {
259
+ this.options.history?.append({
260
+ id: `${turnId}-assistant`,
261
+ role: "assistant",
262
+ text: answer,
263
+ timestamp: Date.now(),
264
+ conversationId: this.options.conversationId,
265
+ status,
266
+ });
267
+ }
268
+ this.options.tui.requestRender();
269
+ }
270
+ }
271
+ /**
272
+ * The authoritative post-turn correction: `metadata.runtime` is set by the
273
+ * harness from the actual run (not the requested config), so it wins over
274
+ * whatever the mid-stream `run_config` event (or nothing, for agents that
275
+ * predate it) already showed. Guarded defensively — `metadata` is
276
+ * `unknown`-shaped wire data. Absence of either field is NOT a signal to
277
+ * clear; only a present string value ever updates the status bar.
278
+ */
279
+ applyFinishMetadata(metadata) {
280
+ if (typeof metadata !== "object" || metadata === null) {
281
+ return;
282
+ }
283
+ const runtime = metadata.runtime;
284
+ if (typeof runtime !== "object" || runtime === null) {
285
+ return;
286
+ }
287
+ const record = runtime;
288
+ if (typeof record.effort === "string") {
289
+ this.options.statusBar.setEffort(record.effort);
290
+ }
291
+ if (typeof record.model === "string") {
292
+ this.options.statusBar.setModel(record.model);
293
+ }
294
+ }
295
+ setLoading(loading) {
296
+ if (loading) {
297
+ if (!this.children.includes(this.loader)) {
298
+ // Loader sits between the transcript and the editor.
299
+ this.children.splice(this.children.indexOf(this.editor), 0, this.loader);
300
+ }
301
+ this.loader.start();
302
+ }
303
+ else {
304
+ this.loader.stop();
305
+ const index = this.children.indexOf(this.loader);
306
+ if (index >= 0) {
307
+ this.children.splice(index, 1);
308
+ }
309
+ }
310
+ this.options.tui.requestRender();
311
+ }
312
+ }
313
+ //# sourceMappingURL=chat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/ui/views/chat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Container } from "@earendil-works/pi-tui";
2
+ import type { TUI } from "@earendil-works/pi-tui";
3
+ export interface ConfigViewOptions {
4
+ readonly tui: TUI;
5
+ readonly env: Record<string, string | undefined>;
6
+ }
7
+ /**
8
+ * Read-only, redacted, source-annotated config view built by the same
9
+ * `buildMonoAgentConfigView` the `mono-agent config` command uses. Reads the
10
+ * agent's config FILE from its manifest path; the env layer shown is this
11
+ * shell's, not the agent process's (stated in the header).
12
+ */
13
+ export declare class ConfigView extends Container {
14
+ private readonly options;
15
+ private configPath;
16
+ private cwd;
17
+ constructor(options: ConfigViewOptions);
18
+ handleInput(data: string): void;
19
+ setConfigPath(configPath: string | undefined, cwd?: string): void;
20
+ refresh(): Promise<void>;
21
+ private showMessage;
22
+ }
23
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/ui/views/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAQ,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAWlD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAClD;AAQD;;;;;GAKG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,GAAG,CAAiB;gBAEhB,OAAO,EAAE,iBAAiB;IAMtC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM/B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ3D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqD9B,OAAO,CAAC,WAAW;CAIpB"}
@@ -0,0 +1,87 @@
1
+ import { Container, Text } from "@earendil-works/pi-tui";
2
+ import { loadMonoAgentConfigWithSources, readMonoAgentConfigJson, redactMonoAgentConfig, } from "@mono-agent/config";
3
+ import { buildTuiConfigSummary } from "../../config/pane.js";
4
+ import { styles } from "../theme.js";
5
+ const SOURCE_STYLE = {
6
+ env: styles.success,
7
+ json: styles.accent,
8
+ default: styles.dim,
9
+ };
10
+ /**
11
+ * Read-only, redacted, source-annotated config view built by the same
12
+ * `buildMonoAgentConfigView` the `mono-agent config` command uses. Reads the
13
+ * agent's config FILE from its manifest path; the env layer shown is this
14
+ * shell's, not the agent process's (stated in the header).
15
+ */
16
+ export class ConfigView extends Container {
17
+ options;
18
+ configPath;
19
+ cwd = process.cwd();
20
+ constructor(options) {
21
+ super();
22
+ this.options = options;
23
+ this.showMessage(styles.muted("No config path available for the selected agent."));
24
+ }
25
+ handleInput(data) {
26
+ if (data === "r" || data === "R") {
27
+ void this.refresh();
28
+ }
29
+ }
30
+ setConfigPath(configPath, cwd) {
31
+ this.configPath = configPath;
32
+ if (cwd !== undefined) {
33
+ this.cwd = cwd;
34
+ }
35
+ void this.refresh();
36
+ }
37
+ async refresh() {
38
+ // Snapshot both inputs: a rapid agent switch mid-load must not paint the
39
+ // previous agent's config under the new agent's header.
40
+ const requestedPath = this.configPath;
41
+ const requestedCwd = this.cwd;
42
+ if (requestedPath === undefined) {
43
+ this.showMessage(styles.muted("No config path available for the selected agent."));
44
+ this.options.tui.requestRender();
45
+ return;
46
+ }
47
+ try {
48
+ const jsonResult = await readMonoAgentConfigJson(requestedPath);
49
+ const config = await loadMonoAgentConfigWithSources({
50
+ env: this.options.env,
51
+ cwd: requestedCwd,
52
+ jsonPath: requestedPath,
53
+ });
54
+ if (this.configPath !== requestedPath) {
55
+ return; // Superseded by a newer agent selection.
56
+ }
57
+ const sections = buildTuiConfigSummary({
58
+ redacted: redactMonoAgentConfig(config),
59
+ json: jsonResult.json,
60
+ env: this.options.env,
61
+ });
62
+ this.clear();
63
+ this.addChild(new Text(`${styles.bold(styles.accent(requestedPath))}\n${styles.dim("read-only · r reload · env overrides shown are from this shell, not the agent process")}`, 1, 0));
64
+ for (const section of sections) {
65
+ const lines = [styles.bold(section.heading)];
66
+ for (const field of section.fields) {
67
+ const source = SOURCE_STYLE[field.source](`[${field.source}]`);
68
+ const value = field.redacted === true ? styles.dim("(redacted)") : field.value;
69
+ lines.push(` ${styles.muted(field.label)} ${value} ${source}`);
70
+ }
71
+ this.addChild(new Text(lines.join("\n"), 1, 0));
72
+ }
73
+ }
74
+ catch (error) {
75
+ if (this.configPath !== requestedPath) {
76
+ return;
77
+ }
78
+ this.showMessage(styles.error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`));
79
+ }
80
+ this.options.tui.requestRender();
81
+ }
82
+ showMessage(text) {
83
+ this.clear();
84
+ this.addChild(new Text(text, 1, 0));
85
+ }
86
+ }
87
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/ui/views/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Container, SelectList } from "@earendil-works/pi-tui";
2
+ import type { DiscoveredInstance } from "../../data/instances.js";
3
+ export interface PickerViewOptions {
4
+ readonly onSelect: (instance: DiscoveredInstance) => void;
5
+ readonly onRefresh: () => void;
6
+ }
7
+ /** Instance picker: every discoverable running agent, `enter` connects. */
8
+ export declare class PickerView extends Container {
9
+ readonly list: SelectList;
10
+ private instances;
11
+ private readonly header;
12
+ private readonly options;
13
+ constructor(options: PickerViewOptions);
14
+ handleInput(data: string): void;
15
+ setInstances(instances: readonly DiscoveredInstance[], registryDir: string): void;
16
+ }
17
+ //# sourceMappingURL=picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker.d.ts","sourceRoot":"","sources":["../../../src/ui/views/picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAQ,MAAM,wBAAwB,CAAC;AAGrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;CAChC;AAED,2EAA2E;AAC3E,qBAAa,UAAW,SAAQ,SAAS;IACvC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;gBAEhC,OAAO,EAAE,iBAAiB;IAgBtC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQ/B,YAAY,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;CA4BlF"}
@@ -0,0 +1,57 @@
1
+ import { Container, SelectList, Text } from "@earendil-works/pi-tui";
2
+ import { selectListTheme, styles } from "../theme.js";
3
+ /** Instance picker: every discoverable running agent, `enter` connects. */
4
+ export class PickerView extends Container {
5
+ list;
6
+ instances = [];
7
+ header = new Text("", 1, 0);
8
+ options;
9
+ constructor(options) {
10
+ super();
11
+ this.options = options;
12
+ this.list = new SelectList([], 12, selectListTheme);
13
+ this.list.onSelect = (item) => {
14
+ const instance = this.instances.find((candidate) => candidate.source.sourceId === item.value);
15
+ if (instance !== undefined) {
16
+ this.options.onSelect(instance);
17
+ }
18
+ };
19
+ this.addChild(this.header);
20
+ this.addChild(this.list);
21
+ this.addChild(new Text(styles.dim("enter connect · r refresh · tab chat"), 1, 0));
22
+ this.setInstances([], "");
23
+ }
24
+ handleInput(data) {
25
+ if (data === "r" || data === "R") {
26
+ this.options.onRefresh();
27
+ return;
28
+ }
29
+ this.list.handleInput(data);
30
+ }
31
+ setInstances(instances, registryDir) {
32
+ this.instances = instances;
33
+ if (instances.length === 0) {
34
+ this.header.setText(`${styles.bold("No running agents found.")}\n${styles.muted(`Registry: ${registryDir}\nStart one with \`mono-agent start\` in its folder, then press r.`)}`);
35
+ }
36
+ else {
37
+ this.header.setText(styles.bold(`Running agents (${instances.length})`));
38
+ }
39
+ const items = instances.map((instance) => {
40
+ const source = instance.source;
41
+ const health = source.health === "running" ? styles.success("●") : styles.warning("◐");
42
+ const transports = (source.transports ?? []).join(", ");
43
+ const chat = instance.tuiBaseUrl === undefined ? " — no tui endpoint (chat disabled)" : "";
44
+ return {
45
+ value: source.sourceId,
46
+ label: `${health} ${source.label}`,
47
+ description: `pid ${source.pid ?? "?"} · ${transports}${chat}`,
48
+ };
49
+ });
50
+ // SelectList has no public setItems in 0.79; rebuild via filter reset.
51
+ this.list.items = items;
52
+ this.list.setFilter("");
53
+ this.list.setSelectedIndex(0);
54
+ this.list.invalidate();
55
+ }
56
+ }
57
+ //# sourceMappingURL=picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker.js","sourceRoot":"","sources":["../../../src/ui/views/picker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAIrE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAOtD,2EAA2E;AAC3E,MAAM,OAAO,UAAW,SAAQ,SAAS;IAC9B,IAAI,CAAa;IAClB,SAAS,GAAkC,EAAE,CAAC;IACrC,MAAM,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAoB;IAE5C,YAAY,OAA0B;QACpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAgB,EAAE,EAAE;YACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9F,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAClC,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,YAAY,CAAC,SAAwC,EAAE,WAAmB;QACxE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,CACjB,GAAG,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,KAAK,MAAM,CAAC,KAAK,CACzD,aAAa,WAAW,oEAAoE,CAC7F,EAAE,CACJ,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAc,EAAE;YACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACvF,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,OAAO;gBACL,KAAK,EAAE,MAAM,CAAC,QAAQ;gBACtB,KAAK,EAAE,GAAG,MAAM,IAAI,MAAM,CAAC,KAAK,EAAE;gBAClC,WAAW,EAAE,OAAO,MAAM,CAAC,GAAG,IAAI,GAAG,MAAM,UAAU,GAAG,IAAI,EAAE;aAC/D,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,uEAAuE;QACtE,IAAI,CAAC,IAAwE,CAAC,KAAK,GAAG,KAAK,CAAC;QAC7F,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,60 @@
1
+ import type { Component } from "@earendil-works/pi-tui";
2
+ import { type RecordedRunEvent } from "@mono-agent/observability";
3
+ import type { ReplayRunDetail, ReplayTimelineItem } from "../../data/replay.js";
4
+ /** Canonical (not alphabetical) filter-category order matching the t/o/m/y/e keymap. */
5
+ export declare const CATEGORY_ORDER: readonly string[];
6
+ /** Single-key toggles for the detail-mode category filter (see task brief's keybinding map). */
7
+ export declare const CATEGORY_KEYS: Readonly<Record<string, string>>;
8
+ export declare const KEY_HINT = "\u2191\u2193/pgup/pgdn/g/G step \u00B7 [ ] turn \u00B7 t/o/m/y/e/a filter \u00B7 / search \u00B7 n/N match \u00B7 enter raw json \u00B7 esc back";
9
+ /** Headline text (multi-line): run id/source, conversation/status, clock/model/effort, usage, errors, turn stats. */
10
+ export declare function buildHeadline(replay: ReplayRunDetail): string;
11
+ export interface StatusLineState {
12
+ /** 1-based rank among VISIBLE (post-filter) items; undefined when nothing is visible/selected. */
13
+ readonly ordinal: number | undefined;
14
+ readonly visibleCount: number;
15
+ readonly turnIndex: number | undefined;
16
+ readonly turnCount: number;
17
+ readonly categoryFilter: ReadonlySet<string>;
18
+ readonly searchInputOpen: boolean;
19
+ readonly searchInputBuffer: string;
20
+ readonly committedSearch: string | undefined;
21
+ readonly matchCount: number;
22
+ }
23
+ /** Filter/status line + a dim key-hint line underneath it. */
24
+ export declare function buildStatusLine(state: StatusLineState): string;
25
+ /**
26
+ * Header line for the selected-event pane (index/label/timing/group span,
27
+ * plus a thinking item's own char/duration stats). Unchanged by the Part B
28
+ * cell redesign below -- only the BODY under it now varies by category.
29
+ */
30
+ export declare function buildPayloadHeader(item: ReplayTimelineItem): string;
31
+ /**
32
+ * Pretty-printed raw JSON body for the selected event, capped at today's
33
+ * established line counts (12 collapsed / 40 expanded) with a
34
+ * `… (+N more lines)` trailer when truncated. Used both as the WHOLE body for
35
+ * runtime/telemetry items (no chat-style cell exists for those) and as the
36
+ * optional strip appended below a chat-style cell once the pane is expanded.
37
+ */
38
+ export declare function buildRawPayloadBody(item: ReplayTimelineItem, expanded: boolean): string;
39
+ /**
40
+ * The chat-style transcript cell for the selected event, reusing live chat's
41
+ * OWN components (ThinkingCell/AssistantCell/UserCell/NoticeCell/ToolPanel) so
42
+ * replay and live chat read as one interface. Returns `undefined` for
43
+ * runtime/telemetry items (provider_request_*, run_config, cost,
44
+ * capabilities…) and for a "tool" category item that -- despite the category
45
+ * -- carries neither a `tool_use` nor a `tool_result` content block (e.g. a
46
+ * `tool_update`/`tool_timing` progress event, classified "tool" purely by its
47
+ * `type` string containing "tool"): callers fall back to
48
+ * {@link buildRawPayloadBody} for both cases, exactly as before Part B.
49
+ *
50
+ * `timeline` (the run's full coalesced item list) is used to look AHEAD from
51
+ * a `tool_use` item for its matching `tool_result` (by `tool_use_id`) so a
52
+ * call+result pair renders as ONE unified panel, like a live tool call
53
+ * settling. `rawEvents` (the run's raw, uncoalesced events) is used to
54
+ * reconstruct a coalesced thinking/text group's FULL joined text -- the
55
+ * combiner's own synthetic payload for a multi-event group carries only the
56
+ * compacted (220-char) `summary`, not the full text (see
57
+ * `combinedEventItem` in event-timeline.ts).
58
+ */
59
+ export declare function buildDetailCell(item: ReplayTimelineItem, timeline: readonly ReplayTimelineItem[], rawEvents: readonly RecordedRunEvent[]): Component | undefined;
60
+ //# sourceMappingURL=replay-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-detail.d.ts","sourceRoot":"","sources":["../../../src/ui/views/replay-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEnF,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAOhF,wFAAwF;AACxF,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAwD,CAAC;AAErG,gGAAgG;AAChG,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM1D,CAAC;AAEF,eAAO,MAAM,QAAQ,qJACuF,CAAC;AAK7G,qHAAqH;AACrH,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA+C7D;AAED,MAAM,WAAW,eAAe;IAC9B,kGAAkG;IAClG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAmB9D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAmBnE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAMvF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,EACvC,SAAS,EAAE,SAAS,gBAAgB,EAAE,GACrC,SAAS,GAAG,SAAS,CA8BvB"}