omnius 1.0.867 → 1.0.869
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/py-embed.js +13 -0
- package/dist/index.js +2 -2
- package/dist/library.js +222 -194
- package/dist/tui/native/worker.js +873 -145
- package/dist/update-worker.js +128 -77
- package/docs/DISCOVERY.json +3049 -432
- package/docs/DISCOVERY.md +71 -7
- package/docs/design/media-unification-TODO.md +71 -26
- package/docs/design/media-unification-design.md +89 -0
- package/docs/design/session-presentation-TODO.md +55 -0
- package/docs/design/update-operation-cancellation.md +40 -0
- package/docs/design/update-session-restoration-TODO.md +67 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/interface-after-reconstruction.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/interface-before-reconstruction.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-audio-playing.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-image-100x30.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-image-120x36.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-image-160x48.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-image-60x20.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-image-80x24.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-progress-collapsed.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-video-frame-a.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-video-frame-b.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/media-voice-autocomplete-junction.png +0 -0
- package/docs/work-orders/evidence/instrument-interface-live-20261016/report.json +1054 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-audio-playing.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-image-100x30.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-image-120x36.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-image-160x48.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-image-60x20.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-image-80x24.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-progress-collapsed.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-video-frame-a.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-video-frame-b.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/media-voice-autocomplete-junction.png +0 -0
- package/docs/work-orders/evidence/instrument-media-live-20261016/report.json +813 -0
- package/docs/work-orders/evidence/instrument-media-verification-20261016.json +59 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/action-working-progress.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/action-working-result-json.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/interface-after-reconstruction.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/interface-before-reconstruction.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-audio-playing.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-image-100x30.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-image-120x36.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-image-160x48.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-image-60x20.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-image-80x24.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-progress-collapsed.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-video-frame-a.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-video-frame-b.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/media-voice-autocomplete-junction.png +0 -0
- package/docs/work-orders/evidence/instrument-working-live-20261016/report.json +1180 -0
- package/docs/work-orders/evidence/native-interface-state-verification-20261016.json +79 -0
- package/docs/work-orders/evidence/native-working-state-verification-20261016.json +66 -0
- package/docs/work-orders/evidence/project-media-browser-20261016/dark-1440-image-output.png +0 -0
- package/docs/work-orders/evidence/project-media-browser-20261016/dark-360-image-output.png +0 -0
- package/docs/work-orders/evidence/project-media-browser-20261016/light-1440-image-output.png +0 -0
- package/docs/work-orders/evidence/project-media-browser-20261016/report.json +47455 -0
- package/docs/work-orders/evidence/project-media-unification-20261016.json +108 -0
- package/docs/work-orders/evidence/session-native-restore-followup-20261016.json +30 -0
- package/docs/work-orders/evidence/session-transcript-browser-20261016.json +1196 -0
- package/docs/work-orders/evidence/session-transcript-dark-1440-session-code.png +0 -0
- package/docs/work-orders/evidence/session-transcript-dark-1440-session-image.png +0 -0
- package/docs/work-orders/evidence/session-transcript-dark-1440-session-working.png +0 -0
- package/docs/work-orders/evidence/session-transcript-light-320-session-code.png +0 -0
- package/docs/work-orders/evidence/session-transcript-light-320-session-image.png +0 -0
- package/docs/work-orders/evidence/session-transcript-light-320-session-working.png +0 -0
- package/docs/work-orders/evidence/tool-event-presentation-verification-20261016.json +87 -0
- package/docs/work-orders/evidence/update-operation-cancellation-20261016.json +106 -0
- package/docs/work-orders/session-transcript-browser-20261016.md +21 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -6,29 +6,71 @@ import { CliRenderEvents as CliRenderEvents7, NativeSession, RGBA as RGBA3, crea
|
|
|
6
6
|
|
|
7
7
|
// packages/cli/src/tui/native/components/frontend.ts
|
|
8
8
|
import {
|
|
9
|
-
BoxRenderable as
|
|
9
|
+
BoxRenderable as BoxRenderable8,
|
|
10
10
|
CliRenderEvents as CliRenderEvents5,
|
|
11
11
|
EmbeddedTerminalRenderable as EmbeddedTerminalRenderable2,
|
|
12
12
|
ScrollBoxRenderable as ScrollBoxRenderable5,
|
|
13
13
|
SyntaxStyle as SyntaxStyle2,
|
|
14
14
|
TextareaRenderable as TextareaRenderable2,
|
|
15
|
-
TextRenderable as
|
|
15
|
+
TextRenderable as TextRenderable7,
|
|
16
16
|
TextAttributes as TextAttributes8,
|
|
17
17
|
createClipboard,
|
|
18
18
|
createHostClipboard,
|
|
19
19
|
createRendererClipboardAdapter
|
|
20
20
|
} from "@opentui/core";
|
|
21
21
|
|
|
22
|
+
// packages/cli/src/tui/native/interface-state.ts
|
|
23
|
+
var record = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
24
|
+
var offset = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.min(1e7, Math.floor(value))) : 0;
|
|
25
|
+
function sanitizeNativeInterfaceState(value) {
|
|
26
|
+
if (!record(value) || value.version !== 1 || typeof value.activeViewId !== "string" || !record(value.input)) return void 0;
|
|
27
|
+
if (typeof value.input.text !== "string") return void 0;
|
|
28
|
+
const text = value.input.text.slice(0, 1e6), views = {};
|
|
29
|
+
if (record(value.views)) for (const [key, entry] of Object.entries(value.views).slice(0, 256)) {
|
|
30
|
+
if (key.length > 1024 || !record(entry)) continue;
|
|
31
|
+
const disclosures = {};
|
|
32
|
+
if (record(entry.disclosures)) for (const [id, collapsed] of Object.entries(entry.disclosures).slice(0, 1e4)) {
|
|
33
|
+
if (id.length <= 1024 && typeof collapsed === "boolean") Object.defineProperty(disclosures, id, { value: collapsed, enumerable: true, configurable: true, writable: true });
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(views, key, { value: { top: offset(entry.top), live: entry.live === true, disclosures }, enumerable: true, configurable: true, writable: true });
|
|
36
|
+
}
|
|
37
|
+
const layout = record(value.layout) ? value.layout : {}, instruments = record(value.instruments) ? value.instruments : {}, tabs = record(value.tabs) ? value.tabs : {};
|
|
38
|
+
return {
|
|
39
|
+
version: 1,
|
|
40
|
+
...typeof value.sessionId === "string" ? { sessionId: value.sessionId.slice(0, 1024) } : {},
|
|
41
|
+
activeViewId: value.activeViewId.slice(0, 1024),
|
|
42
|
+
...typeof value.focusId === "string" && value.focusId.length <= 4096 && !value.focusId.startsWith("modal-") ? { focusId: value.focusId } : {},
|
|
43
|
+
presentation: value.presentation === "tree" ? "tree" : "stack",
|
|
44
|
+
input: { text, cursor: Math.min(text.length, offset(value.input.cursor)) },
|
|
45
|
+
views,
|
|
46
|
+
layout: {
|
|
47
|
+
...typeof layout.sidebarWidth === "number" && Number.isFinite(layout.sidebarWidth) ? { sidebarWidth: Math.max(24, Math.min(1e4, Math.floor(layout.sidebarWidth))) } : {},
|
|
48
|
+
...typeof layout.detailsOpen === "boolean" ? { detailsOpen: layout.detailsOpen } : {},
|
|
49
|
+
narrowDetailsOpen: layout.narrowDetailsOpen === true,
|
|
50
|
+
headerPanelCollapsed: layout.headerPanelCollapsed === true
|
|
51
|
+
},
|
|
52
|
+
instruments: {
|
|
53
|
+
inference: instruments.inference !== false,
|
|
54
|
+
session: instruments.session === true,
|
|
55
|
+
context: instruments.context === true,
|
|
56
|
+
devices: instruments.devices === true,
|
|
57
|
+
scrollTop: offset(instruments.scrollTop),
|
|
58
|
+
deviceScrollTop: offset(instruments.deviceScrollTop)
|
|
59
|
+
},
|
|
60
|
+
tabs: { sessions: offset(tabs.sessions), agents: offset(tabs.agents) }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
22
64
|
// packages/cli/src/tui/native/components/blocks.ts
|
|
23
65
|
import {
|
|
24
|
-
BoxRenderable,
|
|
66
|
+
BoxRenderable as BoxRenderable2,
|
|
25
67
|
CodeRenderable,
|
|
26
68
|
EmbeddedTerminalRenderable,
|
|
27
|
-
ImageRenderable,
|
|
69
|
+
ImageRenderable as ImageRenderable2,
|
|
28
70
|
MarkdownRenderable,
|
|
29
71
|
RenderableEvents,
|
|
30
72
|
ScrollBoxRenderable,
|
|
31
|
-
TextRenderable
|
|
73
|
+
TextRenderable as TextRenderable2
|
|
32
74
|
} from "@opentui/core";
|
|
33
75
|
|
|
34
76
|
// packages/cli/src/tui/native/components/text.ts
|
|
@@ -170,6 +212,505 @@ function installDefaultSelectionContrast(renderer2) {
|
|
|
170
212
|
return dispose;
|
|
171
213
|
}
|
|
172
214
|
|
|
215
|
+
// packages/cli/src/tui/native/components/media.ts
|
|
216
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
217
|
+
import { BoxRenderable, ImageRenderable, NativeImagePool, TextRenderable } from "@opentui/core";
|
|
218
|
+
|
|
219
|
+
// packages/cli/src/tui/native/components/media-playback.ts
|
|
220
|
+
import { spawn, execFile } from "node:child_process";
|
|
221
|
+
import { realpath, lstat } from "node:fs/promises";
|
|
222
|
+
import { extname, relative, resolve } from "node:path";
|
|
223
|
+
import { Audio } from "@opentui/core";
|
|
224
|
+
async function validateMediaFile(path, root) {
|
|
225
|
+
const info = await lstat(path);
|
|
226
|
+
if (!info.isFile() || info.isSymbolicLink()) throw new Error("Media must be a regular local file");
|
|
227
|
+
const canonical = await realpath(path), project = await realpath(root);
|
|
228
|
+
const local = relative(project, canonical);
|
|
229
|
+
if (local === ".." || local.startsWith("../") || resolve(project, local) !== canonical) throw new Error("Media is outside its project");
|
|
230
|
+
if (!/\.(png|jpe?g|webp|gif|mp4|webm|mov|mkv|wav|mp3|flac|ogg|m4a)$/i.test(extname(canonical))) throw new Error("Unsupported media file");
|
|
231
|
+
return canonical;
|
|
232
|
+
}
|
|
233
|
+
async function probeMedia(spec, signal) {
|
|
234
|
+
const path = await validateMediaFile(spec.path, spec.projectRoot);
|
|
235
|
+
const output = await new Promise((done, fail2) => execFile("ffprobe", ["-v", "error", "-show_entries", "stream=codec_type,width,height:format=duration", "-of", "json", path], { signal, timeout: 5e3, maxBuffer: 128e3 }, (error, stdout) => error ? fail2(error) : done(stdout)));
|
|
236
|
+
const data = JSON.parse(output), video = data.streams?.find((stream) => stream.codec_type === "video");
|
|
237
|
+
const durationSec = Number(data.format?.duration);
|
|
238
|
+
return { ...video?.width > 0 ? { width: video.width, height: video.height } : {}, ...Number.isFinite(durationSec) && durationSec > 0 ? { durationSec } : {}, hasAudio: data.streams?.some((stream) => stream.codec_type === "audio") };
|
|
239
|
+
}
|
|
240
|
+
var NativeMediaPlayback = class {
|
|
241
|
+
constructor(changed, silent = process.env["OMNIUS_MEDIA_TEST_SILENT"] === "1") {
|
|
242
|
+
this.changed = changed;
|
|
243
|
+
this.silent = silent;
|
|
244
|
+
}
|
|
245
|
+
changed;
|
|
246
|
+
silent;
|
|
247
|
+
positionSec = 0;
|
|
248
|
+
playing = false;
|
|
249
|
+
process;
|
|
250
|
+
controller;
|
|
251
|
+
audio;
|
|
252
|
+
stream;
|
|
253
|
+
ticker;
|
|
254
|
+
epoch = 0;
|
|
255
|
+
audioOffset = 0;
|
|
256
|
+
cleanup = Promise.resolve();
|
|
257
|
+
get closed() {
|
|
258
|
+
return this.cleanup;
|
|
259
|
+
}
|
|
260
|
+
async play(spec, size, frame) {
|
|
261
|
+
this.pause();
|
|
262
|
+
const epoch = ++this.epoch;
|
|
263
|
+
const controller = this.controller = new AbortController();
|
|
264
|
+
try {
|
|
265
|
+
await this.cleanup;
|
|
266
|
+
if (epoch !== this.epoch) return;
|
|
267
|
+
const path = await validateMediaFile(spec.path, spec.projectRoot);
|
|
268
|
+
if (epoch !== this.epoch) return;
|
|
269
|
+
const width = Math.max(2, Math.min(640, Math.floor(size.width / 2) * 2)), height = Math.max(2, Math.min(360, Math.floor(size.height / 2) * 2));
|
|
270
|
+
const info = spec.kind === "video" ? await probeMedia(spec, controller.signal) : {};
|
|
271
|
+
if (epoch !== this.epoch) return;
|
|
272
|
+
const input = ["-nostdin", "-loglevel", "error", "-hwaccel", "none", "-ss", String(this.positionSec), ...spec.kind === "video" ? ["-re"] : [], "-i", path];
|
|
273
|
+
const output = spec.kind === "video" ? ["-an", "-vf", `scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2,fps=8`, "-pix_fmt", "rgba", "-f", "rawvideo", "pipe:1"] : ["-vn", "-f", "f32le", "-ac", "2", "-ar", "48000", "pipe:1"];
|
|
274
|
+
const withAudio = spec.kind === "video" && info.hasAudio;
|
|
275
|
+
if (withAudio) output.push("-map", "0:a:0", "-vn", "-f", "f32le", "-ac", "2", "-ar", "48000", "pipe:3");
|
|
276
|
+
const child = this.process = spawn("ffmpeg", [...input, ...output], { stdio: withAudio ? ["pipe", "pipe", "pipe", "pipe"] : ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
277
|
+
child.stdin.end();
|
|
278
|
+
let diagnostic = "";
|
|
279
|
+
child.stderr.on("data", (chunk) => {
|
|
280
|
+
diagnostic = (diagnostic + chunk.toString()).slice(-2e3);
|
|
281
|
+
});
|
|
282
|
+
const closed = new Promise((done, fail2) => {
|
|
283
|
+
child.once("error", fail2);
|
|
284
|
+
child.once("close", done);
|
|
285
|
+
});
|
|
286
|
+
this.cleanup = closed.catch(() => {
|
|
287
|
+
});
|
|
288
|
+
this.playing = true;
|
|
289
|
+
this.changed(spec.kind === "video" && !withAudio ? "Playing · no audio track" : "Playing");
|
|
290
|
+
const audioWork = withAudio ? this.consumeAudio(child.stdio[3], controller, epoch) : void 0;
|
|
291
|
+
if (audioWork) void audioWork.catch((error) => {
|
|
292
|
+
if (epoch === this.epoch) {
|
|
293
|
+
this.pause();
|
|
294
|
+
this.changed(error.message);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
if (spec.kind === "video") {
|
|
298
|
+
const bytes = width * height * 4;
|
|
299
|
+
let pending = Buffer.alloc(0), frames = 0;
|
|
300
|
+
const offset2 = this.positionSec;
|
|
301
|
+
for await (const chunk of child.stdout) {
|
|
302
|
+
if (epoch !== this.epoch) break;
|
|
303
|
+
pending = Buffer.concat([pending, chunk]);
|
|
304
|
+
while (pending.length >= bytes && epoch === this.epoch) {
|
|
305
|
+
frame(pending.subarray(0, bytes), width, height);
|
|
306
|
+
pending = pending.subarray(bytes);
|
|
307
|
+
frames++;
|
|
308
|
+
if (!withAudio) this.positionSec = offset2 + frames / 8;
|
|
309
|
+
this.changed();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
} else await this.consumeAudio(child.stdout, controller, epoch);
|
|
313
|
+
if (audioWork) await audioWork;
|
|
314
|
+
const code = await closed;
|
|
315
|
+
if (epoch !== this.epoch) return;
|
|
316
|
+
if (code !== 0) throw new Error(diagnostic.trim() || "Media decoder failed");
|
|
317
|
+
this.pause();
|
|
318
|
+
this.positionSec = 0;
|
|
319
|
+
this.changed("Playback complete");
|
|
320
|
+
} catch (error) {
|
|
321
|
+
if (epoch !== this.epoch) return;
|
|
322
|
+
this.pause();
|
|
323
|
+
this.changed(error instanceof Error ? error.message : String(error));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async consumeAudio(source, controller, epoch) {
|
|
327
|
+
const audio = this.audio = Audio.create({ autoStart: false, sampleRate: 48e3 });
|
|
328
|
+
audio.on("error", (error) => {
|
|
329
|
+
if (epoch === this.epoch) {
|
|
330
|
+
this.pause();
|
|
331
|
+
this.changed(error.message);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
if (!(this.silent ? audio.startMixer() : audio.start())) throw new Error("Audio output is unavailable");
|
|
335
|
+
this.audioOffset = this.positionSec;
|
|
336
|
+
const stream = this.stream = await audio.playStream(source, { format: "pcm", sampleFormat: "f32le", channels: 2, sampleRate: 48e3, buffer: { capacityMs: 500, startupMs: 50, resumeMs: 50 }, signal: controller.signal });
|
|
337
|
+
if (epoch !== this.epoch) {
|
|
338
|
+
stream.dispose();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
stream.on("error", (error) => {
|
|
342
|
+
if (epoch === this.epoch) {
|
|
343
|
+
this.pause();
|
|
344
|
+
this.changed(error.message);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
this.ticker = setInterval(() => {
|
|
348
|
+
if (this.silent) audio.mixFrames(480, 2);
|
|
349
|
+
const stats = stream.getStats();
|
|
350
|
+
this.positionSec = this.audioOffset + Number(stats.framesPlayed) / stats.sampleRate;
|
|
351
|
+
this.changed();
|
|
352
|
+
}, this.silent ? 10 : 100);
|
|
353
|
+
await stream.closed;
|
|
354
|
+
}
|
|
355
|
+
pause() {
|
|
356
|
+
++this.epoch;
|
|
357
|
+
if (this.stream) {
|
|
358
|
+
try {
|
|
359
|
+
const stats = this.stream.getStats();
|
|
360
|
+
this.positionSec = this.audioOffset + Number(stats.framesPlayed) / stats.sampleRate;
|
|
361
|
+
} catch {
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
this.controller?.abort();
|
|
365
|
+
this.controller = void 0;
|
|
366
|
+
this.stream?.dispose();
|
|
367
|
+
this.stream = void 0;
|
|
368
|
+
this.audio?.dispose();
|
|
369
|
+
this.audio = void 0;
|
|
370
|
+
if (this.ticker) clearInterval(this.ticker);
|
|
371
|
+
this.ticker = void 0;
|
|
372
|
+
const child = this.process;
|
|
373
|
+
this.process = void 0;
|
|
374
|
+
if (child && child.exitCode === null) {
|
|
375
|
+
child.kill("SIGTERM");
|
|
376
|
+
const timer = setTimeout(() => {
|
|
377
|
+
if (child.exitCode === null) child.kill("SIGKILL");
|
|
378
|
+
}, 250);
|
|
379
|
+
timer.unref?.();
|
|
380
|
+
child.once("close", () => clearTimeout(timer));
|
|
381
|
+
}
|
|
382
|
+
const wasPlaying = this.playing;
|
|
383
|
+
this.playing = false;
|
|
384
|
+
if (wasPlaying) this.changed("Paused");
|
|
385
|
+
}
|
|
386
|
+
dispose() {
|
|
387
|
+
this.pause();
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// packages/cli/src/tui/native/components/media.ts
|
|
392
|
+
function mediaPreviewHeight(width, imageWidth, imageHeight, cellAspectRatio = 2) {
|
|
393
|
+
if (![width, imageWidth, imageHeight, cellAspectRatio].every((value) => Number.isFinite(value) && value > 0)) return 8;
|
|
394
|
+
return Math.max(1, Math.min(80, Math.round(width * imageHeight / imageWidth / cellAspectRatio)));
|
|
395
|
+
}
|
|
396
|
+
function audioWaveform(samples, width) {
|
|
397
|
+
const cells = Math.max(1, Math.min(240, Math.floor(width)));
|
|
398
|
+
const glyphs = "▁▂▃▄▅▆▇█";
|
|
399
|
+
return Array.from({ length: cells }, (_, column) => {
|
|
400
|
+
const begin = Math.floor(column * samples.length / cells), end = Math.max(begin + 1, Math.floor((column + 1) * samples.length / cells));
|
|
401
|
+
let peak = 0;
|
|
402
|
+
for (let index = begin; index < end && index < samples.length; index++) if (Number.isFinite(samples[index])) peak = Math.max(peak, Math.abs(samples[index]));
|
|
403
|
+
return glyphs[Math.min(7, Math.floor(Math.min(1, peak) * 7))];
|
|
404
|
+
}).join("");
|
|
405
|
+
}
|
|
406
|
+
var time = (seconds) => `${Math.floor(Math.max(0, seconds) / 60)}:${String(Math.floor(Math.max(0, seconds) % 60)).padStart(2, "0")}`;
|
|
407
|
+
var NativeMediaView = class extends BoxRenderable {
|
|
408
|
+
constructor(renderer2, mediaId, spec, colors, sendEvent) {
|
|
409
|
+
super(renderer2, { id: `media:${mediaId}`, width: "100%", flexDirection: "column", flexShrink: 0 });
|
|
410
|
+
this.renderer = renderer2;
|
|
411
|
+
this.mediaId = mediaId;
|
|
412
|
+
this.colors = colors;
|
|
413
|
+
this.sendEvent = sendEvent;
|
|
414
|
+
this.spec = spec;
|
|
415
|
+
this.location = new TextRenderable(renderer2, { id: `media-location:${mediaId}`, content: spec.path, width: "100%", wrapMode: "word", selectable: true, fg: colors.dim });
|
|
416
|
+
this.status = new TextRenderable(renderer2, { id: `media-status:${mediaId}`, content: "", width: "100%", wrapMode: "word", selectable: true, fg: colors.dim });
|
|
417
|
+
this.wave = new TextRenderable(renderer2, { id: `media-waveform:${mediaId}`, content: "", width: "100%", height: 1, wrapMode: "none", fg: colors.foreground, visible: false });
|
|
418
|
+
this.playheadLabel = new TextRenderable(renderer2, { id: `media-position:${mediaId}`, content: "", width: "100%", height: 1, wrapMode: "none", fg: colors.dim, visible: false });
|
|
419
|
+
this.controls = new BoxRenderable(renderer2, { id: `media-controls:${mediaId}`, flexDirection: "row", gap: 2, flexShrink: 0 });
|
|
420
|
+
this.playControl = this.control("play", "Play", () => this.togglePlayback());
|
|
421
|
+
this.controls.add(this.playControl);
|
|
422
|
+
this.controls.add(this.control("open", "Open ↗", () => {
|
|
423
|
+
void this.open();
|
|
424
|
+
}));
|
|
425
|
+
this.playback = new NativeMediaPlayback((message) => {
|
|
426
|
+
if (this.isDestroyed) return;
|
|
427
|
+
if (message) this.currentStatus = message;
|
|
428
|
+
this.refreshStatus();
|
|
429
|
+
});
|
|
430
|
+
this.add(this.location);
|
|
431
|
+
this.add(this.wave);
|
|
432
|
+
this.add(this.playheadLabel);
|
|
433
|
+
this.add(this.status);
|
|
434
|
+
this.add(this.controls);
|
|
435
|
+
this.update(spec);
|
|
436
|
+
}
|
|
437
|
+
renderer;
|
|
438
|
+
mediaId;
|
|
439
|
+
colors;
|
|
440
|
+
sendEvent;
|
|
441
|
+
spec;
|
|
442
|
+
location;
|
|
443
|
+
status;
|
|
444
|
+
wave;
|
|
445
|
+
playheadLabel;
|
|
446
|
+
controls;
|
|
447
|
+
playControl;
|
|
448
|
+
image;
|
|
449
|
+
pool;
|
|
450
|
+
playback;
|
|
451
|
+
probeController;
|
|
452
|
+
samples;
|
|
453
|
+
waveformText = "";
|
|
454
|
+
sourceWidth = 16;
|
|
455
|
+
sourceHeight = 9;
|
|
456
|
+
duration = 0;
|
|
457
|
+
hovered = false;
|
|
458
|
+
lastWidth = 0;
|
|
459
|
+
currentStatus = "";
|
|
460
|
+
sourceEpoch = 0;
|
|
461
|
+
needsProbe = true;
|
|
462
|
+
get closed() {
|
|
463
|
+
return this.playback.closed;
|
|
464
|
+
}
|
|
465
|
+
pausePlayback() {
|
|
466
|
+
this.playback.pause();
|
|
467
|
+
}
|
|
468
|
+
control(action, label, operation) {
|
|
469
|
+
const control = new TextRenderable(this.renderer, {
|
|
470
|
+
id: `media-control:${this.mediaId}:${action}`,
|
|
471
|
+
content: label,
|
|
472
|
+
fg: this.colors.foreground,
|
|
473
|
+
selectable: false,
|
|
474
|
+
onMouseDown: (event) => {
|
|
475
|
+
if (event.button === 0) {
|
|
476
|
+
operation();
|
|
477
|
+
event.stopPropagation();
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
onKeyDown: (event) => {
|
|
481
|
+
if (event.eventType !== "release" && (event.name === "return" || event.sequence === " ")) {
|
|
482
|
+
operation();
|
|
483
|
+
event.preventDefault();
|
|
484
|
+
event.stopPropagation();
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
control.focusable = true;
|
|
489
|
+
control.on("focused", () => {
|
|
490
|
+
control.attributes = 32;
|
|
491
|
+
});
|
|
492
|
+
control.on("blurred", () => {
|
|
493
|
+
control.attributes = 0;
|
|
494
|
+
});
|
|
495
|
+
return control;
|
|
496
|
+
}
|
|
497
|
+
update(spec) {
|
|
498
|
+
const changed = spec.path !== this.spec.path || spec.kind !== this.spec.kind;
|
|
499
|
+
this.spec = spec;
|
|
500
|
+
this.location.content = spec.path;
|
|
501
|
+
this.playControl.visible = spec.kind !== "image";
|
|
502
|
+
if (changed) {
|
|
503
|
+
this.playback.pause();
|
|
504
|
+
this.playback.positionSec = 0;
|
|
505
|
+
this.probeController?.abort();
|
|
506
|
+
this.probeController = void 0;
|
|
507
|
+
this.needsProbe = true;
|
|
508
|
+
this.pool?.dispose();
|
|
509
|
+
this.pool = void 0;
|
|
510
|
+
this.samples = void 0;
|
|
511
|
+
this.sourceEpoch++;
|
|
512
|
+
}
|
|
513
|
+
if ((spec.kind === "image" || spec.kind === "video") && !this.image) {
|
|
514
|
+
this.image = new ImageRenderable(this.renderer, {
|
|
515
|
+
id: `media-preview:${this.mediaId}`,
|
|
516
|
+
width: "100%",
|
|
517
|
+
height: 8,
|
|
518
|
+
fit: "fit",
|
|
519
|
+
protocol: "auto",
|
|
520
|
+
onLoad: (image) => {
|
|
521
|
+
if (this.spec.kind === "image") {
|
|
522
|
+
this.sourceWidth = image.width;
|
|
523
|
+
this.sourceHeight = image.height;
|
|
524
|
+
}
|
|
525
|
+
this.refreshGeometry();
|
|
526
|
+
},
|
|
527
|
+
onError: () => {
|
|
528
|
+
this.currentStatus = "Preview unavailable · use Open";
|
|
529
|
+
this.refreshStatus();
|
|
530
|
+
},
|
|
531
|
+
onMouseOver: () => {
|
|
532
|
+
this.hovered = true;
|
|
533
|
+
this.refreshStatus();
|
|
534
|
+
},
|
|
535
|
+
onMouseOut: () => {
|
|
536
|
+
this.hovered = false;
|
|
537
|
+
this.refreshStatus();
|
|
538
|
+
},
|
|
539
|
+
onMouseUp: (event) => {
|
|
540
|
+
if (event.button === 0 && !event.isDragging) {
|
|
541
|
+
void this.open();
|
|
542
|
+
event.stopPropagation();
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
onKeyDown: (event) => {
|
|
546
|
+
if (event.eventType !== "release" && event.name === "return") {
|
|
547
|
+
void this.open();
|
|
548
|
+
event.preventDefault();
|
|
549
|
+
event.stopPropagation();
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
this.image.focusable = true;
|
|
554
|
+
this.add(this.image, 1);
|
|
555
|
+
}
|
|
556
|
+
if (this.image) {
|
|
557
|
+
this.image.visible = spec.kind === "image" || spec.kind === "video";
|
|
558
|
+
const source = spec.kind === "image" ? spec.path : spec.previewPath;
|
|
559
|
+
if (source && this.image.source !== source && !this.playback.playing) {
|
|
560
|
+
const epoch = this.sourceEpoch;
|
|
561
|
+
void validateMediaFile(source, spec.projectRoot).then((path) => {
|
|
562
|
+
if (!this.isDestroyed && epoch === this.sourceEpoch && !this.playback.playing && this.image && this.image.source !== path) this.image.source = path;
|
|
563
|
+
}).catch((error) => {
|
|
564
|
+
if (!this.isDestroyed) {
|
|
565
|
+
this.currentStatus = `Preview unavailable · ${error.message}`;
|
|
566
|
+
this.refreshStatus();
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
this.wave.visible = spec.kind === "audio" || spec.kind === "music";
|
|
572
|
+
this.playheadLabel.visible = spec.kind !== "image";
|
|
573
|
+
this.refreshStatus();
|
|
574
|
+
}
|
|
575
|
+
startProbe() {
|
|
576
|
+
if (this.needsProbe && !this.probeController) {
|
|
577
|
+
this.needsProbe = false;
|
|
578
|
+
const spec = this.spec;
|
|
579
|
+
const controller = this.probeController = new AbortController(), epoch = this.sourceEpoch;
|
|
580
|
+
if (spec.kind !== "image") void probeMedia(spec, controller.signal).then((info) => {
|
|
581
|
+
if (controller.signal.aborted || epoch !== this.sourceEpoch || this.isDestroyed) return;
|
|
582
|
+
this.sourceWidth = info.width || 16;
|
|
583
|
+
this.sourceHeight = info.height || 9;
|
|
584
|
+
this.duration = info.durationSec || 0;
|
|
585
|
+
this.refreshGeometry();
|
|
586
|
+
if (spec.kind === "audio" || spec.kind === "music") this.loadWaveform(controller, epoch);
|
|
587
|
+
}).catch((error) => {
|
|
588
|
+
if (!controller.signal.aborted && !this.isDestroyed) {
|
|
589
|
+
this.currentStatus = `Media metadata unavailable · ${error.message}`;
|
|
590
|
+
this.refreshStatus();
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
this.refreshStatus();
|
|
595
|
+
}
|
|
596
|
+
loadWaveform(controller, epoch) {
|
|
597
|
+
execFile2("ffmpeg", ["-nostdin", "-loglevel", "error", "-hwaccel", "none", "-i", this.spec.path, "-t", "600", "-vn", "-ac", "1", "-ar", "1000", "-f", "f32le", "pipe:1"], { encoding: "buffer", signal: controller.signal, timeout: 1e4, maxBuffer: 25e5 }, (error, buffer) => {
|
|
598
|
+
if (controller.signal.aborted || epoch !== this.sourceEpoch || this.isDestroyed) return;
|
|
599
|
+
if (error) {
|
|
600
|
+
this.currentStatus = "Waveform unavailable · playback and Open remain available";
|
|
601
|
+
this.refreshStatus();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const samples = new Float32Array(Math.floor(buffer.length / 4));
|
|
605
|
+
for (let index = 0; index < samples.length; index++) samples[index] = buffer.readFloatLE(index * 4);
|
|
606
|
+
this.samples = samples;
|
|
607
|
+
this.lastWidth = 0;
|
|
608
|
+
this.refreshGeometry();
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
reconcile(viewport, active = true) {
|
|
612
|
+
if (this.isDestroyed) return;
|
|
613
|
+
let ancestor = this;
|
|
614
|
+
while (ancestor && active) {
|
|
615
|
+
active = ancestor.visible;
|
|
616
|
+
ancestor = ancestor.parent;
|
|
617
|
+
}
|
|
618
|
+
const visible = active && this.y + this.height > viewport.y && this.y < viewport.y + viewport.height;
|
|
619
|
+
if (!visible && this.playback.playing) this.playback.pause();
|
|
620
|
+
if (!visible && this.probeController && !this.samples) {
|
|
621
|
+
this.probeController.abort();
|
|
622
|
+
this.probeController = void 0;
|
|
623
|
+
this.needsProbe = true;
|
|
624
|
+
}
|
|
625
|
+
if (visible) this.startProbe();
|
|
626
|
+
this.refreshGeometry();
|
|
627
|
+
}
|
|
628
|
+
refreshGeometry() {
|
|
629
|
+
if (this.isDestroyed) return;
|
|
630
|
+
const width = Math.max(1, this.width);
|
|
631
|
+
if (this.image) {
|
|
632
|
+
const height = mediaPreviewHeight(width, this.sourceWidth, this.sourceHeight, this.image.cellAspectRatio);
|
|
633
|
+
if (this.image.height !== height) this.image.height = height;
|
|
634
|
+
}
|
|
635
|
+
if (width !== this.lastWidth) {
|
|
636
|
+
this.lastWidth = width;
|
|
637
|
+
if (this.samples) this.waveformText = audioWaveform(this.samples, width);
|
|
638
|
+
}
|
|
639
|
+
this.refreshStatus();
|
|
640
|
+
}
|
|
641
|
+
refreshStatus() {
|
|
642
|
+
if (this.isDestroyed) return;
|
|
643
|
+
const text = `${this.hovered ? "Open ↗ · " : ""}${this.currentStatus}`;
|
|
644
|
+
if (this.status.plainText !== text) this.status.content = text;
|
|
645
|
+
const label = this.playback?.playing ? "Pause" : this.playback?.positionSec ? "Resume" : "Play";
|
|
646
|
+
if (this.playControl.plainText !== label) this.playControl.content = label;
|
|
647
|
+
if (this.waveformText) {
|
|
648
|
+
const cursor = this.duration > 0 ? Math.min(this.waveformText.length - 1, Math.floor(this.playback.positionSec / this.duration * this.waveformText.length)) : 0;
|
|
649
|
+
const waveform = this.playback.positionSec > 0 ? this.waveformText.slice(0, cursor) + "│" + this.waveformText.slice(cursor + 1) : this.waveformText;
|
|
650
|
+
if (this.wave.plainText !== waveform) this.wave.content = waveform;
|
|
651
|
+
}
|
|
652
|
+
const progress = `${time(this.playback?.positionSec ?? 0)} / ${this.duration ? time(this.duration) : "--:--"}${this.duration > 600 && this.samples ? " · waveform shows first 10 min" : ""}`;
|
|
653
|
+
if (this.playheadLabel.plainText !== progress) this.playheadLabel.content = progress;
|
|
654
|
+
}
|
|
655
|
+
togglePlayback() {
|
|
656
|
+
if (this.playback.playing) {
|
|
657
|
+
this.playback.pause();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
if (this.spec.kind === "image") return;
|
|
661
|
+
void this.playback.play(this.spec, { width: Math.max(2, this.width * 4), height: Math.max(2, (this.image?.height ?? 24) * 8) }, (rgba, width, height) => {
|
|
662
|
+
if (!this.image || this.isDestroyed) return;
|
|
663
|
+
if (!this.pool || this.pool.width !== width || this.pool.height !== height) {
|
|
664
|
+
this.pool?.dispose();
|
|
665
|
+
this.pool = new NativeImagePool({ width, height, capacity: 3, owner: this.renderer.nativeScene.resourceContext });
|
|
666
|
+
}
|
|
667
|
+
const frame = this.pool.publishRgba(rgba);
|
|
668
|
+
if (frame) {
|
|
669
|
+
this.image.source = frame;
|
|
670
|
+
frame.dispose();
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
async open() {
|
|
675
|
+
try {
|
|
676
|
+
const path = await validateMediaFile(this.spec.path, this.spec.projectRoot);
|
|
677
|
+
if (this.isDestroyed) return;
|
|
678
|
+
this.sendEvent({ type: "action", action: "media-open", id: this.mediaId, text: path });
|
|
679
|
+
if (process.env["OMNIUS_MEDIA_TEST_NO_OPEN"] === "1") {
|
|
680
|
+
this.currentStatus = "Open requested (test fixture)";
|
|
681
|
+
this.refreshStatus();
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
const command2 = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer.exe" : "xdg-open";
|
|
685
|
+
execFile2(command2, [path], { timeout: 5e3 }, (error) => {
|
|
686
|
+
if (!this.isDestroyed) {
|
|
687
|
+
this.currentStatus = error ? `Open failed · ${error.message}` : "Opened in the system viewer";
|
|
688
|
+
this.refreshStatus();
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
} catch (error) {
|
|
692
|
+
if (!this.isDestroyed) {
|
|
693
|
+
this.currentStatus = `Open unavailable · ${error instanceof Error ? error.message : String(error)}`;
|
|
694
|
+
this.refreshStatus();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
applyTheme(colors) {
|
|
699
|
+
this.colors = colors;
|
|
700
|
+
for (const view of [this.location, this.status, this.wave, this.playheadLabel, ...this.controls.getChildren()]) if (view instanceof TextRenderable) {
|
|
701
|
+
view.fg = view === this.wave ? colors.foreground : colors.dim;
|
|
702
|
+
view.bg = colors.background;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
destroy() {
|
|
706
|
+
this.playback.dispose();
|
|
707
|
+
this.probeController?.abort();
|
|
708
|
+
this.pool?.dispose();
|
|
709
|
+
this.pool = void 0;
|
|
710
|
+
super.destroy();
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
|
|
173
714
|
// packages/cli/src/tui/native/components/code.ts
|
|
174
715
|
var aliases = {
|
|
175
716
|
js: "javascript",
|
|
@@ -297,10 +838,10 @@ function nativeMarkdownSections(owner, source, streaming = false) {
|
|
|
297
838
|
}
|
|
298
839
|
];
|
|
299
840
|
const rows = source.split("\n"), offsets = [];
|
|
300
|
-
let
|
|
841
|
+
let offset2 = 0;
|
|
301
842
|
for (const row of rows) {
|
|
302
|
-
offsets.push(
|
|
303
|
-
|
|
843
|
+
offsets.push(offset2);
|
|
844
|
+
offset2 += row.length + 1;
|
|
304
845
|
}
|
|
305
846
|
const output = [], stack = [
|
|
306
847
|
{ level: 0, children: output }
|
|
@@ -400,7 +941,7 @@ var NativeBlockView = class {
|
|
|
400
941
|
this.inline = inline;
|
|
401
942
|
this.spec = spec;
|
|
402
943
|
this.pixel = inline && spec.kind === "text" && Boolean(spec.actions?.length) && spec.actions.every((action) => action.id.startsWith("pixel:"));
|
|
403
|
-
this.root = new
|
|
944
|
+
this.root = new BoxRenderable2(context.renderer, {
|
|
404
945
|
id: `block:${spec.id}`,
|
|
405
946
|
flexDirection: "column",
|
|
406
947
|
flexShrink: inline && !this.pixel ? 1 : 0,
|
|
@@ -424,6 +965,7 @@ var NativeBlockView = class {
|
|
|
424
965
|
actions;
|
|
425
966
|
progress;
|
|
426
967
|
image;
|
|
968
|
+
media;
|
|
427
969
|
terminal;
|
|
428
970
|
collapsed = false;
|
|
429
971
|
previousModelCollapsed;
|
|
@@ -443,7 +985,7 @@ var NativeBlockView = class {
|
|
|
443
985
|
this.root.marginBottom = 0;
|
|
444
986
|
this.root.flexDirection = spec.kind === "row" ? "row" : "column";
|
|
445
987
|
if (spec.title) {
|
|
446
|
-
this.title = new
|
|
988
|
+
this.title = new TextRenderable2(renderer2, {
|
|
447
989
|
id: `block-title:${spec.id}`,
|
|
448
990
|
content: "",
|
|
449
991
|
fg: colors.foreground,
|
|
@@ -467,7 +1009,7 @@ var NativeBlockView = class {
|
|
|
467
1009
|
nativeControlFocus(this.title, 1);
|
|
468
1010
|
this.root.add(this.title);
|
|
469
1011
|
}
|
|
470
|
-
this.body = new
|
|
1012
|
+
this.body = new BoxRenderable2(renderer2, {
|
|
471
1013
|
id: `block-body:${spec.id}`,
|
|
472
1014
|
flexDirection: spec.kind === "row" ? "row" : "column",
|
|
473
1015
|
width: this.pixel ? "auto" : "100%",
|
|
@@ -487,8 +1029,12 @@ var NativeBlockView = class {
|
|
|
487
1029
|
});
|
|
488
1030
|
this.context.terminals.set(spec.id, this.terminal);
|
|
489
1031
|
this.body.add(this.terminal);
|
|
1032
|
+
} else if (spec.kind === "media" && spec.media) {
|
|
1033
|
+
this.media = new NativeMediaView(renderer2, spec.id, spec.media, colors, this.context.emit);
|
|
1034
|
+
this.context.mediaViews?.add(this.media);
|
|
1035
|
+
this.body.add(this.media);
|
|
490
1036
|
} else if (spec.kind === "image" && spec.imagePath) {
|
|
491
|
-
this.image = new
|
|
1037
|
+
this.image = new ImageRenderable2(renderer2, {
|
|
492
1038
|
id: `image:${spec.id}`,
|
|
493
1039
|
source: spec.imagePath,
|
|
494
1040
|
width: "100%",
|
|
@@ -499,7 +1045,7 @@ var NativeBlockView = class {
|
|
|
499
1045
|
if (this.image) this.image.visible = false;
|
|
500
1046
|
if (this.text) {
|
|
501
1047
|
this.text.visible = true;
|
|
502
|
-
if (this.text instanceof
|
|
1048
|
+
if (this.text instanceof TextRenderable2) this.text.content = styledText(this.spec.text ?? "Image unavailable");
|
|
503
1049
|
}
|
|
504
1050
|
this.context.emit({ type: "action", action: "image-error", id: spec.id, text: String(error) });
|
|
505
1051
|
},
|
|
@@ -509,7 +1055,7 @@ var NativeBlockView = class {
|
|
|
509
1055
|
}
|
|
510
1056
|
});
|
|
511
1057
|
this.body.add(this.image);
|
|
512
|
-
this.text = new
|
|
1058
|
+
this.text = new TextRenderable2(renderer2, { id: `image-fallback:${spec.id}`, content: "", visible: false, width: "100%", wrapMode: "word", fg: colors.dim, selectable: true });
|
|
513
1059
|
this.body.add(this.text);
|
|
514
1060
|
} else if (spec.kind === "markdown") {
|
|
515
1061
|
this.text = new MarkdownRenderable(renderer2, {
|
|
@@ -561,7 +1107,7 @@ var NativeBlockView = class {
|
|
|
561
1107
|
});
|
|
562
1108
|
this.body.add(this.text);
|
|
563
1109
|
} else if (spec.text !== void 0) {
|
|
564
|
-
this.text = new
|
|
1110
|
+
this.text = new TextRenderable2(renderer2, {
|
|
565
1111
|
id: `text:${spec.id}`,
|
|
566
1112
|
content: "",
|
|
567
1113
|
width: this.pixel ? "auto" : "100%",
|
|
@@ -574,7 +1120,7 @@ var NativeBlockView = class {
|
|
|
574
1120
|
this.body.add(this.text);
|
|
575
1121
|
}
|
|
576
1122
|
if (spec.kind === "progress") {
|
|
577
|
-
this.progress = new
|
|
1123
|
+
this.progress = new TextRenderable2(renderer2, {
|
|
578
1124
|
id: `progress-track:${spec.id}`,
|
|
579
1125
|
width: "100%",
|
|
580
1126
|
height: 1,
|
|
@@ -588,7 +1134,7 @@ var NativeBlockView = class {
|
|
|
588
1134
|
this.body.add(this.progress);
|
|
589
1135
|
}
|
|
590
1136
|
this.children = new NativeBlockList(this.context, this.body);
|
|
591
|
-
this.actions = new
|
|
1137
|
+
this.actions = new BoxRenderable2(renderer2, {
|
|
592
1138
|
id: `block-actions:${spec.id}`,
|
|
593
1139
|
flexDirection: "row",
|
|
594
1140
|
gap: 1,
|
|
@@ -597,6 +1143,11 @@ var NativeBlockView = class {
|
|
|
597
1143
|
this.root.add(this.actions);
|
|
598
1144
|
}
|
|
599
1145
|
reset() {
|
|
1146
|
+
if (this.media) {
|
|
1147
|
+
this.context.mediaViews?.delete(this.media);
|
|
1148
|
+
this.media.destroy();
|
|
1149
|
+
this.media = void 0;
|
|
1150
|
+
}
|
|
600
1151
|
this.children?.destroy();
|
|
601
1152
|
this.markdownSections?.destroy();
|
|
602
1153
|
this.markdownSections = void 0;
|
|
@@ -632,13 +1183,14 @@ var NativeBlockView = class {
|
|
|
632
1183
|
this.markdownSections.destroy();
|
|
633
1184
|
this.markdownSections = void 0;
|
|
634
1185
|
}
|
|
635
|
-
if (this.text instanceof
|
|
1186
|
+
if (this.text instanceof TextRenderable2) this.text.content = styledText(spec.kind === "image" ? spec.text ?? "Image unavailable" : spec.text);
|
|
636
1187
|
else if (this.text instanceof MarkdownRenderable || this.text instanceof CodeRenderable) {
|
|
637
1188
|
const code = this.text instanceof CodeRenderable ? nativeCodeContent(plainText(spec.text), spec.language) : void 0;
|
|
638
1189
|
this.text.content = sections ? "" : code?.content ?? plainText(spec.text);
|
|
639
1190
|
this.text.streaming = spec.streaming ?? false;
|
|
640
1191
|
if (this.text instanceof CodeRenderable) this.text.filetype = code?.language ?? "text";
|
|
641
1192
|
}
|
|
1193
|
+
if (this.media && spec.media) this.media.update(spec.media);
|
|
642
1194
|
if (this.image && spec.imagePath && this.image.source !== spec.imagePath) this.image.source = spec.imagePath;
|
|
643
1195
|
if (this.terminal) this.terminal.height = spec.height ?? 14;
|
|
644
1196
|
if (this.image) this.image.height = spec.height ?? 12;
|
|
@@ -649,7 +1201,7 @@ var NativeBlockView = class {
|
|
|
649
1201
|
this.actionsSignature = actionsSignature;
|
|
650
1202
|
for (const child of [...this.actions.getChildren()]) child.destroy();
|
|
651
1203
|
for (const action of spec.actions ?? []) {
|
|
652
|
-
const button = new
|
|
1204
|
+
const button = new TextRenderable2(this.context.renderer, {
|
|
653
1205
|
id: `block-action:${spec.id}:${action.id}`,
|
|
654
1206
|
content: plainText(action.label),
|
|
655
1207
|
fg: this.context.colors.foreground,
|
|
@@ -686,6 +1238,20 @@ var NativeBlockView = class {
|
|
|
686
1238
|
if (this.title) this.title.content = `${this.collapsed ? "▸ " : "· "}${plainText(this.spec.title)}`;
|
|
687
1239
|
this.context.emit({ type: "action", action: "toggle-block", id: this.spec.id });
|
|
688
1240
|
}
|
|
1241
|
+
captureDisclosures(result) {
|
|
1242
|
+
if (this.spec.collapsible) Object.defineProperty(result, this.spec.id, { value: this.collapsed, enumerable: true, configurable: true, writable: true });
|
|
1243
|
+
this.children?.captureDisclosures(result);
|
|
1244
|
+
this.markdownSections?.captureDisclosures(result);
|
|
1245
|
+
}
|
|
1246
|
+
restoreDisclosures(state) {
|
|
1247
|
+
if (this.spec.collapsible && Object.hasOwn(state, this.spec.id)) {
|
|
1248
|
+
this.collapsed = state[this.spec.id];
|
|
1249
|
+
if (this.body) this.body.visible = !this.collapsed;
|
|
1250
|
+
if (this.title) this.title.content = `${this.collapsed ? "▸ " : "· "}${plainText(this.spec.title)}`;
|
|
1251
|
+
}
|
|
1252
|
+
this.children?.restoreDisclosures(state);
|
|
1253
|
+
this.markdownSections?.restoreDisclosures(state);
|
|
1254
|
+
}
|
|
689
1255
|
applyTheme() {
|
|
690
1256
|
const colors = this.context.colors;
|
|
691
1257
|
this.root.backgroundColor = colors.background;
|
|
@@ -704,14 +1270,20 @@ var NativeBlockView = class {
|
|
|
704
1270
|
this.progress.fg = colors.foreground;
|
|
705
1271
|
this.progress.bg = colors.background;
|
|
706
1272
|
}
|
|
707
|
-
for (const action of this.actions?.getChildren() ?? []) if (action instanceof
|
|
1273
|
+
for (const action of this.actions?.getChildren() ?? []) if (action instanceof TextRenderable2) {
|
|
708
1274
|
action.fg = colors.foreground;
|
|
709
1275
|
action.bg = colors.background;
|
|
710
1276
|
}
|
|
1277
|
+
this.media?.applyTheme(colors);
|
|
711
1278
|
this.children?.applyTheme();
|
|
712
1279
|
this.markdownSections?.applyTheme();
|
|
713
1280
|
}
|
|
714
1281
|
destroy() {
|
|
1282
|
+
if (this.media) {
|
|
1283
|
+
this.context.mediaViews?.delete(this.media);
|
|
1284
|
+
this.media.destroy();
|
|
1285
|
+
this.media = void 0;
|
|
1286
|
+
}
|
|
715
1287
|
this.children?.destroy();
|
|
716
1288
|
this.markdownSections?.destroy();
|
|
717
1289
|
if (this.terminal) this.context.terminals.delete(this.spec.id);
|
|
@@ -750,7 +1322,10 @@ var NativeBlockList = class {
|
|
|
750
1322
|
reorder(order) {
|
|
751
1323
|
const next = order.filter((id) => this.views.has(id));
|
|
752
1324
|
if (next.length === this.order.length && next.every((id, index) => this.order[index] === id)) return;
|
|
753
|
-
next.forEach((id, index) =>
|
|
1325
|
+
next.forEach((id, index) => {
|
|
1326
|
+
const view = this.views.get(id).root;
|
|
1327
|
+
if (this.parent.getChildren()[index] !== view) this.parent.add(view, index);
|
|
1328
|
+
});
|
|
754
1329
|
this.order = next;
|
|
755
1330
|
}
|
|
756
1331
|
remove(id) {
|
|
@@ -761,6 +1336,13 @@ var NativeBlockList = class {
|
|
|
761
1336
|
applyTheme() {
|
|
762
1337
|
for (const view of this.views.values()) view.applyTheme();
|
|
763
1338
|
}
|
|
1339
|
+
captureDisclosures(result = {}) {
|
|
1340
|
+
for (const view of this.views.values()) view.captureDisclosures(result);
|
|
1341
|
+
return result;
|
|
1342
|
+
}
|
|
1343
|
+
restoreDisclosures(state) {
|
|
1344
|
+
for (const view of this.views.values()) view.restoreDisclosures(state);
|
|
1345
|
+
}
|
|
764
1346
|
clear() {
|
|
765
1347
|
for (const view of this.views.values()) view.destroy();
|
|
766
1348
|
this.views.clear();
|
|
@@ -773,12 +1355,12 @@ var NativeBlockList = class {
|
|
|
773
1355
|
|
|
774
1356
|
// packages/cli/src/tui/native/components/modals.ts
|
|
775
1357
|
import {
|
|
776
|
-
BoxRenderable as
|
|
1358
|
+
BoxRenderable as BoxRenderable4,
|
|
777
1359
|
InputRenderable,
|
|
778
1360
|
ScrollBoxRenderable as ScrollBoxRenderable2,
|
|
779
1361
|
TextareaRenderable,
|
|
780
1362
|
TextAttributes as TextAttributes4,
|
|
781
|
-
TextRenderable as
|
|
1363
|
+
TextRenderable as TextRenderable3
|
|
782
1364
|
} from "@opentui/core";
|
|
783
1365
|
|
|
784
1366
|
// packages/cli/src/tui/native/components/select.ts
|
|
@@ -820,8 +1402,8 @@ function styleNativeSlider(slider, colors) {
|
|
|
820
1402
|
const seek = (event) => {
|
|
821
1403
|
const horizontal = slider.orientation === "horizontal";
|
|
822
1404
|
const length = horizontal ? slider.width : slider.height;
|
|
823
|
-
const
|
|
824
|
-
const progress = length > 1 ? Math.max(0, Math.min(1,
|
|
1405
|
+
const offset2 = horizontal ? event.x - slider.x : event.y - slider.y;
|
|
1406
|
+
const progress = length > 1 ? Math.max(0, Math.min(1, offset2 / (length - 1))) : 0;
|
|
825
1407
|
slider.value = slider.min + progress * (slider.max - slider.min);
|
|
826
1408
|
event.preventDefault();
|
|
827
1409
|
event.stopPropagation();
|
|
@@ -854,8 +1436,8 @@ var NativeSelectRenderable = class extends SelectRenderable {
|
|
|
854
1436
|
this.renderAfter = (buffer) => {
|
|
855
1437
|
const count = this.visibleCount();
|
|
856
1438
|
if (!this.showScrollIndicator || this.options.length <= count) return;
|
|
857
|
-
const
|
|
858
|
-
drawDotRail(buffer, this.width - 1, 0, this.height, false,
|
|
1439
|
+
const offset2 = Math.max(0, Math.min(this.getSelectedIndex() - Math.floor(count / 2), this.options.length - count));
|
|
1440
|
+
drawDotRail(buffer, this.width - 1, 0, this.height, false, offset2 / (this.options.length - count), colors);
|
|
859
1441
|
};
|
|
860
1442
|
}
|
|
861
1443
|
visibleCount() {
|
|
@@ -931,7 +1513,7 @@ var NativeSelectRenderable = class extends SelectRenderable {
|
|
|
931
1513
|
};
|
|
932
1514
|
|
|
933
1515
|
// packages/cli/src/tui/native/components/corner-frame.ts
|
|
934
|
-
import { BoxRenderable as
|
|
1516
|
+
import { BoxRenderable as BoxRenderable3, CliRenderEvents as CliRenderEvents2, RenderableEvents as RenderableEvents2, TextAttributes as TextAttributes3 } from "@opentui/core";
|
|
935
1517
|
function drawCornerFrame(buffer, panel, colors, progress = 1) {
|
|
936
1518
|
const { x, y, width, height } = panel;
|
|
937
1519
|
if (width <= 0 || height <= 0) return;
|
|
@@ -970,7 +1552,7 @@ var NativeCornerFrame = class {
|
|
|
970
1552
|
this.colors = colors;
|
|
971
1553
|
this.renderer = renderer2;
|
|
972
1554
|
this.container = container;
|
|
973
|
-
this.chrome = new
|
|
1555
|
+
this.chrome = new BoxRenderable3(renderer2, {
|
|
974
1556
|
id: `${panel.id}:corners`,
|
|
975
1557
|
position: "absolute",
|
|
976
1558
|
left: 0,
|
|
@@ -1100,7 +1682,7 @@ var NativeModalView = class {
|
|
|
1100
1682
|
this.close = close2;
|
|
1101
1683
|
this.spec = spec;
|
|
1102
1684
|
const { renderer: renderer2, colors } = context;
|
|
1103
|
-
this.root = new
|
|
1685
|
+
this.root = new BoxRenderable4(renderer2, {
|
|
1104
1686
|
id: `modal:${spec.id}`,
|
|
1105
1687
|
position: "absolute",
|
|
1106
1688
|
top: 0,
|
|
@@ -1122,7 +1704,7 @@ var NativeModalView = class {
|
|
|
1122
1704
|
}
|
|
1123
1705
|
}
|
|
1124
1706
|
});
|
|
1125
|
-
this.panel = new
|
|
1707
|
+
this.panel = new BoxRenderable4(renderer2, {
|
|
1126
1708
|
id: `modal-panel:${spec.id}`,
|
|
1127
1709
|
flexDirection: "column",
|
|
1128
1710
|
width: "94%",
|
|
@@ -1138,7 +1720,12 @@ var NativeModalView = class {
|
|
|
1138
1720
|
this.root.add(this.panel);
|
|
1139
1721
|
this.frame = new NativeCornerFrame(this.panel, colors, renderer2, this.root);
|
|
1140
1722
|
this.breadcrumb = this.addText(`modal-breadcrumb:${spec.id}`);
|
|
1141
|
-
|
|
1723
|
+
const header = new BoxRenderable4(renderer2, { id: `modal-heading:${spec.id}`, width: "100%", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
1724
|
+
this.heading = new TextRenderable3(renderer2, { id: `modal-title:${spec.id}`, content: "", width: 0, flexGrow: 1, flexShrink: 1, wrapMode: "word", fg: colors.foreground });
|
|
1725
|
+
this.headerActions = new BoxRenderable4(renderer2, { id: `modal-header-actions:${spec.id}`, flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
1726
|
+
header.add(this.heading);
|
|
1727
|
+
header.add(this.headerActions);
|
|
1728
|
+
this.panel.add(header);
|
|
1142
1729
|
this.description = this.addText(`modal-description:${spec.id}`);
|
|
1143
1730
|
if (spec.kind === "select") this.buildSelect();
|
|
1144
1731
|
else if (spec.kind === "input") this.buildInput();
|
|
@@ -1156,7 +1743,7 @@ var NativeModalView = class {
|
|
|
1156
1743
|
this.blocks = new NativeBlockList(this.modalContext(), this.document);
|
|
1157
1744
|
this.panel.add(this.document);
|
|
1158
1745
|
} else {
|
|
1159
|
-
this.progress = new
|
|
1746
|
+
this.progress = new TextRenderable3(renderer2, {
|
|
1160
1747
|
id: `modal-progress:${spec.id}`,
|
|
1161
1748
|
width: "100%",
|
|
1162
1749
|
height: 1,
|
|
@@ -1168,13 +1755,13 @@ var NativeModalView = class {
|
|
|
1168
1755
|
selectable: false
|
|
1169
1756
|
});
|
|
1170
1757
|
this.panel.add(this.progress);
|
|
1171
|
-
const progressBlocks = new
|
|
1758
|
+
const progressBlocks = new BoxRenderable4(renderer2, { id: `modal-progress-blocks:${spec.id}`, flexDirection: "column", width: "100%" });
|
|
1172
1759
|
this.panel.add(progressBlocks);
|
|
1173
1760
|
this.blocks = new NativeBlockList(this.modalContext(), progressBlocks);
|
|
1174
1761
|
}
|
|
1175
1762
|
this.error = this.addText(`modal-error:${spec.id}`);
|
|
1176
1763
|
this.hints = this.addText(`modal-hints:${spec.id}`);
|
|
1177
|
-
this.actions = new
|
|
1764
|
+
this.actions = new BoxRenderable4(renderer2, { id: `modal-actions:${spec.id}`, flexDirection: "row", gap: 1, width: "100%", marginTop: 0 });
|
|
1178
1765
|
this.panel.add(this.actions);
|
|
1179
1766
|
this.update(spec);
|
|
1180
1767
|
}
|
|
@@ -1190,6 +1777,7 @@ var NativeModalView = class {
|
|
|
1190
1777
|
error;
|
|
1191
1778
|
hints;
|
|
1192
1779
|
actions;
|
|
1780
|
+
headerActions;
|
|
1193
1781
|
filterInput;
|
|
1194
1782
|
editor;
|
|
1195
1783
|
secretMask;
|
|
@@ -1201,11 +1789,39 @@ var NativeModalView = class {
|
|
|
1201
1789
|
filter = "";
|
|
1202
1790
|
changing = false;
|
|
1203
1791
|
actionsSignature = "";
|
|
1792
|
+
headerActionsSignature = "";
|
|
1204
1793
|
addText(id) {
|
|
1205
|
-
const text = new
|
|
1794
|
+
const text = new TextRenderable3(this.context.renderer, { id, content: "", width: "100%", wrapMode: "word", flexShrink: 0, fg: this.context.colors.foreground, selectable: true });
|
|
1206
1795
|
this.panel.add(text);
|
|
1207
1796
|
return text;
|
|
1208
1797
|
}
|
|
1798
|
+
replaceActions(container, actions, prefix = "") {
|
|
1799
|
+
for (const child of [...container.getChildren()]) child.destroy();
|
|
1800
|
+
for (const action of actions) {
|
|
1801
|
+
const button = new TextRenderable3(this.context.renderer, {
|
|
1802
|
+
id: `modal-action:${this.spec.id}:${prefix}${action.id}`,
|
|
1803
|
+
content: plainText(action.label),
|
|
1804
|
+
fg: this.context.colors.foreground,
|
|
1805
|
+
bg: this.context.colors.background,
|
|
1806
|
+
attributes: action.disabled ? 2 : action.active ? 1 : 0,
|
|
1807
|
+
selectable: false,
|
|
1808
|
+
onMouseDown: (event) => {
|
|
1809
|
+
if (event.button !== 0 || action.disabled) return;
|
|
1810
|
+
this.emitAction(action.command ?? action.id, this.editor?.plainText);
|
|
1811
|
+
event.stopPropagation();
|
|
1812
|
+
},
|
|
1813
|
+
onKeyDown: (key) => {
|
|
1814
|
+
if (key.eventType === "release" || key.name !== "return" && key.sequence !== " " || action.disabled) return;
|
|
1815
|
+
this.emitAction(action.command ?? action.id, this.editor?.plainText);
|
|
1816
|
+
key.preventDefault();
|
|
1817
|
+
}
|
|
1818
|
+
});
|
|
1819
|
+
button.focusable = !action.disabled;
|
|
1820
|
+
nativeControlFocus(button, action.disabled ? 2 : action.active ? 1 : 0);
|
|
1821
|
+
container.add(button);
|
|
1822
|
+
}
|
|
1823
|
+
container.visible = actions.length > 0;
|
|
1824
|
+
}
|
|
1209
1825
|
buildSelect() {
|
|
1210
1826
|
const { renderer: renderer2, colors } = this.context;
|
|
1211
1827
|
this.filterInput = new InputRenderable(renderer2, {
|
|
@@ -1308,34 +1924,15 @@ var NativeModalView = class {
|
|
|
1308
1924
|
this.refreshOptions(patch.selectedIndex);
|
|
1309
1925
|
this.blocks?.replace(spec.blocks ?? []);
|
|
1310
1926
|
if (this.progress) this.progress.content = nativeProgressText(spec.progress, true);
|
|
1927
|
+
const headerActionsSignature = JSON.stringify(spec.headerActions ?? []);
|
|
1928
|
+
if (headerActionsSignature !== this.headerActionsSignature) {
|
|
1929
|
+
this.headerActionsSignature = headerActionsSignature;
|
|
1930
|
+
this.replaceActions(this.headerActions, spec.headerActions ?? [], "header:");
|
|
1931
|
+
}
|
|
1311
1932
|
const actionsSignature = JSON.stringify(spec.actions ?? []);
|
|
1312
1933
|
if (actionsSignature !== this.actionsSignature) {
|
|
1313
1934
|
this.actionsSignature = actionsSignature;
|
|
1314
|
-
|
|
1315
|
-
for (const action of spec.actions ?? []) {
|
|
1316
|
-
const button = new TextRenderable2(this.context.renderer, {
|
|
1317
|
-
id: `modal-action:${spec.id}:${action.id}`,
|
|
1318
|
-
content: plainText(action.label),
|
|
1319
|
-
fg: this.context.colors.foreground,
|
|
1320
|
-
bg: this.context.colors.background,
|
|
1321
|
-
attributes: action.disabled ? 2 : action.active ? 1 : 0,
|
|
1322
|
-
selectable: false,
|
|
1323
|
-
onMouseDown: (event) => {
|
|
1324
|
-
if (event.button !== 0 || action.disabled) return;
|
|
1325
|
-
this.emitAction(action.command ?? action.id, this.editor?.plainText);
|
|
1326
|
-
event.stopPropagation();
|
|
1327
|
-
},
|
|
1328
|
-
onKeyDown: (key) => {
|
|
1329
|
-
if (key.eventType === "release" || key.name !== "return" && key.sequence !== " " || action.disabled) return;
|
|
1330
|
-
this.emitAction(action.command ?? action.id, this.editor?.plainText);
|
|
1331
|
-
key.preventDefault();
|
|
1332
|
-
}
|
|
1333
|
-
});
|
|
1334
|
-
button.focusable = !action.disabled;
|
|
1335
|
-
nativeControlFocus(button, action.disabled ? 2 : action.active ? 1 : 0);
|
|
1336
|
-
this.actions.add(button);
|
|
1337
|
-
}
|
|
1338
|
-
this.actions.visible = (spec.actions?.length ?? 0) > 0;
|
|
1935
|
+
this.replaceActions(this.actions, spec.actions ?? []);
|
|
1339
1936
|
}
|
|
1340
1937
|
} finally {
|
|
1341
1938
|
this.changing = false;
|
|
@@ -1390,7 +1987,7 @@ var NativeModalView = class {
|
|
|
1390
1987
|
this.close(this.spec.id, { confirmed: true, key: current?.item.key ?? null, index: current?.index ?? -1, ...value === void 0 ? {} : { value } });
|
|
1391
1988
|
}
|
|
1392
1989
|
cancel(action = "cancel") {
|
|
1393
|
-
if (this.frame.closing) return;
|
|
1990
|
+
if (this.frame.closing || this.spec.nonDismissible) return;
|
|
1394
1991
|
if (this.spec.deferSelection) {
|
|
1395
1992
|
this.emitAction(action);
|
|
1396
1993
|
return;
|
|
@@ -1559,7 +2156,7 @@ var NativeModalView = class {
|
|
|
1559
2156
|
editor.placeholderColor = colors.foreground;
|
|
1560
2157
|
}
|
|
1561
2158
|
if (this.secretMask) this.secretMask.fg = colors.foreground;
|
|
1562
|
-
for (const action of this.actions.getChildren()) if (action instanceof
|
|
2159
|
+
for (const action of [...this.actions.getChildren(), ...this.headerActions.getChildren()]) if (action instanceof TextRenderable3) {
|
|
1563
2160
|
action.fg = colors.foreground;
|
|
1564
2161
|
action.bg = colors.background;
|
|
1565
2162
|
}
|
|
@@ -1643,12 +2240,12 @@ var NativeModalStack = class {
|
|
|
1643
2240
|
|
|
1644
2241
|
// packages/cli/src/tui/native/components/instruments.ts
|
|
1645
2242
|
import {
|
|
1646
|
-
BoxRenderable as
|
|
2243
|
+
BoxRenderable as BoxRenderable5,
|
|
1647
2244
|
RGBA as RGBA2,
|
|
1648
2245
|
RenderableEvents as RenderableEvents3,
|
|
1649
2246
|
ScrollBoxRenderable as ScrollBoxRenderable3,
|
|
1650
2247
|
TextAttributes as TextAttributes5,
|
|
1651
|
-
TextRenderable as
|
|
2248
|
+
TextRenderable as TextRenderable4
|
|
1652
2249
|
} from "@opentui/core";
|
|
1653
2250
|
|
|
1654
2251
|
// packages/cli/src/tui/native/components/device-history.ts
|
|
@@ -1848,7 +2445,7 @@ function instrumentStatus(value) {
|
|
|
1848
2445
|
// packages/cli/src/tui/native/components/instruments.ts
|
|
1849
2446
|
var foreground = RGBA2.defaultForeground();
|
|
1850
2447
|
var background = RGBA2.defaultBackground();
|
|
1851
|
-
var SectionBanner = class extends
|
|
2448
|
+
var SectionBanner = class extends TextRenderable4 {
|
|
1852
2449
|
constructor(renderer2, title, id, activate) {
|
|
1853
2450
|
super(renderer2, {
|
|
1854
2451
|
id,
|
|
@@ -1903,7 +2500,7 @@ var SectionBanner = class extends TextRenderable3 {
|
|
|
1903
2500
|
if (this.plainText !== next) this.content = next;
|
|
1904
2501
|
}
|
|
1905
2502
|
};
|
|
1906
|
-
var TelemetryRow = class extends
|
|
2503
|
+
var TelemetryRow = class extends TextRenderable4 {
|
|
1907
2504
|
constructor(renderer2, label, id, reserved = 12) {
|
|
1908
2505
|
super(renderer2, {
|
|
1909
2506
|
id,
|
|
@@ -1949,7 +2546,7 @@ var SignalMeter = class extends TelemetryRow {
|
|
|
1949
2546
|
this.update(formatSignalMeter(value, maximum));
|
|
1950
2547
|
}
|
|
1951
2548
|
};
|
|
1952
|
-
var InstrumentDivider = class extends
|
|
2549
|
+
var InstrumentDivider = class extends TextRenderable4 {
|
|
1953
2550
|
constructor(renderer2, actions) {
|
|
1954
2551
|
super(renderer2, {
|
|
1955
2552
|
id: "omnius-instrument-divider",
|
|
@@ -2046,17 +2643,17 @@ var InstrumentDivider = class extends TextRenderable3 {
|
|
|
2046
2643
|
this.attributes = this.focused ? TextAttributes5.INVERSE : TextAttributes5.DIM;
|
|
2047
2644
|
}
|
|
2048
2645
|
};
|
|
2049
|
-
var DeviceMonitor = class extends
|
|
2646
|
+
var DeviceMonitor = class extends BoxRenderable5 {
|
|
2050
2647
|
constructor(renderer2, action) {
|
|
2051
2648
|
super(renderer2, { id: "omnius-devices", width: "100%", height: 5, minHeight: 5, maxHeight: "60%", flexShrink: 1, flexDirection: "column", visible: false });
|
|
2052
2649
|
this.action = action;
|
|
2053
2650
|
this.heading = new SectionBanner(renderer2, "DEVICES", "omnius-devices:heading", () => this.toggle());
|
|
2054
2651
|
this.heading.update("DEVICES", false);
|
|
2055
2652
|
this.add(this.heading);
|
|
2056
|
-
this.summary = new
|
|
2653
|
+
this.summary = new TextRenderable4(renderer2, { id: "omnius-devices:summary", content: "--", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
2057
2654
|
this.add(this.summary);
|
|
2058
|
-
this.compactLoad = new
|
|
2059
|
-
this.compactMemory = new
|
|
2655
|
+
this.compactLoad = new TextRenderable4(renderer2, { id: "omnius-devices:load-history", content: "", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
2656
|
+
this.compactMemory = new TextRenderable4(renderer2, { id: "omnius-devices:memory-history", content: "", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
2060
2657
|
this.add(this.compactLoad);
|
|
2061
2658
|
this.add(this.compactMemory);
|
|
2062
2659
|
this.scroll = new ScrollBoxRenderable3(renderer2, {
|
|
@@ -2074,7 +2671,7 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2074
2671
|
contentOptions: { flexDirection: "column" }
|
|
2075
2672
|
});
|
|
2076
2673
|
this.add(this.scroll);
|
|
2077
|
-
this.notes = new
|
|
2674
|
+
this.notes = new TextRenderable4(renderer2, {
|
|
2078
2675
|
id: "omnius-devices:notes",
|
|
2079
2676
|
content: "",
|
|
2080
2677
|
width: "100%",
|
|
@@ -2086,7 +2683,7 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2086
2683
|
truncate: true
|
|
2087
2684
|
});
|
|
2088
2685
|
this.scroll.add(this.notes);
|
|
2089
|
-
const controls = new
|
|
2686
|
+
const controls = new BoxRenderable5(renderer2, { id: "omnius-devices:controls", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2 });
|
|
2090
2687
|
this.add(controls);
|
|
2091
2688
|
this.policy = this.button(renderer2, "omnius-devices:policy", "GPU POLICY", () => {
|
|
2092
2689
|
if (this.canSelect()) this.action?.("/gpu");
|
|
@@ -2110,7 +2707,7 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2110
2707
|
historySource = "";
|
|
2111
2708
|
rows = /* @__PURE__ */ new Map();
|
|
2112
2709
|
button(renderer2, id, label, activate) {
|
|
2113
|
-
const button = new
|
|
2710
|
+
const button = new TextRenderable4(renderer2, {
|
|
2114
2711
|
id,
|
|
2115
2712
|
content: label,
|
|
2116
2713
|
height: 1,
|
|
@@ -2173,7 +2770,7 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2173
2770
|
for (const device of snapshot?.devices ?? []) {
|
|
2174
2771
|
let row = this.rows.get(device.uuid);
|
|
2175
2772
|
if (!row) {
|
|
2176
|
-
const root = new
|
|
2773
|
+
const root = new BoxRenderable5(this._ctx, {
|
|
2177
2774
|
id: `omnius-device:${device.uuid}`,
|
|
2178
2775
|
width: "100%",
|
|
2179
2776
|
flexDirection: "column",
|
|
@@ -2192,9 +2789,9 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2192
2789
|
title.on(RenderableEvents3.FOCUSED, () => this.scroll.scrollChildIntoView(root.id));
|
|
2193
2790
|
const load = new TelemetryRow(this._ctx, "LOAD", `${root.id}:load`, 16);
|
|
2194
2791
|
const memory = new TelemetryRow(this._ctx, "VRAM", `${root.id}:memory`, 16);
|
|
2195
|
-
const plot = (name) => new
|
|
2792
|
+
const plot = (name) => new TextRenderable4(this._ctx, { id: `${root.id}:${name}-history`, content: "", width: "100%", height: 3, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true, selectable: false });
|
|
2196
2793
|
const loadGraph = plot("load"), memoryGraph = plot("memory"), history = new DeviceHistory();
|
|
2197
|
-
const reason = new
|
|
2794
|
+
const reason = new TextRenderable4(this._ctx, {
|
|
2198
2795
|
id: `${root.id}:reason`,
|
|
2199
2796
|
content: "",
|
|
2200
2797
|
width: "100%",
|
|
@@ -2241,6 +2838,12 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2241
2838
|
this.fitHeight(this.availableRows + 2);
|
|
2242
2839
|
this.refresh();
|
|
2243
2840
|
}
|
|
2841
|
+
get isExpanded() {
|
|
2842
|
+
return this.expanded;
|
|
2843
|
+
}
|
|
2844
|
+
setExpanded(expanded) {
|
|
2845
|
+
if (this.expanded !== expanded) this.toggle();
|
|
2846
|
+
}
|
|
2244
2847
|
fitHeight(railRows) {
|
|
2245
2848
|
this.availableRows = Math.max(0, railRows - 2);
|
|
2246
2849
|
this.visible = Boolean(this.snapshot) && this.availableRows >= 3;
|
|
@@ -2299,7 +2902,7 @@ var DeviceMonitor = class extends BoxRenderable4 {
|
|
|
2299
2902
|
];
|
|
2300
2903
|
}
|
|
2301
2904
|
};
|
|
2302
|
-
var ChannelMap = class extends
|
|
2905
|
+
var ChannelMap = class extends BoxRenderable5 {
|
|
2303
2906
|
constructor(renderer2, id, inspect, reveal) {
|
|
2304
2907
|
super(renderer2, {
|
|
2305
2908
|
id,
|
|
@@ -2331,7 +2934,7 @@ var ChannelMap = class extends BoxRenderable4 {
|
|
|
2331
2934
|
if (!this.channels.has(agent.id))
|
|
2332
2935
|
this.channels.set(agent.id, this.channels.size + 1);
|
|
2333
2936
|
if (!this.rows.has(agent.id)) {
|
|
2334
|
-
const row = new
|
|
2937
|
+
const row = new TextRenderable4(this._ctx, {
|
|
2335
2938
|
id: `${this.id}:channel:${agent.id}`,
|
|
2336
2939
|
content: "",
|
|
2337
2940
|
width: "100%",
|
|
@@ -2397,7 +3000,7 @@ var ChannelMap = class extends BoxRenderable4 {
|
|
|
2397
3000
|
}
|
|
2398
3001
|
}
|
|
2399
3002
|
};
|
|
2400
|
-
var InstrumentRail = class extends
|
|
3003
|
+
var InstrumentRail = class extends BoxRenderable5 {
|
|
2401
3004
|
scroll;
|
|
2402
3005
|
inferenceHeader;
|
|
2403
3006
|
sessionHeader;
|
|
@@ -2451,7 +3054,7 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2451
3054
|
() => this.reveal(this.inferenceHeader)
|
|
2452
3055
|
);
|
|
2453
3056
|
this.scroll.add(this.inferenceHeader);
|
|
2454
|
-
this.inference = new
|
|
3057
|
+
this.inference = new BoxRenderable5(renderer2, {
|
|
2455
3058
|
id: `${id}:inference-body`,
|
|
2456
3059
|
width: "100%",
|
|
2457
3060
|
flexDirection: "column",
|
|
@@ -2466,7 +3069,7 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2466
3069
|
};
|
|
2467
3070
|
addRow(this.inference, "route", "ROUTE");
|
|
2468
3071
|
addRow(this.inference, "backend", "BACKEND");
|
|
2469
|
-
this.model = new
|
|
3072
|
+
this.model = new TextRenderable4(renderer2, {
|
|
2470
3073
|
id: `${id}:model`,
|
|
2471
3074
|
content: "MODEL --",
|
|
2472
3075
|
width: "100%",
|
|
@@ -2495,7 +3098,7 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2495
3098
|
});
|
|
2496
3099
|
this.contextHeader.on(RenderableEvents3.FOCUSED, () => this.reveal(this.contextHeader));
|
|
2497
3100
|
this.inference.add(this.contextHeader);
|
|
2498
|
-
this.contextDetails = new
|
|
3101
|
+
this.contextDetails = new BoxRenderable5(renderer2, { id: `${id}:context-detail-body`, width: "100%", flexDirection: "column", flexShrink: 0, visible: false });
|
|
2499
3102
|
this.inference.add(this.contextDetails);
|
|
2500
3103
|
this.contextHeader.update("CONTEXT DETAILS", false);
|
|
2501
3104
|
addRow(this.contextDetails, "messages", "MESSAGES");
|
|
@@ -2514,7 +3117,7 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2514
3117
|
() => this.reveal(this.sessionHeader)
|
|
2515
3118
|
);
|
|
2516
3119
|
this.scroll.add(this.sessionHeader);
|
|
2517
|
-
this.session = new
|
|
3120
|
+
this.session = new BoxRenderable5(renderer2, {
|
|
2518
3121
|
id: `${id}:session-body`,
|
|
2519
3122
|
width: "100%",
|
|
2520
3123
|
flexDirection: "column",
|
|
@@ -2597,7 +3200,7 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2597
3200
|
applyTheme(colors) {
|
|
2598
3201
|
this.backgroundColor = colors.background;
|
|
2599
3202
|
const visit = (node) => {
|
|
2600
|
-
if (node instanceof
|
|
3203
|
+
if (node instanceof TextRenderable4) {
|
|
2601
3204
|
node.fg = colors.foreground;
|
|
2602
3205
|
node.bg = colors.background;
|
|
2603
3206
|
}
|
|
@@ -2616,6 +3219,25 @@ var InstrumentRail = class extends BoxRenderable4 {
|
|
|
2616
3219
|
body.visible
|
|
2617
3220
|
);
|
|
2618
3221
|
}
|
|
3222
|
+
capturePresentation() {
|
|
3223
|
+
return {
|
|
3224
|
+
inference: this.inference.visible,
|
|
3225
|
+
session: this.session.visible,
|
|
3226
|
+
context: this.contextHeader.expanded,
|
|
3227
|
+
devices: this.devices.isExpanded,
|
|
3228
|
+
scrollTop: this.scroll.scrollTop,
|
|
3229
|
+
deviceScrollTop: this.devices.scroll.scrollTop
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
restorePresentation(state) {
|
|
3233
|
+
if (this.inference.visible !== state.inference) this.toggleSection("inference");
|
|
3234
|
+
if (this.session.visible !== state.session) this.toggleSection("session");
|
|
3235
|
+
this.contextHeader.update("CONTEXT DETAILS", state.context);
|
|
3236
|
+
this.contextDetails.visible = this.contextHeader.visible && state.context;
|
|
3237
|
+
this.devices.setExpanded(state.devices);
|
|
3238
|
+
this.scroll.scrollTo(state.scrollTop);
|
|
3239
|
+
this.devices.scroll.scrollTo(state.deviceScrollTop);
|
|
3240
|
+
}
|
|
2619
3241
|
focusTargets() {
|
|
2620
3242
|
if (!this.visible) return [];
|
|
2621
3243
|
return [
|
|
@@ -3440,6 +4062,7 @@ var ALIASES = {
|
|
|
3440
4062
|
update: ["upgrade"],
|
|
3441
4063
|
indicator: ["tray"],
|
|
3442
4064
|
listen: ["mic"],
|
|
4065
|
+
sound: ["audio"],
|
|
3443
4066
|
pointcloud: ["points", "pcl", "point"],
|
|
3444
4067
|
neovim: ["nvim"],
|
|
3445
4068
|
apikey: ["key"],
|
|
@@ -4074,7 +4697,7 @@ var VimComposer = class {
|
|
|
4074
4697
|
};
|
|
4075
4698
|
|
|
4076
4699
|
// packages/cli/src/tui/native/components/selection-menu.ts
|
|
4077
|
-
import { BoxRenderable as
|
|
4700
|
+
import { BoxRenderable as BoxRenderable6, CliRenderEvents as CliRenderEvents3, TextAttributes as TextAttributes6, TextRenderable as TextRenderable5 } from "@opentui/core";
|
|
4078
4701
|
var NativeSelectionMenu = class {
|
|
4079
4702
|
constructor(renderer2, colors, copy, restoreFocus) {
|
|
4080
4703
|
this.renderer = renderer2;
|
|
@@ -4102,7 +4725,7 @@ var NativeSelectionMenu = class {
|
|
|
4102
4725
|
this.selectedText = text;
|
|
4103
4726
|
this.anchor = { x, y };
|
|
4104
4727
|
this.previousFocus = this.renderer.currentFocusedRenderable;
|
|
4105
|
-
this.overlay = new
|
|
4728
|
+
this.overlay = new BoxRenderable6(this.renderer, {
|
|
4106
4729
|
id: "omnius-selection-menu",
|
|
4107
4730
|
position: "absolute",
|
|
4108
4731
|
left: 0,
|
|
@@ -4118,7 +4741,7 @@ var NativeSelectionMenu = class {
|
|
|
4118
4741
|
event.stopPropagation();
|
|
4119
4742
|
}
|
|
4120
4743
|
});
|
|
4121
|
-
this.panel = new
|
|
4744
|
+
this.panel = new BoxRenderable6(this.renderer, {
|
|
4122
4745
|
id: "omnius-selection-menu-panel",
|
|
4123
4746
|
position: "absolute",
|
|
4124
4747
|
width: 14,
|
|
@@ -4132,7 +4755,7 @@ var NativeSelectionMenu = class {
|
|
|
4132
4755
|
event.stopPropagation();
|
|
4133
4756
|
}
|
|
4134
4757
|
});
|
|
4135
|
-
const action = new
|
|
4758
|
+
const action = new TextRenderable5(this.renderer, {
|
|
4136
4759
|
id: "omnius-selection-copy",
|
|
4137
4760
|
content: "COPY",
|
|
4138
4761
|
height: 1,
|
|
@@ -4181,7 +4804,7 @@ var NativeSelectionMenu = class {
|
|
|
4181
4804
|
if (!this.panel) return;
|
|
4182
4805
|
this.panel.backgroundColor = colors.background;
|
|
4183
4806
|
this.frame?.setColors(colors);
|
|
4184
|
-
for (const child of this.panel.getChildren()) if (child instanceof
|
|
4807
|
+
for (const child of this.panel.getChildren()) if (child instanceof TextRenderable5) {
|
|
4185
4808
|
child.fg = colors.foreground;
|
|
4186
4809
|
child.bg = colors.background;
|
|
4187
4810
|
}
|
|
@@ -4207,8 +4830,8 @@ var NativeSelectionMenu = class {
|
|
|
4207
4830
|
};
|
|
4208
4831
|
|
|
4209
4832
|
// packages/cli/src/tui/native/components/tab-strip.ts
|
|
4210
|
-
import { BoxRenderable as
|
|
4211
|
-
var NativeTabStrip = class extends
|
|
4833
|
+
import { BoxRenderable as BoxRenderable7, CliRenderEvents as CliRenderEvents4, ScrollBoxRenderable as ScrollBoxRenderable4, SliderRenderable, TextAttributes as TextAttributes7, TextRenderable as TextRenderable6 } from "@opentui/core";
|
|
4834
|
+
var NativeTabStrip = class extends BoxRenderable7 {
|
|
4212
4835
|
constructor(renderer2, options) {
|
|
4213
4836
|
super(renderer2, {
|
|
4214
4837
|
id: options.id,
|
|
@@ -4287,7 +4910,7 @@ var NativeTabStrip = class extends BoxRenderable6 {
|
|
|
4287
4910
|
for (const [index, action] of items.entries()) {
|
|
4288
4911
|
let entry = this.buttons.get(action.id);
|
|
4289
4912
|
if (!entry) {
|
|
4290
|
-
const button = new
|
|
4913
|
+
const button = new TextRenderable6(this.renderer, {
|
|
4291
4914
|
id: `${this.options.prefix}:${action.id}`,
|
|
4292
4915
|
content: "",
|
|
4293
4916
|
height: 1,
|
|
@@ -4374,6 +4997,10 @@ var NativeTabStrip = class extends BoxRenderable6 {
|
|
|
4374
4997
|
styleNativeScrollbars(this.scroll, colors);
|
|
4375
4998
|
styleNativeSlider(this.rail, colors);
|
|
4376
4999
|
}
|
|
5000
|
+
restoreOffset(offset2) {
|
|
5001
|
+
this.reveal = void 0;
|
|
5002
|
+
this.scroll.scrollLeft = offset2;
|
|
5003
|
+
}
|
|
4377
5004
|
destroySelf() {
|
|
4378
5005
|
this.renderer.off(CliRenderEvents4.FRAME, this.syncScroll);
|
|
4379
5006
|
super.destroySelf();
|
|
@@ -4387,13 +5014,13 @@ var NativeFrontend = class {
|
|
|
4387
5014
|
this.renderer = renderer2;
|
|
4388
5015
|
this.emit = emit;
|
|
4389
5016
|
const colors = palette(initialTheme);
|
|
4390
|
-
this.context = { renderer: renderer2, colors, syntax: SyntaxStyle2.fromStyles({}, renderer2.nativeScene), emit, terminals: /* @__PURE__ */ new Map() };
|
|
5017
|
+
this.context = { renderer: renderer2, colors, syntax: SyntaxStyle2.fromStyles({}, renderer2.nativeScene), emit, terminals: /* @__PURE__ */ new Map(), mediaViews: /* @__PURE__ */ new Set() };
|
|
4391
5018
|
this.disposeSelectionContrast = installDefaultSelectionContrast(renderer2);
|
|
4392
5019
|
this.clipboard = options.clipboard ?? createClipboard({ host: createHostClipboard({ timeoutMs: 1500 }), terminal: createRendererClipboardAdapter(renderer2) });
|
|
4393
5020
|
this.selectionMenu = new NativeSelectionMenu(renderer2, colors, (text) => {
|
|
4394
5021
|
void this.copy(text);
|
|
4395
5022
|
}, () => this.restoreFocus());
|
|
4396
|
-
this.root = new
|
|
5023
|
+
this.root = new BoxRenderable8(renderer2, {
|
|
4397
5024
|
id: "omnius-native",
|
|
4398
5025
|
width: "100%",
|
|
4399
5026
|
height: "100%",
|
|
@@ -4401,7 +5028,7 @@ var NativeFrontend = class {
|
|
|
4401
5028
|
backgroundColor: colors.background
|
|
4402
5029
|
});
|
|
4403
5030
|
renderer2.root.add(this.root);
|
|
4404
|
-
this.header = new
|
|
5031
|
+
this.header = new BoxRenderable8(renderer2, {
|
|
4405
5032
|
id: "omnius-header",
|
|
4406
5033
|
width: "100%",
|
|
4407
5034
|
minWidth: 0,
|
|
@@ -4425,9 +5052,9 @@ var NativeFrontend = class {
|
|
|
4425
5052
|
TextAttributes8.DIM
|
|
4426
5053
|
);
|
|
4427
5054
|
};
|
|
4428
|
-
const headerRow = new
|
|
5055
|
+
const headerRow = new BoxRenderable8(renderer2, { id: "omnius-header-row", width: "100%", minWidth: 0, minHeight: 1, flexDirection: "row", gap: 1 });
|
|
4429
5056
|
this.header.add(headerRow);
|
|
4430
|
-
this.identity = new
|
|
5057
|
+
this.identity = new TextRenderable7(renderer2, {
|
|
4431
5058
|
id: "omnius-identity",
|
|
4432
5059
|
content: "Omnius",
|
|
4433
5060
|
fg: colors.foreground,
|
|
@@ -4465,9 +5092,9 @@ var NativeFrontend = class {
|
|
|
4465
5092
|
verticalScrollbarOptions: { visible: false }
|
|
4466
5093
|
});
|
|
4467
5094
|
headerRow.add(this.headerActions);
|
|
4468
|
-
this.headerPanel = new
|
|
5095
|
+
this.headerPanel = new TextRenderable7(renderer2, { id: "omnius-header-panel", content: "", width: "100%", wrapMode: "word", visible: false });
|
|
4469
5096
|
this.header.add(this.headerPanel);
|
|
4470
|
-
this.detailButton = new
|
|
5097
|
+
this.detailButton = new TextRenderable7(renderer2, {
|
|
4471
5098
|
id: "omnius-details-toggle",
|
|
4472
5099
|
content: "+ DETAILS",
|
|
4473
5100
|
height: 1,
|
|
@@ -4500,7 +5127,7 @@ var NativeFrontend = class {
|
|
|
4500
5127
|
control.attributes = attributes;
|
|
4501
5128
|
});
|
|
4502
5129
|
}
|
|
4503
|
-
this.sessionRow = new
|
|
5130
|
+
this.sessionRow = new BoxRenderable8(renderer2, {
|
|
4504
5131
|
id: "omnius-sessions-row",
|
|
4505
5132
|
width: "100%",
|
|
4506
5133
|
height: 1,
|
|
@@ -4518,7 +5145,7 @@ var NativeFrontend = class {
|
|
|
4518
5145
|
activate: (id) => this.emitAction("session", id)
|
|
4519
5146
|
});
|
|
4520
5147
|
this.sessionRow.add(this.sessions);
|
|
4521
|
-
this.newSession = new
|
|
5148
|
+
this.newSession = new TextRenderable7(renderer2, {
|
|
4522
5149
|
id: "omnius-session-new",
|
|
4523
5150
|
content: "+ NEW",
|
|
4524
5151
|
width: 5,
|
|
@@ -4547,13 +5174,15 @@ var NativeFrontend = class {
|
|
|
4547
5174
|
this.newSession.on("focused", styleNew);
|
|
4548
5175
|
this.newSession.on("blurred", styleNew);
|
|
4549
5176
|
this.sessionRow.add(this.newSession);
|
|
4550
|
-
this.routeWarning = new
|
|
5177
|
+
this.routeWarning = new TextRenderable7(renderer2, { id: "omnius-route-warning", content: "", width: "100%", wrapMode: "word", fg: colors.warning, attributes: TextAttributes8.BOLD | TextAttributes8.UNDERLINE, visible: false, flexShrink: 0 });
|
|
4551
5178
|
this.root.add(this.routeWarning);
|
|
4552
|
-
this.taskPane = new
|
|
5179
|
+
this.taskPane = new BoxRenderable8(renderer2, { id: "omnius-tasks", width: "100%", flexDirection: "column", maxHeight: 6, flexShrink: 0, overflow: "hidden", visible: false });
|
|
4553
5180
|
this.tasks = new NativeBlockList(this.context, this.taskPane);
|
|
4554
5181
|
this.root.add(this.taskPane);
|
|
4555
|
-
this.body = new
|
|
5182
|
+
this.body = new BoxRenderable8(renderer2, { id: "omnius-body", width: "100%", flexDirection: "row", flexGrow: 1, minHeight: 1 });
|
|
4556
5183
|
this.root.add(this.body);
|
|
5184
|
+
this.transcriptPane = new BoxRenderable8(renderer2, { id: "omnius-transcript-pane", flexDirection: "column", flexGrow: 1, flexShrink: 1, minWidth: 0, minHeight: 1 });
|
|
5185
|
+
this.body.add(this.transcriptPane);
|
|
4557
5186
|
this.scroll = new ScrollBoxRenderable5(renderer2, {
|
|
4558
5187
|
id: "omnius-conversation",
|
|
4559
5188
|
flexGrow: 1,
|
|
@@ -4609,7 +5238,7 @@ var NativeFrontend = class {
|
|
|
4609
5238
|
}
|
|
4610
5239
|
} }
|
|
4611
5240
|
});
|
|
4612
|
-
this.
|
|
5241
|
+
this.transcriptPane.add(this.scroll);
|
|
4613
5242
|
this.content = new NativeBlockList(this.context, this.scroll);
|
|
4614
5243
|
this.instrumentDivider = new InstrumentDivider(renderer2, {
|
|
4615
5244
|
resize: (column) => this.resizeInstruments(column),
|
|
@@ -4627,7 +5256,7 @@ var NativeFrontend = class {
|
|
|
4627
5256
|
this.root.onMouseUp = (event) => this.instrumentDivider.handleRelease(event);
|
|
4628
5257
|
this.instruments = new InstrumentRail(renderer2, { colors, onInspectAgent: (id) => this.emitAction("view", id), onAction: (command2) => this.emitAction(command2) });
|
|
4629
5258
|
this.body.add(this.instruments);
|
|
4630
|
-
this.embeddedPane = new
|
|
5259
|
+
this.embeddedPane = new BoxRenderable8(renderer2, {
|
|
4631
5260
|
id: "omnius-editor-pane",
|
|
4632
5261
|
width: "50%",
|
|
4633
5262
|
flexShrink: 0,
|
|
@@ -4638,7 +5267,7 @@ var NativeFrontend = class {
|
|
|
4638
5267
|
visible: false
|
|
4639
5268
|
});
|
|
4640
5269
|
this.body.add(this.embeddedPane);
|
|
4641
|
-
this.liveButton = new
|
|
5270
|
+
this.liveButton = new TextRenderable7(renderer2, {
|
|
4642
5271
|
id: "omnius-live-button",
|
|
4643
5272
|
content: "↓ Live",
|
|
4644
5273
|
width: "100%",
|
|
@@ -4660,9 +5289,9 @@ var NativeFrontend = class {
|
|
|
4660
5289
|
}
|
|
4661
5290
|
});
|
|
4662
5291
|
this.liveButton.focusable = true;
|
|
4663
|
-
this.
|
|
4664
|
-
this.queue = new
|
|
4665
|
-
this.
|
|
5292
|
+
this.transcriptPane.add(this.liveButton);
|
|
5293
|
+
this.queue = new TextRenderable7(renderer2, { id: "omnius-steering-queue", content: "", width: "100%", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, visible: false, flexShrink: 0 });
|
|
5294
|
+
this.transcriptPane.add(this.queue);
|
|
4666
5295
|
this.suggestions = new NativeSelectRenderable(renderer2, {
|
|
4667
5296
|
id: "omnius-suggestions",
|
|
4668
5297
|
width: "100%",
|
|
@@ -4679,10 +5308,10 @@ var NativeFrontend = class {
|
|
|
4679
5308
|
});
|
|
4680
5309
|
this.suggestions.onActivate = () => this.acceptSuggestion();
|
|
4681
5310
|
this.suggestions.on("itemSelected", () => this.acceptSuggestion());
|
|
4682
|
-
this.
|
|
4683
|
-
this.status = new
|
|
4684
|
-
this.
|
|
4685
|
-
this.footer = new
|
|
5311
|
+
this.transcriptPane.add(this.suggestions);
|
|
5312
|
+
this.status = new BoxRenderable8(renderer2, { id: "omnius-live-status", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2, visible: false });
|
|
5313
|
+
this.transcriptPane.add(this.status);
|
|
5314
|
+
this.footer = new BoxRenderable8(renderer2, {
|
|
4686
5315
|
id: "omnius-input-box",
|
|
4687
5316
|
width: "100%",
|
|
4688
5317
|
flexShrink: 0,
|
|
@@ -4691,7 +5320,7 @@ var NativeFrontend = class {
|
|
|
4691
5320
|
flexDirection: "column"
|
|
4692
5321
|
});
|
|
4693
5322
|
this.root.add(this.footer);
|
|
4694
|
-
this.footerRule = new
|
|
5323
|
+
this.footerRule = new BoxRenderable8(renderer2, {
|
|
4695
5324
|
id: "omnius-input-rule",
|
|
4696
5325
|
width: "100%",
|
|
4697
5326
|
height: 1,
|
|
@@ -4719,9 +5348,9 @@ var NativeFrontend = class {
|
|
|
4719
5348
|
sidebarColumn: this.instrumentDivider.visible ? this.instrumentDivider.x - this.footerRule.x : void 0
|
|
4720
5349
|
}), this.footerRule.x, this.footerRule.y, this.context.colors.foreground, this.context.colors.background, TextAttributes8.DIM);
|
|
4721
5350
|
};
|
|
4722
|
-
const inputRow = new
|
|
5351
|
+
const inputRow = new BoxRenderable8(renderer2, { id: "omnius-input-row", width: "100%", flexDirection: "row", gap: 1 });
|
|
4723
5352
|
this.footer.add(inputRow);
|
|
4724
|
-
this.prompt = new
|
|
5353
|
+
this.prompt = new TextRenderable7(renderer2, { id: "omnius-prompt", content: "❯", fg: colors.accent, wrapMode: "none", selectable: false, flexShrink: 0 });
|
|
4725
5354
|
inputRow.add(this.prompt);
|
|
4726
5355
|
this.editor = new TextareaRenderable2(renderer2, {
|
|
4727
5356
|
id: "omnius-input",
|
|
@@ -4741,7 +5370,7 @@ var NativeFrontend = class {
|
|
|
4741
5370
|
onCursorChange: () => this.editorChanged(),
|
|
4742
5371
|
onSubmit: () => this.submit()
|
|
4743
5372
|
});
|
|
4744
|
-
this.vimMode = new
|
|
5373
|
+
this.vimMode = new TextRenderable7(renderer2, {
|
|
4745
5374
|
id: "omnius-vim-mode",
|
|
4746
5375
|
content: "INSERT",
|
|
4747
5376
|
height: 1,
|
|
@@ -4762,17 +5391,17 @@ var NativeFrontend = class {
|
|
|
4762
5391
|
this.renderer.requestRender();
|
|
4763
5392
|
});
|
|
4764
5393
|
inputRow.add(this.editor);
|
|
4765
|
-
this.enhance = new
|
|
5394
|
+
this.enhance = new BoxRenderable8(renderer2, { id: "omnius-enhance", flexDirection: "row", gap: 1, flexShrink: 0, visible: false });
|
|
4766
5395
|
inputRow.add(this.enhance);
|
|
4767
|
-
this.activity = new
|
|
5396
|
+
this.activity = new TextRenderable7(renderer2, { id: "omnius-activity", content: "", flexGrow: 1, minWidth: 0, height: 1, wrapMode: "none", truncate: true, visible: false, fg: colors.accent });
|
|
4768
5397
|
this.status.add(this.activity);
|
|
4769
|
-
this.media = new
|
|
4770
|
-
this.mediaText = new
|
|
5398
|
+
this.media = new BoxRenderable8(renderer2, { id: "omnius-media", height: 1, minWidth: 0, flexShrink: 1, flexDirection: "row", gap: 1, visible: false });
|
|
5399
|
+
this.mediaText = new TextRenderable7(renderer2, { id: "omnius-media-text", content: "", flexGrow: 1, minWidth: 0, wrapMode: "none", truncate: true, fg: colors.accent });
|
|
4771
5400
|
this.media.add(this.mediaText);
|
|
4772
|
-
this.micTrack = new
|
|
5401
|
+
this.micTrack = new TextRenderable7(renderer2, { id: "omnius-mic-meter", width: 12, height: 1, flexShrink: 0, fg: colors.foreground, visible: false });
|
|
4773
5402
|
this.media.add(this.micTrack);
|
|
4774
5403
|
this.status.add(this.media);
|
|
4775
|
-
this.copyFeedback = new
|
|
5404
|
+
this.copyFeedback = new TextRenderable7(renderer2, {
|
|
4776
5405
|
id: "omnius-copy-feedback",
|
|
4777
5406
|
content: "",
|
|
4778
5407
|
height: 1,
|
|
@@ -4783,14 +5412,14 @@ var NativeFrontend = class {
|
|
|
4783
5412
|
visible: false
|
|
4784
5413
|
});
|
|
4785
5414
|
this.status.add(this.copyFeedback);
|
|
4786
|
-
this.metricsRow = new
|
|
4787
|
-
this.keyHints = new
|
|
5415
|
+
this.metricsRow = new BoxRenderable8(renderer2, { id: "omnius-metrics-row", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 1 });
|
|
5416
|
+
this.keyHints = new TextRenderable7(renderer2, { id: "omnius-key-hints", content: "F1 HELP TAB FOCUS", height: 1, flexShrink: 0, attributes: TextAttributes8.DIM, fg: colors.foreground, selectable: false });
|
|
4788
5417
|
this.metricsRow.add(this.keyHints);
|
|
4789
|
-
this.metricsStartActions = new
|
|
5418
|
+
this.metricsStartActions = new BoxRenderable8(renderer2, { id: "omnius-metrics-start-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
4790
5419
|
this.metricsRow.add(this.metricsStartActions);
|
|
4791
|
-
this.metrics = new
|
|
5420
|
+
this.metrics = new TextRenderable7(renderer2, { id: "omnius-metrics", content: "", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, flexShrink: 1, flexGrow: 1, minWidth: 0 });
|
|
4792
5421
|
this.metricsRow.add(this.metrics);
|
|
4793
|
-
this.metricsEndActions = new
|
|
5422
|
+
this.metricsEndActions = new BoxRenderable8(renderer2, { id: "omnius-metrics-end-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
4794
5423
|
this.metricsRow.add(this.metricsEndActions);
|
|
4795
5424
|
this.root.add(this.metricsRow);
|
|
4796
5425
|
this.modals = new NativeModalStack(this.context, () => this.restoreFocus());
|
|
@@ -4823,6 +5452,7 @@ var NativeFrontend = class {
|
|
|
4823
5452
|
taskPane;
|
|
4824
5453
|
tasks;
|
|
4825
5454
|
body;
|
|
5455
|
+
transcriptPane;
|
|
4826
5456
|
instruments;
|
|
4827
5457
|
instrumentDivider;
|
|
4828
5458
|
detailButton;
|
|
@@ -4874,6 +5504,9 @@ var NativeFrontend = class {
|
|
|
4874
5504
|
destroyed = false;
|
|
4875
5505
|
pendingScrollRestore;
|
|
4876
5506
|
viewScroll = /* @__PURE__ */ new Map();
|
|
5507
|
+
viewDisclosures = /* @__PURE__ */ new Map();
|
|
5508
|
+
pendingDisclosures;
|
|
5509
|
+
pendingInterface;
|
|
4877
5510
|
embeddedId;
|
|
4878
5511
|
selectionArmed = false;
|
|
4879
5512
|
update(state, patch) {
|
|
@@ -4883,7 +5516,9 @@ var NativeFrontend = class {
|
|
|
4883
5516
|
const viewChanged = previousView !== void 0 && previousView !== currentView;
|
|
4884
5517
|
if (viewChanged) {
|
|
4885
5518
|
this.viewScroll.set(previousView, { top: this.scroll.scrollTop, live: this.offset === 0 });
|
|
5519
|
+
this.viewDisclosures.set(previousView, this.content.captureDisclosures(this.tasks.captureDisclosures()));
|
|
4886
5520
|
this.pendingScrollRestore = this.viewScroll.get(currentView) ?? { top: 0, live: true };
|
|
5521
|
+
this.pendingDisclosures = this.viewDisclosures.get(currentView);
|
|
4887
5522
|
this.newEntries = 0;
|
|
4888
5523
|
}
|
|
4889
5524
|
this.state = state;
|
|
@@ -4918,6 +5553,11 @@ var NativeFrontend = class {
|
|
|
4918
5553
|
if (this.offset > 0 && !viewChanged && !patch.reset) this.newEntries += patch.upsert.filter((block) => !this.content.views.has(block.id)).length;
|
|
4919
5554
|
this.content.patch(patch);
|
|
4920
5555
|
}
|
|
5556
|
+
if (this.pendingDisclosures) {
|
|
5557
|
+
this.content.restoreDisclosures(this.pendingDisclosures);
|
|
5558
|
+
this.tasks.restoreDisclosures(this.pendingDisclosures);
|
|
5559
|
+
this.pendingDisclosures = void 0;
|
|
5560
|
+
}
|
|
4921
5561
|
this.queue.content = state.queued.length ? `Queued (${state.queued.length}) · ${state.queued.join(" · ")}` : "";
|
|
4922
5562
|
this.queue.visible = state.queued.length > 0;
|
|
4923
5563
|
const suggestionSignature = JSON.stringify(state.suggestions);
|
|
@@ -4966,7 +5606,7 @@ var NativeFrontend = class {
|
|
|
4966
5606
|
for (const action of actions) {
|
|
4967
5607
|
const colors = this.context.colors;
|
|
4968
5608
|
const attributes = action.disabled ? TextAttributes8.DIM : action.active ? TextAttributes8.BOLD | TextAttributes8.UNDERLINE : 0;
|
|
4969
|
-
const button = new
|
|
5609
|
+
const button = new TextRenderable7(this.renderer, {
|
|
4970
5610
|
id: `${prefix}:${action.id}`,
|
|
4971
5611
|
content: styledText(action.label),
|
|
4972
5612
|
flexShrink: 0,
|
|
@@ -5013,8 +5653,11 @@ var NativeFrontend = class {
|
|
|
5013
5653
|
}
|
|
5014
5654
|
renderActivity() {
|
|
5015
5655
|
const activity = this.state?.activity;
|
|
5016
|
-
const stage = activity?.stage === "idle" ? void 0 : activity?.stage;
|
|
5017
|
-
const
|
|
5656
|
+
const stage = activity?.stage === "idle" ? void 0 : activity?.stage?.replace(/_/g, " ").toUpperCase();
|
|
5657
|
+
const label = activity?.label && activity.label.toUpperCase() !== stage ? activity.label : void 0;
|
|
5658
|
+
const elapsed = activity?.elapsedMs === void 0 ? void 0 : `${Math.max(0, Math.floor(activity.elapsedMs / 1e3))}s`;
|
|
5659
|
+
const progress = activity?.progress === void 0 ? void 0 : `${Math.round(activity.progress * 100)}% source accounted`;
|
|
5660
|
+
const reading = [stage, label, elapsed, progress].filter(Boolean).join(" · ") || this.state?.instruments?.runtimeStatus || "";
|
|
5018
5661
|
this.activity.visible = Boolean(activity?.processing || reading);
|
|
5019
5662
|
this.activity.content = `${activity?.processing ? "RUN · " : ""}${reading}`;
|
|
5020
5663
|
this.status.visible = this.activity.visible || this.media.visible || this.copyFeedback.visible;
|
|
@@ -5112,14 +5755,17 @@ var NativeFrontend = class {
|
|
|
5112
5755
|
const shown = !this.embeddedPane.visible && (wide ? this.detailsOpen ?? true : this.narrowDetailsOpen);
|
|
5113
5756
|
const horizontal = wide || this.embeddedPane.visible && width >= 80;
|
|
5114
5757
|
this.body.flexDirection = horizontal ? "row" : "column";
|
|
5115
|
-
this.
|
|
5116
|
-
this.
|
|
5758
|
+
this.transcriptPane.height = horizontal ? "100%" : "auto";
|
|
5759
|
+
this.transcriptPane.flexBasis = horizontal ? "auto" : 0;
|
|
5760
|
+
this.scroll.height = "auto";
|
|
5761
|
+
this.scroll.flexBasis = 0;
|
|
5117
5762
|
this.instruments.visible = shown;
|
|
5118
5763
|
this.instrumentDivider.visible = wide && !this.embeddedPane.visible;
|
|
5119
5764
|
this.instrumentDivider.setCollapsed(!shown);
|
|
5120
5765
|
const railWidth = Math.max(24, Math.min(width - 41, this.sidebarWidth ?? Math.floor(width * 0.38)));
|
|
5121
5766
|
this.instruments.width = wide ? railWidth : "100%";
|
|
5122
|
-
this.
|
|
5767
|
+
this.transcriptPane.width = wide && this.instrumentDivider.visible ? width - (shown ? railWidth : 0) - 1 : this.embeddedPane.visible && width >= 80 ? "50%" : "100%";
|
|
5768
|
+
this.scroll.width = "100%";
|
|
5123
5769
|
const inspectorHeight = Math.max(4, Math.min(9, Math.floor(this.renderer.terminalHeight / 3)));
|
|
5124
5770
|
this.instruments.height = wide ? "100%" : inspectorHeight;
|
|
5125
5771
|
this.instruments.maxHeight = wide ? "100%" : inspectorHeight;
|
|
@@ -5167,6 +5813,22 @@ var NativeFrontend = class {
|
|
|
5167
5813
|
}
|
|
5168
5814
|
onFrame = () => {
|
|
5169
5815
|
if (this.destroyed) return;
|
|
5816
|
+
if (this.pendingInterface) {
|
|
5817
|
+
const state = this.pendingInterface;
|
|
5818
|
+
this.pendingInterface = void 0;
|
|
5819
|
+
this.instruments.restorePresentation(state.instruments);
|
|
5820
|
+
this.sessions.restoreOffset(state.tabs.sessions);
|
|
5821
|
+
this.tabs.restoreOffset(state.tabs.agents);
|
|
5822
|
+
const focus = state.focusId && !this.modals.active ? this.getRenderable(state.focusId) : void 0;
|
|
5823
|
+
if (focus?.focusable) {
|
|
5824
|
+
let ancestor = focus, visible = true;
|
|
5825
|
+
while (ancestor) {
|
|
5826
|
+
visible &&= ancestor.visible;
|
|
5827
|
+
ancestor = ancestor.parent;
|
|
5828
|
+
}
|
|
5829
|
+
if (visible) focus.focus();
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5170
5832
|
if (this.pendingScrollRestore) {
|
|
5171
5833
|
const restore = this.pendingScrollRestore;
|
|
5172
5834
|
this.pendingScrollRestore = void 0;
|
|
@@ -5176,10 +5838,11 @@ var NativeFrontend = class {
|
|
|
5176
5838
|
const height = Math.max(1, Math.min(8, this.editor.editorView.getTotalVirtualLineCount(), this.renderer.terminalHeight - 8));
|
|
5177
5839
|
if (height !== this.editor.height) this.editor.height = height;
|
|
5178
5840
|
this.layoutTabStrips();
|
|
5179
|
-
const
|
|
5180
|
-
|
|
5181
|
-
this.
|
|
5182
|
-
|
|
5841
|
+
for (const media of this.context.mediaViews ?? []) media.reconcile({ x: this.scroll.viewport.x, y: this.scroll.viewport.y, width: this.scroll.viewport.width, height: this.scroll.viewport.height }, !this.paused);
|
|
5842
|
+
const offset2 = this.offset;
|
|
5843
|
+
if (offset2 === 0) this.newEntries = 0;
|
|
5844
|
+
this.liveButton.visible = offset2 > 0;
|
|
5845
|
+
const liveLabel = offset2 > 0 ? `↓ Live${this.newEntries ? ` · ${this.newEntries} new` : ""}` : "↓ Live";
|
|
5183
5846
|
if (this.liveButton.plainText !== liveLabel) this.liveButton.content = liveLabel;
|
|
5184
5847
|
const event = { type: "viewport", offset: this.scroll.scrollTop, height: this.scroll.viewport.height, width: this.scroll.viewport.width, total: this.scroll.scrollHeight };
|
|
5185
5848
|
const signature = JSON.stringify(event);
|
|
@@ -5446,7 +6109,7 @@ var NativeFrontend = class {
|
|
|
5446
6109
|
const target = targets[(current + direction + targets.length) % targets.length];
|
|
5447
6110
|
target.focus();
|
|
5448
6111
|
if (target.id.startsWith("header:")) this.headerActions.scrollChildIntoView(target.id);
|
|
5449
|
-
else if (target.id.startsWith("block-title:") || target.id.startsWith("block-action:")) {
|
|
6112
|
+
else if (target.id.startsWith("block-title:") || target.id.startsWith("block-action:") || target.id.startsWith("media-control:") || target.id.startsWith("media-preview:")) {
|
|
5450
6113
|
let block = target;
|
|
5451
6114
|
while (block && !block.id.startsWith("block:")) block = block.parent;
|
|
5452
6115
|
if (block) this.scroll.scrollChildIntoView(block.id);
|
|
@@ -5618,6 +6281,53 @@ var NativeFrontend = class {
|
|
|
5618
6281
|
this.restoreFocus();
|
|
5619
6282
|
}
|
|
5620
6283
|
}
|
|
6284
|
+
pauseMedia() {
|
|
6285
|
+
for (const media of this.context.mediaViews ?? []) media.pausePlayback();
|
|
6286
|
+
}
|
|
6287
|
+
captureInterfaceState() {
|
|
6288
|
+
this.flushLatestInput();
|
|
6289
|
+
const key = `${this.state?.sessions?.activeId ?? ""}:${this.state?.activeViewId ?? "main"}:${this.state?.presentation ?? "stack"}`;
|
|
6290
|
+
this.viewScroll.set(key, { top: this.scroll.scrollTop, live: this.offset === 0 });
|
|
6291
|
+
this.viewDisclosures.set(key, this.content.captureDisclosures(this.tasks.captureDisclosures()));
|
|
6292
|
+
return {
|
|
6293
|
+
version: 1,
|
|
6294
|
+
sessionId: this.state?.sessions?.activeId,
|
|
6295
|
+
activeViewId: this.state?.activeViewId ?? "main",
|
|
6296
|
+
presentation: this.state?.presentation ?? "stack",
|
|
6297
|
+
focusId: this.renderer.currentFocusedRenderable?.id,
|
|
6298
|
+
input: { text: this.editor.plainText, cursor: this.inputCursor() },
|
|
6299
|
+
views: Object.fromEntries([...this.viewScroll].slice(-256).map(([id, view]) => [id, { ...view, disclosures: this.viewDisclosures.get(id) ?? {} }])),
|
|
6300
|
+
layout: { sidebarWidth: this.sidebarWidth, detailsOpen: this.detailsOpen, narrowDetailsOpen: this.narrowDetailsOpen, headerPanelCollapsed: this.headerPanelCollapsed },
|
|
6301
|
+
instruments: this.instruments.capturePresentation(),
|
|
6302
|
+
tabs: { sessions: this.sessions.scroll.scrollLeft, agents: this.tabs.scroll.scrollLeft }
|
|
6303
|
+
};
|
|
6304
|
+
}
|
|
6305
|
+
restoreInterfaceState(value) {
|
|
6306
|
+
const state = sanitizeNativeInterfaceState(value);
|
|
6307
|
+
if (!state) return;
|
|
6308
|
+
for (const [key2, view2] of Object.entries(state.views)) {
|
|
6309
|
+
this.viewScroll.set(key2, { top: view2.top, live: view2.live });
|
|
6310
|
+
this.viewDisclosures.set(key2, view2.disclosures);
|
|
6311
|
+
}
|
|
6312
|
+
this.sidebarWidth = state.layout.sidebarWidth;
|
|
6313
|
+
this.detailsOpen = state.layout.detailsOpen;
|
|
6314
|
+
this.narrowDetailsOpen = state.layout.narrowDetailsOpen;
|
|
6315
|
+
this.headerPanelCollapsed = state.layout.headerPanelCollapsed;
|
|
6316
|
+
this.headerSignature = "";
|
|
6317
|
+
this.setInput(state.input.text, state.input.cursor);
|
|
6318
|
+
const key = `${this.state?.sessions?.activeId ?? state.sessionId ?? ""}:${this.state?.activeViewId ?? state.activeViewId}:${this.state?.presentation ?? state.presentation}`;
|
|
6319
|
+
const view = this.viewScroll.get(key);
|
|
6320
|
+
if (view) {
|
|
6321
|
+
this.pendingScrollRestore = view;
|
|
6322
|
+
const disclosures = this.viewDisclosures.get(key) ?? {};
|
|
6323
|
+
this.content.restoreDisclosures(disclosures);
|
|
6324
|
+
this.tasks.restoreDisclosures(disclosures);
|
|
6325
|
+
}
|
|
6326
|
+
this.pendingInterface = state;
|
|
6327
|
+
if (this.state) this.update(this.state);
|
|
6328
|
+
this.layoutInstruments();
|
|
6329
|
+
this.renderer.requestRender();
|
|
6330
|
+
}
|
|
5621
6331
|
async dispose() {
|
|
5622
6332
|
if (this.destroyed) return;
|
|
5623
6333
|
this.destroyed = true;
|
|
@@ -5628,9 +6338,14 @@ var NativeFrontend = class {
|
|
|
5628
6338
|
this.renderer.keyInput.off("paste", this.onPaste);
|
|
5629
6339
|
this.renderer.off(CliRenderEvents5.FRAME, this.onFrame);
|
|
5630
6340
|
this.renderer.off(CliRenderEvents5.RESIZE, this.onResize);
|
|
6341
|
+
const mediaClosed = [...this.context.mediaViews ?? []].map((media) => {
|
|
6342
|
+
media.pausePlayback();
|
|
6343
|
+
return media.closed;
|
|
6344
|
+
});
|
|
5631
6345
|
this.modals.destroy();
|
|
5632
6346
|
this.content.destroy();
|
|
5633
6347
|
this.tasks.destroy();
|
|
6348
|
+
await Promise.allSettled(mediaClosed);
|
|
5634
6349
|
this.root.destroyRecursively();
|
|
5635
6350
|
this.context.syntax.destroy();
|
|
5636
6351
|
await this.clipboard.dispose();
|
|
@@ -5650,10 +6365,10 @@ function installTerminalCursorDefaults(renderer2, session) {
|
|
|
5650
6365
|
if (disposed || session.disposed) return Promise.resolve();
|
|
5651
6366
|
requested++;
|
|
5652
6367
|
if (pending) return pending;
|
|
5653
|
-
let
|
|
6368
|
+
let resolve2;
|
|
5654
6369
|
let reject;
|
|
5655
6370
|
const completion = new Promise((done, fail2) => {
|
|
5656
|
-
|
|
6371
|
+
resolve2 = done;
|
|
5657
6372
|
reject = fail2;
|
|
5658
6373
|
});
|
|
5659
6374
|
pending = completion;
|
|
@@ -5666,7 +6381,7 @@ function installTerminalCursorDefaults(renderer2, session) {
|
|
|
5666
6381
|
restored = generation;
|
|
5667
6382
|
}
|
|
5668
6383
|
pending = void 0;
|
|
5669
|
-
|
|
6384
|
+
resolve2();
|
|
5670
6385
|
} catch (error) {
|
|
5671
6386
|
pending = void 0;
|
|
5672
6387
|
reject(error);
|
|
@@ -5732,11 +6447,24 @@ async function command(message) {
|
|
|
5732
6447
|
frontend.command(message.command);
|
|
5733
6448
|
return;
|
|
5734
6449
|
}
|
|
6450
|
+
if (message.type === "interface-capture") {
|
|
6451
|
+
await renderer.idle();
|
|
6452
|
+
reply({ type: "interface-state", id: message.id, state: frontend.captureInterfaceState() });
|
|
6453
|
+
return;
|
|
6454
|
+
}
|
|
6455
|
+
if (message.type === "interface-restore") {
|
|
6456
|
+
frontend.restoreInterfaceState(message.state);
|
|
6457
|
+
renderer.requestRender();
|
|
6458
|
+
await renderer.idle();
|
|
6459
|
+
reply({ type: "ack", id: message.id });
|
|
6460
|
+
return;
|
|
6461
|
+
}
|
|
5735
6462
|
if (message.type === "state") {
|
|
5736
6463
|
frontend.update(message.snapshot, message.content);
|
|
5737
6464
|
renderer.requestRender();
|
|
5738
6465
|
await renderer.idle();
|
|
5739
6466
|
} else if (message.type === "suspend") {
|
|
6467
|
+
frontend.pauseMedia();
|
|
5740
6468
|
await cursorDefaults.restore();
|
|
5741
6469
|
await renderer.suspend();
|
|
5742
6470
|
} else if (message.type === "resume") {
|