omnius 1.0.881 → 1.0.883
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/index.js +2 -2
- package/dist/library.js +3482 -1918
- package/dist/omni-setup-worker.js +49 -25
- package/dist/postinstall-daemon.cjs +8 -5
- package/dist/tui/native/worker.js +934 -180
- package/dist/update-worker-runtime.js +369 -165
- package/dist/update-worker.js +4 -4
- package/docs/DISCOVERY.json +36 -0
- package/docs/DISCOVERY.md +1 -0
- package/docs/work-orders/evidence/workspace-media-view-verification-20261018.json +108 -0
- package/npm-shrinkwrap.json +1016 -48
- package/package.json +4 -2
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import { createWriteStream } from "node:fs";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
4
|
import { PassThrough } from "node:stream";
|
|
5
|
-
import { CliRenderEvents as CliRenderEvents10, NativeSession, RGBA as
|
|
5
|
+
import { CliRenderEvents as CliRenderEvents10, NativeSession, RGBA as RGBA4, createCliRenderer } from "@opentui/core";
|
|
6
6
|
|
|
7
7
|
// packages/cli/src/tui/native/components/frontend.ts
|
|
8
8
|
import {
|
|
9
|
-
BoxRenderable as
|
|
9
|
+
BoxRenderable as BoxRenderable12,
|
|
10
10
|
CliRenderEvents as CliRenderEvents8,
|
|
11
11
|
EmbeddedTerminalRenderable as EmbeddedTerminalRenderable2,
|
|
12
12
|
ScrollBoxRenderable as ScrollBoxRenderable8,
|
|
13
13
|
SyntaxStyle as SyntaxStyle2,
|
|
14
14
|
TextareaRenderable as TextareaRenderable2,
|
|
15
|
-
TextRenderable as
|
|
15
|
+
TextRenderable as TextRenderable11,
|
|
16
16
|
TextAttributes as TextAttributes11,
|
|
17
17
|
createClipboard,
|
|
18
18
|
createHostClipboard,
|
|
@@ -42,12 +42,12 @@ function sanitizeNativeInterfaceState(value) {
|
|
|
42
42
|
const workQueue = record(instruments.workQueue) ? instruments.workQueue : void 0;
|
|
43
43
|
const workspaceFiles = record(instruments.workspaceFiles) ? instruments.workspaceFiles : void 0;
|
|
44
44
|
const workDisclosures = {};
|
|
45
|
-
if (workQueue && record(workQueue.disclosures)) for (const [id,
|
|
46
|
-
if (id.length <= 1024 && typeof
|
|
45
|
+
if (workQueue && record(workQueue.disclosures)) for (const [id, open2] of Object.entries(workQueue.disclosures).slice(0, 2048)) {
|
|
46
|
+
if (id.length <= 1024 && typeof open2 === "boolean") Object.defineProperty(workDisclosures, id, { value: open2, enumerable: true, configurable: true, writable: true });
|
|
47
47
|
}
|
|
48
48
|
const taskDisclosures = {};
|
|
49
|
-
if (taskNotes && record(taskNotes.disclosures)) for (const [id,
|
|
50
|
-
if (id.length <= 1024 && typeof
|
|
49
|
+
if (taskNotes && record(taskNotes.disclosures)) for (const [id, open2] of Object.entries(taskNotes.disclosures).slice(0, 2048)) {
|
|
50
|
+
if (id.length <= 1024 && typeof open2 === "boolean") Object.defineProperty(taskDisclosures, id, { value: open2, enumerable: true, configurable: true, writable: true });
|
|
51
51
|
}
|
|
52
52
|
return {
|
|
53
53
|
version: 1,
|
|
@@ -90,14 +90,14 @@ function sanitizeNativeInterfaceState(value) {
|
|
|
90
90
|
|
|
91
91
|
// packages/cli/src/tui/native/components/blocks.ts
|
|
92
92
|
import {
|
|
93
|
-
BoxRenderable as
|
|
93
|
+
BoxRenderable as BoxRenderable3,
|
|
94
94
|
CodeRenderable,
|
|
95
95
|
EmbeddedTerminalRenderable,
|
|
96
96
|
ImageRenderable as ImageRenderable2,
|
|
97
97
|
MarkdownRenderable,
|
|
98
98
|
RenderableEvents,
|
|
99
99
|
ScrollBoxRenderable,
|
|
100
|
-
TextRenderable as
|
|
100
|
+
TextRenderable as TextRenderable3
|
|
101
101
|
} from "@opentui/core";
|
|
102
102
|
|
|
103
103
|
// packages/cli/src/tui/native/components/text.ts
|
|
@@ -248,18 +248,18 @@ import { spawn, execFile } from "node:child_process";
|
|
|
248
248
|
import { realpath, lstat } from "node:fs/promises";
|
|
249
249
|
import { extname, relative, resolve } from "node:path";
|
|
250
250
|
import { Audio } from "@opentui/core";
|
|
251
|
-
async function validateMediaFile(path, root) {
|
|
251
|
+
async function validateMediaFile(path, root, allowSvg = false) {
|
|
252
252
|
const info = await lstat(path);
|
|
253
253
|
if (!info.isFile() || info.isSymbolicLink()) throw new Error("Media must be a regular local file");
|
|
254
254
|
const canonical = await realpath(path), project = await realpath(root);
|
|
255
255
|
const local = relative(project, canonical);
|
|
256
256
|
if (local === ".." || local.startsWith("../") || resolve(project, local) !== canonical) throw new Error("Media is outside its project");
|
|
257
|
-
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");
|
|
257
|
+
if (!/\.(png|jpe?g|webp|gif|mp4|webm|mov|mkv|wav|mp3|flac|ogg|opus|m4a|aiff?)$/i.test(extname(canonical)) && !(allowSvg && extname(canonical).toLowerCase() === ".svg")) throw new Error("Unsupported media file");
|
|
258
258
|
return canonical;
|
|
259
259
|
}
|
|
260
260
|
async function probeMedia(spec, signal) {
|
|
261
261
|
const path = await validateMediaFile(spec.path, spec.projectRoot);
|
|
262
|
-
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)));
|
|
262
|
+
const output = await new Promise((done, fail2) => execFile("ffprobe", ["-v", "error", "-protocol_whitelist", "file,pipe", "-show_entries", "stream=codec_type,width,height:format=duration", "-of", "json", path], { signal, timeout: 5e3, maxBuffer: 128e3 }, (error, stdout) => error ? fail2(error) : done(stdout)));
|
|
263
263
|
const data = JSON.parse(output), video = data.streams?.find((stream) => stream.codec_type === "video");
|
|
264
264
|
const durationSec = Number(data.format?.duration);
|
|
265
265
|
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") };
|
|
@@ -296,7 +296,7 @@ var NativeMediaPlayback = class {
|
|
|
296
296
|
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));
|
|
297
297
|
const info = spec.kind === "video" ? await probeMedia(spec, controller.signal) : {};
|
|
298
298
|
if (epoch !== this.epoch) return;
|
|
299
|
-
const input = ["-nostdin", "-loglevel", "error", "-hwaccel", "none", "-ss", String(this.positionSec), ...spec.kind === "video" ? ["-re"] : [], "-i", path];
|
|
299
|
+
const input = ["-nostdin", "-loglevel", "error", "-hwaccel", "none", "-protocol_whitelist", "file,pipe", "-ss", String(this.positionSec), ...spec.kind === "video" ? ["-re"] : [], "-i", path];
|
|
300
300
|
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"];
|
|
301
301
|
const withAudio = spec.kind === "video" && info.hasAudio;
|
|
302
302
|
if (withAudio) output.push("-map", "0:a:0", "-vn", "-f", "f32le", "-ac", "2", "-ar", "48000", "pipe:3");
|
|
@@ -423,11 +423,14 @@ function mediaPreviewHeight(width, imageWidth, imageHeight, cellAspectRatio = 2)
|
|
|
423
423
|
function audioWaveform(samples, width) {
|
|
424
424
|
const cells = Math.max(1, Math.min(240, Math.floor(width)));
|
|
425
425
|
const glyphs = "▁▂▃▄▅▆▇█";
|
|
426
|
+
let maximum = 0;
|
|
427
|
+
for (const sample of samples) if (Number.isFinite(sample)) maximum = Math.max(maximum, Math.abs(sample));
|
|
428
|
+
const scale = maximum > 1e-5 ? maximum : 0;
|
|
426
429
|
return Array.from({ length: cells }, (_, column3) => {
|
|
427
430
|
const begin = Math.floor(column3 * samples.length / cells), end = Math.max(begin + 1, Math.floor((column3 + 1) * samples.length / cells));
|
|
428
431
|
let peak = 0;
|
|
429
432
|
for (let index = begin; index < end && index < samples.length; index++) if (Number.isFinite(samples[index])) peak = Math.max(peak, Math.abs(samples[index]));
|
|
430
|
-
return glyphs[Math.min(7, Math.floor(Math.min(1, peak) * 7))];
|
|
433
|
+
return glyphs[scale ? Math.min(7, Math.floor(Math.min(1, peak / scale) * 7)) : 0];
|
|
431
434
|
}).join("");
|
|
432
435
|
}
|
|
433
436
|
var time = (seconds) => `${Math.floor(Math.max(0, seconds) / 60)}:${String(Math.floor(Math.max(0, seconds) % 60)).padStart(2, "0")}`;
|
|
@@ -439,7 +442,7 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
439
442
|
this.colors = colors;
|
|
440
443
|
this.sendEvent = sendEvent;
|
|
441
444
|
this.spec = spec;
|
|
442
|
-
this.location = new TextRenderable(renderer2, { id: `media-location:${mediaId}`, content: spec.path, width: "100%", wrapMode: "word", selectable: true, fg: colors.dim });
|
|
445
|
+
this.location = new TextRenderable(renderer2, { id: `media-location:${mediaId}`, content: spec.displayName ?? spec.path, width: "100%", wrapMode: "word", selectable: true, fg: colors.dim });
|
|
443
446
|
this.status = new TextRenderable(renderer2, { id: `media-status:${mediaId}`, content: "", width: "100%", wrapMode: "word", selectable: true, fg: colors.dim });
|
|
444
447
|
this.wave = new TextRenderable(renderer2, { id: `media-waveform:${mediaId}`, content: "", width: "100%", height: 1, wrapMode: "none", fg: colors.foreground, visible: false });
|
|
445
448
|
this.playheadLabel = new TextRenderable(renderer2, { id: `media-position:${mediaId}`, content: "", width: "100%", height: 1, wrapMode: "none", fg: colors.dim, visible: false });
|
|
@@ -524,7 +527,7 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
524
527
|
update(spec) {
|
|
525
528
|
const changed = spec.path !== this.spec.path || spec.kind !== this.spec.kind;
|
|
526
529
|
this.spec = spec;
|
|
527
|
-
this.location.content = spec.path;
|
|
530
|
+
this.location.content = spec.displayName ?? spec.path;
|
|
528
531
|
this.playControl.visible = spec.kind !== "image";
|
|
529
532
|
if (changed) {
|
|
530
533
|
this.playback.pause();
|
|
@@ -582,7 +585,7 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
582
585
|
}
|
|
583
586
|
if (this.image) {
|
|
584
587
|
this.image.visible = spec.kind === "image" || spec.kind === "video";
|
|
585
|
-
const source = spec.kind === "image" ? spec.path : spec.previewPath;
|
|
588
|
+
const source = spec.kind === "image" ? spec.previewPath ?? spec.path : spec.previewPath;
|
|
586
589
|
if (source && this.image.source !== source && !this.playback.playing) {
|
|
587
590
|
const epoch = this.sourceEpoch;
|
|
588
591
|
void validateMediaFile(source, spec.projectRoot).then((path) => {
|
|
@@ -621,7 +624,7 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
621
624
|
this.refreshStatus();
|
|
622
625
|
}
|
|
623
626
|
loadWaveform(controller, epoch) {
|
|
624
|
-
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) => {
|
|
627
|
+
execFile2("ffmpeg", ["-nostdin", "-loglevel", "error", "-hwaccel", "none", "-protocol_whitelist", "file,pipe", "-i", this.spec.path, "-t", "600", "-vn", "-af", "aformat=channel_layouts=mono,aeval=abs(val(0))", "-ac", "1", "-ar", "1000", "-f", "f32le", "pipe:1"], { encoding: "buffer", signal: controller.signal, timeout: 1e4, maxBuffer: 25e5 }, (error, buffer) => {
|
|
625
628
|
if (controller.signal.aborted || epoch !== this.sourceEpoch || this.isDestroyed) return;
|
|
626
629
|
if (error) {
|
|
627
630
|
this.currentStatus = "Waveform unavailable · playback and Open remain available";
|
|
@@ -700,7 +703,7 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
700
703
|
}
|
|
701
704
|
async open() {
|
|
702
705
|
try {
|
|
703
|
-
const path = await validateMediaFile(this.spec.path, this.spec.projectRoot);
|
|
706
|
+
const path = await validateMediaFile(this.spec.path, this.spec.projectRoot, this.spec.kind === "image" && !!this.spec.previewPath);
|
|
704
707
|
if (this.isDestroyed) return;
|
|
705
708
|
this.sendEvent({ type: "action", action: "media-open", id: this.mediaId, text: path });
|
|
706
709
|
if (process.env["OMNIUS_MEDIA_TEST_NO_OPEN"] === "1") {
|
|
@@ -738,6 +741,649 @@ var NativeMediaView = class extends BoxRenderable {
|
|
|
738
741
|
}
|
|
739
742
|
};
|
|
740
743
|
|
|
744
|
+
// packages/cli/src/tui/native/components/model3d.ts
|
|
745
|
+
import { constants } from "node:fs";
|
|
746
|
+
import { open } from "node:fs/promises";
|
|
747
|
+
import { BoxRenderable as BoxRenderable2, FrameBufferRenderable, OptimizedBuffer, RGBA as RGBA2, TextRenderable as TextRenderable2 } from "@opentui/core";
|
|
748
|
+
|
|
749
|
+
// packages/cli/src/tui/native/model3d.ts
|
|
750
|
+
var MODEL3D_MAX_BYTES = 16 * 1024 * 1024;
|
|
751
|
+
var MODEL3D_MAX_VERTICES = 75e4;
|
|
752
|
+
var MODEL3D_MAX_TRIANGLES = 25e4;
|
|
753
|
+
var MODEL3D_MAX_WIREFRAME_EDGES = 6e3;
|
|
754
|
+
var initialModel3DCamera = () => ({ yaw: 0.65, pitch: 0.35, distance: 3.5 });
|
|
755
|
+
var invalid = (message) => {
|
|
756
|
+
throw new Error(message);
|
|
757
|
+
};
|
|
758
|
+
function preflight(data, format) {
|
|
759
|
+
if (!data.byteLength || data.byteLength > MODEL3D_MAX_BYTES) invalid("3D preview supports nonempty files up to 16 MiB.");
|
|
760
|
+
if (format === "stl") {
|
|
761
|
+
if (data.byteLength < 84) invalid("STL data is incomplete.");
|
|
762
|
+
const faces = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(80, true);
|
|
763
|
+
const binary2 = 84 + faces * 50 === data.byteLength;
|
|
764
|
+
if (binary2) {
|
|
765
|
+
if (!faces || faces > MODEL3D_MAX_TRIANGLES) invalid("STL exceeds the 250,000 triangle preview limit.");
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const text2 = new TextDecoder().decode(data);
|
|
769
|
+
if (!/^\uFEFF?\s*solid\b/i.test(text2) || !/endsolid\b/i.test(text2)) invalid("STL data is incomplete or unsupported.");
|
|
770
|
+
const count = text2.match(/\bfacet\s+normal\b/gi)?.length ?? 0;
|
|
771
|
+
if (!count || count > MODEL3D_MAX_TRIANGLES) invalid("STL exceeds the 250,000 triangle preview limit or has no faces.");
|
|
772
|
+
let asciiFaces = 0;
|
|
773
|
+
for (const match of text2.matchAll(/\bfacet\b([\s\S]*?)\bendfacet\b/gi)) {
|
|
774
|
+
const normals = [...match[1].matchAll(/\bnormal\s+([^\r\n]+)/gi)], vertices2 = [...match[1].matchAll(/\bvertex\s+([^\r\n]+)/gi)];
|
|
775
|
+
if (normals.length !== 1 || vertices2.length !== 3 || [...normals, ...vertices2].some((row) => {
|
|
776
|
+
const values = row[1].trim().split(/\s+/).map(Number);
|
|
777
|
+
return values.length !== 3 || values.some((value) => !Number.isFinite(value));
|
|
778
|
+
})) invalid("STL face data is incomplete or invalid.");
|
|
779
|
+
asciiFaces++;
|
|
780
|
+
}
|
|
781
|
+
if (asciiFaces !== count) invalid("STL face data is incomplete.");
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const text = new TextDecoder().decode(data);
|
|
785
|
+
if (format === "obj") {
|
|
786
|
+
let vertices2 = 0, triangles2 = 0;
|
|
787
|
+
for (const line of text.split(/\r?\n/)) {
|
|
788
|
+
if (line.length > 65536) invalid("OBJ line exceeds the preview limit.");
|
|
789
|
+
const record2 = line.trim().split(/\s+/, 1)[0];
|
|
790
|
+
if (record2 && !record2.startsWith("#") && !["v", "vn", "vt", "f", "l", "p", "o", "g", "s", "mtllib", "usemtl"].includes(record2)) invalid("OBJ contains an unsupported record; preview supports geometry and material names only.");
|
|
791
|
+
if (/^\s*v\s/.test(line)) {
|
|
792
|
+
const values = line.trim().split(/\s+/).slice(1, 4).map(Number);
|
|
793
|
+
if (values.length !== 3 || values.some((value) => !Number.isFinite(value) || Math.abs(value) > 1e30)) invalid("OBJ contains invalid coordinates.");
|
|
794
|
+
vertices2++;
|
|
795
|
+
}
|
|
796
|
+
if (/^\s*(f|l|p)\s/.test(line)) {
|
|
797
|
+
const values = line.split("#", 1)[0].trim().split(/\s+/);
|
|
798
|
+
for (const token of values.slice(1)) {
|
|
799
|
+
const index = Number(token.split("/")[0]);
|
|
800
|
+
if (!Number.isSafeInteger(index) || index === 0 || index > vertices2 || index < -vertices2) invalid("OBJ contains an invalid vertex index.");
|
|
801
|
+
}
|
|
802
|
+
if (values[0] === "f") triangles2 += Math.max(0, values.length - 3);
|
|
803
|
+
}
|
|
804
|
+
if (vertices2 > MODEL3D_MAX_VERTICES || triangles2 > MODEL3D_MAX_TRIANGLES) invalid("OBJ exceeds the bounded geometry preview limit.");
|
|
805
|
+
}
|
|
806
|
+
if (!vertices2) invalid("OBJ contains no vertices.");
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const end = text.indexOf("end_header");
|
|
810
|
+
if (!text.startsWith("ply") || end < 0 || end > 65536) invalid("PLY header is missing or too large.");
|
|
811
|
+
const header = text.slice(0, end);
|
|
812
|
+
if (!/^format (ascii|binary_little_endian|binary_big_endian) 1\.0\s*$/m.test(header)) invalid("PLY format is unsupported.");
|
|
813
|
+
let vertices = 0;
|
|
814
|
+
const elements = [];
|
|
815
|
+
for (const line of header.split(/\r?\n/)) {
|
|
816
|
+
const element = /^element\s+(\S+)\s+(\d+)\s*$/.exec(line);
|
|
817
|
+
if (!element) {
|
|
818
|
+
const property = /^property\s+(\S+)\s+(\S+)(?:\s+(\S+)\s+(\S+))?\s*$/.exec(line);
|
|
819
|
+
if (property) {
|
|
820
|
+
if (!elements.length) invalid("PLY property has no element.");
|
|
821
|
+
elements.at(-1).properties.push(property[1] === "list" ? { type: property[2], item: property[3] } : { type: property[1] });
|
|
822
|
+
}
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
const count = Number(element[2]);
|
|
826
|
+
if (!Number.isSafeInteger(count) || count > MODEL3D_MAX_VERTICES) invalid("PLY exceeds the bounded geometry preview limit.");
|
|
827
|
+
if (element[1] === "vertex") vertices = count;
|
|
828
|
+
if (element[1] === "face" && count > MODEL3D_MAX_TRIANGLES) invalid("PLY exceeds the 250,000 face preview limit.");
|
|
829
|
+
elements.push({ name: element[1], count, properties: [] });
|
|
830
|
+
}
|
|
831
|
+
if (!vertices) invalid("PLY contains no vertices.");
|
|
832
|
+
if (elements.reduce((count, element) => count + element.count, 0) > 1e6 || elements.some((element) => !element.properties.length || element.properties.length > 32)) invalid("PLY record layout exceeds the bounded preview limit.");
|
|
833
|
+
const sizes = { char: 1, uchar: 1, int8: 1, uint8: 1, short: 2, ushort: 2, int16: 2, uint16: 2, int: 4, uint: 4, int32: 4, uint32: 4, float: 4, float32: 4, double: 8, float64: 8 };
|
|
834
|
+
const binary = !/^format ascii /m.test(header), little = /^format binary_little_endian /m.test(header);
|
|
835
|
+
const headerBytes = new TextEncoder().encode(text.slice(0, end + "end_header".length)).byteLength;
|
|
836
|
+
let offset2 = headerBytes;
|
|
837
|
+
if (data[offset2] === 13) offset2++;
|
|
838
|
+
if (data[offset2] === 10) offset2++;
|
|
839
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
840
|
+
const ascii = binary ? "" : new TextDecoder().decode(data.subarray(offset2)), next = /\S+/g;
|
|
841
|
+
let triangles = 0;
|
|
842
|
+
const scalar = (type) => {
|
|
843
|
+
const size = sizes[type];
|
|
844
|
+
if (!size) invalid("PLY property type is unsupported.");
|
|
845
|
+
if (!binary) {
|
|
846
|
+
const token = next.exec(ascii);
|
|
847
|
+
const value2 = token ? Number(token[0]) : NaN;
|
|
848
|
+
if (!Number.isFinite(value2)) invalid("PLY data is incomplete or invalid.");
|
|
849
|
+
return value2;
|
|
850
|
+
}
|
|
851
|
+
if (offset2 + size > data.length) invalid("PLY data is incomplete.");
|
|
852
|
+
let value;
|
|
853
|
+
if (/^(uchar|uint8)$/.test(type)) value = view.getUint8(offset2);
|
|
854
|
+
else if (/^(char|int8)$/.test(type)) value = view.getInt8(offset2);
|
|
855
|
+
else if (/^(ushort|uint16)$/.test(type)) value = view.getUint16(offset2, little);
|
|
856
|
+
else if (/^(short|int16)$/.test(type)) value = view.getInt16(offset2, little);
|
|
857
|
+
else if (/^(uint|uint32)$/.test(type)) value = view.getUint32(offset2, little);
|
|
858
|
+
else if (/^(int|int32)$/.test(type)) value = view.getInt32(offset2, little);
|
|
859
|
+
else value = size === 4 ? view.getFloat32(offset2, little) : view.getFloat64(offset2, little);
|
|
860
|
+
offset2 += size;
|
|
861
|
+
if (!Number.isFinite(value)) invalid("PLY data contains invalid coordinates.");
|
|
862
|
+
return value;
|
|
863
|
+
};
|
|
864
|
+
for (const element of elements) for (let row = 0; row < element.count; row++) for (const property of element.properties) {
|
|
865
|
+
if (!property.item) {
|
|
866
|
+
scalar(property.type);
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
const count = scalar(property.type);
|
|
870
|
+
if (!Number.isInteger(count) || count < 0 || count > 4096) invalid("PLY list exceeds the bounded preview limit.");
|
|
871
|
+
if (element.name === "face") {
|
|
872
|
+
triangles += Math.max(0, count - 2);
|
|
873
|
+
if (triangles > MODEL3D_MAX_TRIANGLES) invalid("PLY exceeds the triangle preview limit.");
|
|
874
|
+
}
|
|
875
|
+
for (let item = 0; item < count; item++) {
|
|
876
|
+
const value = scalar(property.item);
|
|
877
|
+
if (element.name === "face" && (!Number.isInteger(value) || value < 0 || value >= vertices)) invalid("PLY contains an invalid vertex index.");
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
async function parseModel3D(data, format) {
|
|
882
|
+
if (!["stl", "obj", "ply"].includes(format)) invalid("Supported 3D preview formats: STL, OBJ and PLY.");
|
|
883
|
+
preflight(data, format);
|
|
884
|
+
const THREE = await import("three");
|
|
885
|
+
const bytes = Uint8Array.from(data).buffer;
|
|
886
|
+
let object;
|
|
887
|
+
if (format === "obj") {
|
|
888
|
+
const { OBJLoader } = await import("three/addons/loaders/OBJLoader.js");
|
|
889
|
+
object = new OBJLoader().parse(new TextDecoder().decode(data));
|
|
890
|
+
} else {
|
|
891
|
+
const geometry = format === "stl" ? new (await import("three/addons/loaders/STLLoader.js")).STLLoader().parse(bytes) : new (await import("three/addons/loaders/PLYLoader.js")).PLYLoader().parse(bytes);
|
|
892
|
+
object = format === "ply" && !geometry.index ? new THREE.Points(geometry) : new THREE.Mesh(geometry);
|
|
893
|
+
}
|
|
894
|
+
const positions = [], triangles = [], segments = [];
|
|
895
|
+
const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
|
|
896
|
+
try {
|
|
897
|
+
object.updateMatrixWorld(true);
|
|
898
|
+
object.traverse((node) => {
|
|
899
|
+
const drawable = node;
|
|
900
|
+
if (!drawable.geometry) return;
|
|
901
|
+
const geometry = drawable.geometry, attribute = geometry.getAttribute("position");
|
|
902
|
+
if (!attribute || !attribute.count) return;
|
|
903
|
+
const base = positions.length / 3;
|
|
904
|
+
if (base + attribute.count > MODEL3D_MAX_VERTICES) invalid("Decoded geometry exceeds the 750,000 vertex preview limit.");
|
|
905
|
+
const point = new THREE.Vector3();
|
|
906
|
+
for (let i = 0; i < attribute.count; i++) {
|
|
907
|
+
point.set(attribute.getX(i), attribute.getY(i), attribute.getZ(i)).applyMatrix4(node.matrixWorld);
|
|
908
|
+
const values = [point.x, point.y, point.z];
|
|
909
|
+
if (values.some((value) => !Number.isFinite(value) || Math.abs(value) > 1e30)) invalid("3D geometry contains invalid coordinates.");
|
|
910
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
911
|
+
min[axis] = Math.min(min[axis], values[axis]);
|
|
912
|
+
max[axis] = Math.max(max[axis], values[axis]);
|
|
913
|
+
}
|
|
914
|
+
positions.push(...values);
|
|
915
|
+
}
|
|
916
|
+
const count = geometry.index?.count ?? attribute.count;
|
|
917
|
+
const at = (index) => {
|
|
918
|
+
const value = geometry.index ? geometry.index.getX(index) : index;
|
|
919
|
+
if (!Number.isInteger(value) || value < 0 || value >= attribute.count) invalid("3D geometry contains an invalid vertex index.");
|
|
920
|
+
return base + value;
|
|
921
|
+
};
|
|
922
|
+
if (drawable.isMesh) {
|
|
923
|
+
if (count % 3 !== 0 || triangles.length / 3 + count / 3 > MODEL3D_MAX_TRIANGLES) invalid("Decoded geometry exceeds the triangle preview limit or is incomplete.");
|
|
924
|
+
for (let i = 0; i < count; i++) triangles.push(at(i));
|
|
925
|
+
} else if (drawable.isLineSegments) {
|
|
926
|
+
for (let i = 0; i + 1 < count; i += 2) segments.push(at(i), at(i + 1));
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
} finally {
|
|
930
|
+
object.traverse((node) => {
|
|
931
|
+
const drawable = node;
|
|
932
|
+
drawable.geometry?.dispose();
|
|
933
|
+
for (const material of Array.isArray(drawable.material) ? drawable.material : drawable.material ? [drawable.material] : []) material.dispose();
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
if (!positions.length) invalid("No renderable geometry was found.");
|
|
937
|
+
const center = min.map((value, axis) => (value + max[axis]) / 2);
|
|
938
|
+
const radius = Math.hypot(...min.map((value, axis) => max[axis] - value)) / 2 || 1;
|
|
939
|
+
for (let i = 0; i < positions.length; i++) positions[i] = (positions[i] - center[i % 3]) / radius;
|
|
940
|
+
return {
|
|
941
|
+
format,
|
|
942
|
+
positions: Float32Array.from(positions),
|
|
943
|
+
triangles: Uint32Array.from(triangles),
|
|
944
|
+
segments: Uint32Array.from(segments),
|
|
945
|
+
bounds: { min, max },
|
|
946
|
+
vertexCount: positions.length / 3,
|
|
947
|
+
triangleCount: triangles.length / 3,
|
|
948
|
+
warnings: format === "obj" ? ["Geometry preview only; external materials and textures are not loaded."] : []
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
function orbitModel3D(camera, dx, dy) {
|
|
952
|
+
return { ...camera, yaw: camera.yaw + dx * 0.06, pitch: Math.max(-1.5, Math.min(1.5, camera.pitch + dy * 0.06)) };
|
|
953
|
+
}
|
|
954
|
+
function zoomModel3D(camera, direction) {
|
|
955
|
+
return { ...camera, distance: Math.max(1.15, Math.min(30, camera.distance * Math.exp(direction * 0.16))) };
|
|
956
|
+
}
|
|
957
|
+
function fitModel3D(camera, aspect) {
|
|
958
|
+
const halfFov = Math.atan(Math.tan(Math.PI / 8) * Math.min(1, Math.max(0.05, aspect)));
|
|
959
|
+
return { ...camera, distance: 1.1 / Math.sin(halfFov) };
|
|
960
|
+
}
|
|
961
|
+
function model3DCameraPosition(camera) {
|
|
962
|
+
return [Math.sin(camera.yaw) * Math.cos(camera.pitch) * camera.distance, Math.sin(camera.pitch) * camera.distance, Math.cos(camera.yaw) * Math.cos(camera.pitch) * camera.distance];
|
|
963
|
+
}
|
|
964
|
+
function model3DWireEdges(model) {
|
|
965
|
+
const edges = Array.from(model.segments), seen = /* @__PURE__ */ new Set();
|
|
966
|
+
for (let i = 0; i < model.triangles.length; i += 3) for (const [a, b] of [[model.triangles[i], model.triangles[i + 1]], [model.triangles[i + 1], model.triangles[i + 2]], [model.triangles[i + 2], model.triangles[i]]]) {
|
|
967
|
+
const key = a < b ? `${a}:${b}` : `${b}:${a}`;
|
|
968
|
+
if (!seen.has(key)) {
|
|
969
|
+
seen.add(key);
|
|
970
|
+
edges.push(a, b);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return Uint32Array.from(edges);
|
|
974
|
+
}
|
|
975
|
+
function projectModel3DWireframe(model, camera, width, height, edges = model3DWireEdges(model)) {
|
|
976
|
+
width = Math.max(1, Math.min(240, Math.floor(width)));
|
|
977
|
+
height = Math.max(1, Math.min(80, Math.floor(height)));
|
|
978
|
+
const cells = Array.from({ length: height }, () => Array(width).fill(" "));
|
|
979
|
+
const sy = Math.sin(camera.yaw), cy = Math.cos(camera.yaw), sp = Math.sin(camera.pitch), cp = Math.cos(camera.pitch);
|
|
980
|
+
const aspect = width / (height * 2), focal = 1 / Math.tan(Math.PI / 8);
|
|
981
|
+
const project = (index) => {
|
|
982
|
+
const x = model.positions[index * 3], y = model.positions[index * 3 + 1], z = model.positions[index * 3 + 2];
|
|
983
|
+
const rx = cy * x - sy * z, rz = sy * x + cy * z, ry = cp * y - sp * rz, depth = camera.distance - (sp * y + cp * rz);
|
|
984
|
+
if (depth <= 0.05) return;
|
|
985
|
+
return [(0.5 + rx / depth * focal / aspect / 2) * (width - 1), (0.5 - ry / depth * focal / 2) * (height - 1)];
|
|
986
|
+
};
|
|
987
|
+
const plot = (x, y) => {
|
|
988
|
+
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = "·";
|
|
989
|
+
};
|
|
990
|
+
const totalEdges = edges.length / 2, stride = Math.max(1, Math.ceil(totalEdges / MODEL3D_MAX_WIREFRAME_EDGES));
|
|
991
|
+
let displayedEdges = 0;
|
|
992
|
+
for (let i = 0; i < totalEdges; i += stride) {
|
|
993
|
+
const a = project(edges[i * 2]), b = project(edges[i * 2 + 1]);
|
|
994
|
+
if (!a || !b) continue;
|
|
995
|
+
const steps = Math.min(width + height, Math.max(Math.abs(a[0] - b[0]), Math.abs(a[1] - b[1]), 1));
|
|
996
|
+
for (let step = 0; step <= steps; step++) plot(Math.round(a[0] + (b[0] - a[0]) * step / steps), Math.round(a[1] + (b[1] - a[1]) * step / steps));
|
|
997
|
+
displayedEdges++;
|
|
998
|
+
}
|
|
999
|
+
if (!totalEdges) for (let i = 0; i < model.vertexCount; i += Math.max(1, Math.ceil(model.vertexCount / MODEL3D_MAX_WIREFRAME_EDGES))) {
|
|
1000
|
+
const p = project(i);
|
|
1001
|
+
if (p) plot(Math.round(p[0]), Math.round(p[1]));
|
|
1002
|
+
}
|
|
1003
|
+
return { text: cells.map((row) => row.join("")).join("\n"), displayedEdges, totalEdges };
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// packages/cli/src/tui/native/components/model3d.ts
|
|
1007
|
+
async function createEngine(renderer2, width, height, background2) {
|
|
1008
|
+
if (!process.versions["bun"] || !(process.platform === "linux" && process.arch === "x64" || process.platform === "darwin" || process.platform === "win32" && process.arch === "x64")) throw new Error("WebGPU is not packaged for this runtime.");
|
|
1009
|
+
const packageName = "@opentui/three";
|
|
1010
|
+
const { ThreeCliRenderer, SuperSampleType } = await import(packageName);
|
|
1011
|
+
return new ThreeCliRenderer(renderer2, { width, height, autoResize: false, superSample: SuperSampleType.CPU, alpha: true, backgroundColor: RGBA2.fromValues(background2.r, background2.g, background2.b, 0) });
|
|
1012
|
+
}
|
|
1013
|
+
async function readCapture(path) {
|
|
1014
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
1015
|
+
try {
|
|
1016
|
+
const before = await file.stat();
|
|
1017
|
+
if (!before.isFile() || before.size <= 0 || before.size > MODEL3D_MAX_BYTES) throw new Error("3D preview requires a regular file up to 16 MiB.");
|
|
1018
|
+
const bytes = Buffer.alloc(before.size);
|
|
1019
|
+
let length = 0;
|
|
1020
|
+
while (length < bytes.length) {
|
|
1021
|
+
const read = await file.read(bytes, length, bytes.length - length, null);
|
|
1022
|
+
if (!read.bytesRead) break;
|
|
1023
|
+
length += read.bytesRead;
|
|
1024
|
+
}
|
|
1025
|
+
const extra = await file.read(Buffer.alloc(1), 0, 1, null), after = await file.stat();
|
|
1026
|
+
if (length !== bytes.length || extra.bytesRead) throw new Error("The captured model changed while being read.");
|
|
1027
|
+
if (bytes.length !== before.size || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeMs !== after.mtimeMs) throw new Error("The captured model changed while being read.");
|
|
1028
|
+
return bytes;
|
|
1029
|
+
} finally {
|
|
1030
|
+
await file.close();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
var NativeModel3DView = class extends BoxRenderable2 {
|
|
1034
|
+
constructor(renderer2, modelId, spec, colors, options = {}) {
|
|
1035
|
+
super(renderer2, { id: `model3d:${modelId}`, width: "100%", flexDirection: "column", flexShrink: 0, shouldFill: false });
|
|
1036
|
+
this.renderer = renderer2;
|
|
1037
|
+
this.modelId = modelId;
|
|
1038
|
+
this.colors = colors;
|
|
1039
|
+
this.options = options;
|
|
1040
|
+
this.spec = spec;
|
|
1041
|
+
let resolveClosed;
|
|
1042
|
+
this.closed = new Promise((resolve2) => {
|
|
1043
|
+
resolveClosed = resolve2;
|
|
1044
|
+
});
|
|
1045
|
+
this.resolveClosed = resolveClosed;
|
|
1046
|
+
this.location = new TextRenderable2(renderer2, { id: `model3d-location:${modelId}`, width: "100%", wrapMode: "word", fg: colors.dim, content: plainText(spec.displayName ?? spec.path), selectable: true });
|
|
1047
|
+
this.status = new TextRenderable2(renderer2, { id: `model3d-status:${modelId}`, width: "100%", wrapMode: "word", fg: colors.dim, content: "Loading 3D geometry…", selectable: true });
|
|
1048
|
+
const pointer = {
|
|
1049
|
+
onMouseDown: (event) => {
|
|
1050
|
+
if (event.button === 0) {
|
|
1051
|
+
event.currentTarget?.focus();
|
|
1052
|
+
this.drag = { x: event.x, y: event.y };
|
|
1053
|
+
event.stopPropagation();
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
onMouseDrag: (event) => {
|
|
1057
|
+
if (this.drag) {
|
|
1058
|
+
this.cameraState = orbitModel3D(this.cameraState, event.x - this.drag.x, event.y - this.drag.y);
|
|
1059
|
+
this.drag = { x: event.x, y: event.y };
|
|
1060
|
+
this.changed();
|
|
1061
|
+
event.stopPropagation();
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
onMouseDragEnd: () => {
|
|
1065
|
+
this.drag = void 0;
|
|
1066
|
+
},
|
|
1067
|
+
onMouseUp: () => {
|
|
1068
|
+
this.drag = void 0;
|
|
1069
|
+
},
|
|
1070
|
+
onMouseScroll: (event) => {
|
|
1071
|
+
if (event.scroll?.direction === "up" || event.scroll?.direction === "down") {
|
|
1072
|
+
this.zoom(event.scroll.direction === "up" ? -1 : 1);
|
|
1073
|
+
event.preventDefault();
|
|
1074
|
+
event.stopPropagation();
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
onKeyDown: (key) => {
|
|
1078
|
+
this.handleKey(key);
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
this.cpu = new TextRenderable2(renderer2, { id: `model3d-cpu:${modelId}`, width: "100%", height: 12, flexShrink: 0, wrapMode: "none", content: "", fg: colors.accent, selectable: false, ...pointer });
|
|
1082
|
+
this.cpu.focusable = true;
|
|
1083
|
+
this.surface = new FrameBufferRenderable(renderer2, {
|
|
1084
|
+
id: `model3d-surface:${modelId}`,
|
|
1085
|
+
width: 1,
|
|
1086
|
+
height: 12,
|
|
1087
|
+
flexShrink: 0,
|
|
1088
|
+
visible: false,
|
|
1089
|
+
respectAlpha: true,
|
|
1090
|
+
onSizeChange: () => {
|
|
1091
|
+
this.dirty = true;
|
|
1092
|
+
if (!this.closing) this.renderer.requestRender();
|
|
1093
|
+
},
|
|
1094
|
+
...pointer
|
|
1095
|
+
});
|
|
1096
|
+
this.surface.focusable = true;
|
|
1097
|
+
this.controls = new BoxRenderable2(renderer2, { id: `model3d-controls:${modelId}`, width: "100%", flexDirection: "row", flexWrap: "wrap", gap: 2, flexShrink: 0 });
|
|
1098
|
+
for (const [id, label3, action] of [
|
|
1099
|
+
["fit", "Fit", () => this.fit()],
|
|
1100
|
+
["reset", "Reset", () => this.reset()],
|
|
1101
|
+
["in", "Zoom +", () => this.zoom(-1)],
|
|
1102
|
+
["out", "Zoom −", () => this.zoom(1)]
|
|
1103
|
+
]) {
|
|
1104
|
+
const control = new TextRenderable2(renderer2, {
|
|
1105
|
+
id: `model3d-control:${modelId}:${id}`,
|
|
1106
|
+
content: label3,
|
|
1107
|
+
fg: colors.foreground,
|
|
1108
|
+
selectable: false,
|
|
1109
|
+
onMouseDown: (event) => {
|
|
1110
|
+
if (event.button === 0) {
|
|
1111
|
+
action();
|
|
1112
|
+
event.stopPropagation();
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
onKeyDown: (key) => {
|
|
1116
|
+
if (key.eventType !== "release" && (key.name === "return" || key.sequence === " ")) {
|
|
1117
|
+
action();
|
|
1118
|
+
key.preventDefault();
|
|
1119
|
+
key.stopPropagation();
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
control.focusable = true;
|
|
1124
|
+
this.controls.add(control);
|
|
1125
|
+
}
|
|
1126
|
+
this.add(this.location);
|
|
1127
|
+
this.add(this.cpu);
|
|
1128
|
+
this.add(this.surface);
|
|
1129
|
+
this.add(this.status);
|
|
1130
|
+
this.add(this.controls);
|
|
1131
|
+
this.hints = new TextRenderable2(renderer2, { id: `model3d-hints:${modelId}`, content: "Drag / arrows: orbit · wheel / + −: zoom · F: fit · R: reset", width: "100%", wrapMode: "word", fg: colors.dim });
|
|
1132
|
+
this.add(this.hints);
|
|
1133
|
+
renderer2.setFrameCallback(this.frame);
|
|
1134
|
+
}
|
|
1135
|
+
renderer;
|
|
1136
|
+
modelId;
|
|
1137
|
+
colors;
|
|
1138
|
+
options;
|
|
1139
|
+
spec;
|
|
1140
|
+
cameraState = initialModel3DCamera();
|
|
1141
|
+
location;
|
|
1142
|
+
status;
|
|
1143
|
+
cpu;
|
|
1144
|
+
surface;
|
|
1145
|
+
controls;
|
|
1146
|
+
hints;
|
|
1147
|
+
model;
|
|
1148
|
+
edges;
|
|
1149
|
+
scene;
|
|
1150
|
+
camera;
|
|
1151
|
+
engine;
|
|
1152
|
+
loading;
|
|
1153
|
+
drawing;
|
|
1154
|
+
cleanup;
|
|
1155
|
+
/** Bounded local diagnostic; a failed preview cleanup must not kill its TUI. */
|
|
1156
|
+
cleanupDiagnostic;
|
|
1157
|
+
resolveClosed;
|
|
1158
|
+
closed;
|
|
1159
|
+
closing = false;
|
|
1160
|
+
active = false;
|
|
1161
|
+
dirty = true;
|
|
1162
|
+
epoch = 0;
|
|
1163
|
+
pixelWidth = 0;
|
|
1164
|
+
pixelHeight = 0;
|
|
1165
|
+
drag;
|
|
1166
|
+
mode = "loading";
|
|
1167
|
+
frame = async () => {
|
|
1168
|
+
this.draw();
|
|
1169
|
+
};
|
|
1170
|
+
update(spec) {
|
|
1171
|
+
if (spec.path !== this.spec.path || spec.format !== this.spec.format) return;
|
|
1172
|
+
this.spec = spec;
|
|
1173
|
+
this.location.content = plainText(spec.displayName ?? spec.path);
|
|
1174
|
+
}
|
|
1175
|
+
applyTheme(colors) {
|
|
1176
|
+
this.colors = colors;
|
|
1177
|
+
this.location.fg = colors.dim;
|
|
1178
|
+
this.status.fg = colors.dim;
|
|
1179
|
+
this.cpu.fg = colors.accent;
|
|
1180
|
+
for (const child of this.controls.getChildren()) if (child instanceof TextRenderable2) child.fg = colors.foreground;
|
|
1181
|
+
this.changed();
|
|
1182
|
+
}
|
|
1183
|
+
async load() {
|
|
1184
|
+
const epoch = this.epoch;
|
|
1185
|
+
try {
|
|
1186
|
+
const bytes = await readCapture(this.spec.path);
|
|
1187
|
+
if (this.closing || epoch !== this.epoch) return;
|
|
1188
|
+
const model = await parseModel3D(bytes, this.spec.format);
|
|
1189
|
+
if (this.closing || epoch !== this.epoch) return;
|
|
1190
|
+
this.model = model;
|
|
1191
|
+
this.edges = model3DWireEdges(model);
|
|
1192
|
+
this.mode = "cpu";
|
|
1193
|
+
this.fit();
|
|
1194
|
+
if ((this.options.mode ?? process.env["OMNIUS_TUI_3D_RENDERER"]) !== "cpu") {
|
|
1195
|
+
try {
|
|
1196
|
+
const THREE = await import("three");
|
|
1197
|
+
if (this.closing) return;
|
|
1198
|
+
this.scene = new THREE.Scene();
|
|
1199
|
+
this.camera = new THREE.PerspectiveCamera(45, 1, 0.01, 100);
|
|
1200
|
+
this.scene.add(new THREE.HemisphereLight(16777215, 2631720, 2));
|
|
1201
|
+
const light = new THREE.DirectionalLight(16777215, 2);
|
|
1202
|
+
light.position.set(3, 4, 5);
|
|
1203
|
+
this.scene.add(light);
|
|
1204
|
+
const geometry = new THREE.BufferGeometry();
|
|
1205
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(model.positions, 3));
|
|
1206
|
+
if (model.triangleCount) {
|
|
1207
|
+
geometry.setIndex(new THREE.BufferAttribute(model.triangles, 1));
|
|
1208
|
+
geometry.computeVertexNormals();
|
|
1209
|
+
this.scene.add(new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 12369084, roughness: 0.75, metalness: 0.05, side: THREE.DoubleSide })));
|
|
1210
|
+
} else if (model.segments.length) {
|
|
1211
|
+
geometry.setIndex(new THREE.BufferAttribute(model.segments, 1));
|
|
1212
|
+
this.scene.add(new THREE.LineSegments(geometry, new THREE.LineBasicMaterial({ color: 12369084 })));
|
|
1213
|
+
} else this.scene.add(new THREE.Points(geometry, new THREE.PointsMaterial({ color: 12369084, size: 0.025 })));
|
|
1214
|
+
this.engine = this.options.createEngine ? await this.options.createEngine(this.renderer, Math.max(1, this.pixelWidth), Math.max(1, this.pixelHeight)) : await createEngine(this.renderer, Math.max(1, this.pixelWidth), Math.max(1, this.pixelHeight), this.colors.background);
|
|
1215
|
+
await this.engine.init();
|
|
1216
|
+
if (this.closing) return;
|
|
1217
|
+
this.engine.setActiveCamera(this.camera);
|
|
1218
|
+
this.mode = "webgpu";
|
|
1219
|
+
this.surface.visible = true;
|
|
1220
|
+
this.cpu.visible = false;
|
|
1221
|
+
} catch {
|
|
1222
|
+
this.releaseScene();
|
|
1223
|
+
this.engine?.destroy();
|
|
1224
|
+
this.engine = void 0;
|
|
1225
|
+
this.mode = "cpu";
|
|
1226
|
+
}
|
|
1227
|
+
} else this.mode = "cpu";
|
|
1228
|
+
if (!this.closing) this.changed();
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
if (!this.closing) {
|
|
1231
|
+
this.mode = "error";
|
|
1232
|
+
this.status.content = `3D preview unavailable · ${plainText(error instanceof Error ? error.message : "Unable to read model").slice(0, 200)}`;
|
|
1233
|
+
this.renderer.requestRender();
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
reconcile(viewport, active = true) {
|
|
1238
|
+
if (this.closing || this.isDestroyed) return;
|
|
1239
|
+
let ancestor = this;
|
|
1240
|
+
while (ancestor && active) {
|
|
1241
|
+
active = ancestor.visible;
|
|
1242
|
+
ancestor = ancestor.parent;
|
|
1243
|
+
}
|
|
1244
|
+
this.active = active && this.y + this.height > viewport.y && this.y < viewport.y + viewport.height;
|
|
1245
|
+
if (!this.active) return;
|
|
1246
|
+
const chrome = [this.location, this.status, this.controls, this.hints].reduce((rows, node) => rows + (node.visible ? Math.max(1, node.height) : 0), 0);
|
|
1247
|
+
const width = Math.max(1, Math.min(240, Math.floor(this.width))), height = Math.max(3, Math.min(30, this.renderer.terminalHeight - 7 - chrome));
|
|
1248
|
+
if (width !== this.pixelWidth || height !== this.pixelHeight) {
|
|
1249
|
+
this.pixelWidth = width;
|
|
1250
|
+
this.pixelHeight = height;
|
|
1251
|
+
this.cpu.height = height;
|
|
1252
|
+
this.surface.width = width;
|
|
1253
|
+
this.surface.height = height;
|
|
1254
|
+
this.changed();
|
|
1255
|
+
}
|
|
1256
|
+
if (!this.loading && !this.model && this.mode !== "error") this.loading = this.load();
|
|
1257
|
+
if (this.dirty) this.draw();
|
|
1258
|
+
}
|
|
1259
|
+
changed() {
|
|
1260
|
+
this.dirty = true;
|
|
1261
|
+
if (!this.closing) {
|
|
1262
|
+
this.draw();
|
|
1263
|
+
this.renderer.requestRender();
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
draw() {
|
|
1267
|
+
if (!this.active || !this.dirty || !this.model || this.closing || this.drawing) return;
|
|
1268
|
+
this.dirty = false;
|
|
1269
|
+
const model = this.model, width = Math.max(1, this.pixelWidth), height = Math.max(1, this.pixelHeight);
|
|
1270
|
+
const stats = `${model.vertexCount.toLocaleString("en-US")} ${model.vertexCount === 1 ? "vertex" : "vertices"} · ${model.triangleCount.toLocaleString("en-US")} ${model.triangleCount === 1 ? "triangle" : "triangles"}`;
|
|
1271
|
+
if (this.mode === "cpu") {
|
|
1272
|
+
const frame = projectModel3DWireframe(model, this.cameraState, width, height, this.edges);
|
|
1273
|
+
this.cpu.visible = true;
|
|
1274
|
+
this.surface.visible = false;
|
|
1275
|
+
this.cpu.content = frame.text;
|
|
1276
|
+
this.status.content = `CPU wireframe · ${stats}${frame.displayedEdges < frame.totalEdges ? ` · ${frame.displayedEdges}/${frame.totalEdges} edges sampled` : ""}${model.warnings.length ? `
|
|
1277
|
+
${model.warnings.join(" ")}` : ""}`;
|
|
1278
|
+
} else if (this.mode === "webgpu" && this.engine && this.scene && this.camera) {
|
|
1279
|
+
this.camera.aspect = width / (height * 2);
|
|
1280
|
+
this.camera.position.set(...model3DCameraPosition(this.cameraState));
|
|
1281
|
+
this.camera.lookAt(0, 0, 0);
|
|
1282
|
+
this.camera.updateProjectionMatrix();
|
|
1283
|
+
this.status.content = `WebGPU · ${stats}${model.warnings.length ? `
|
|
1284
|
+
${model.warnings.join(" ")}` : ""}`;
|
|
1285
|
+
const staging = OptimizedBuffer.create(width, height, this.renderer.widthMethod, { owner: this.renderer.nativeScene, respectAlpha: true, id: `model3d-stage:${this.modelId}` });
|
|
1286
|
+
staging.clear(RGBA2.fromValues(0, 0, 0, 0));
|
|
1287
|
+
this.engine.setSize(width, height);
|
|
1288
|
+
this.drawing = this.engine.drawScene(this.scene, staging, 0).then(() => {
|
|
1289
|
+
if (!this.closing && !this.surface.isDestroyed && width === this.pixelWidth && height === this.pixelHeight) {
|
|
1290
|
+
this.surface.frameBuffer.clear(RGBA2.fromValues(0, 0, 0, 0));
|
|
1291
|
+
this.surface.frameBuffer.drawFrameBuffer(0, 0, staging);
|
|
1292
|
+
} else if (!this.closing) this.dirty = true;
|
|
1293
|
+
}).catch(() => {
|
|
1294
|
+
if (!this.closing) {
|
|
1295
|
+
this.releaseScene();
|
|
1296
|
+
this.engine?.destroy();
|
|
1297
|
+
this.engine = void 0;
|
|
1298
|
+
this.mode = "cpu";
|
|
1299
|
+
this.dirty = true;
|
|
1300
|
+
}
|
|
1301
|
+
}).finally(() => {
|
|
1302
|
+
staging.destroy();
|
|
1303
|
+
this.drawing = void 0;
|
|
1304
|
+
if (!this.closing) {
|
|
1305
|
+
this.draw();
|
|
1306
|
+
this.renderer.requestRender();
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
fit() {
|
|
1312
|
+
this.cameraState = fitModel3D(this.cameraState, Math.max(1, this.pixelWidth) / (Math.max(1, this.pixelHeight) * 2));
|
|
1313
|
+
this.changed();
|
|
1314
|
+
}
|
|
1315
|
+
reset() {
|
|
1316
|
+
this.cameraState = initialModel3DCamera();
|
|
1317
|
+
this.fit();
|
|
1318
|
+
}
|
|
1319
|
+
zoom(direction) {
|
|
1320
|
+
this.cameraState = zoomModel3D(this.cameraState, direction);
|
|
1321
|
+
this.changed();
|
|
1322
|
+
}
|
|
1323
|
+
handleKey(key) {
|
|
1324
|
+
if (!this.active || this.closing || key.eventType === "release") return false;
|
|
1325
|
+
let focused = this.renderer.currentFocusedRenderable;
|
|
1326
|
+
while (focused && focused !== this) focused = focused.parent;
|
|
1327
|
+
if (focused !== this) return false;
|
|
1328
|
+
if (["left", "right", "up", "down"].includes(key.name)) this.cameraState = orbitModel3D(this.cameraState, key.name === "left" ? -1 : key.name === "right" ? 1 : 0, key.name === "up" ? -1 : key.name === "down" ? 1 : 0);
|
|
1329
|
+
else if (key.sequence === "+" || key.sequence === "=" || key.sequence === "-") this.zoom(key.sequence === "-" ? 1 : -1);
|
|
1330
|
+
else if (key.name === "f") this.fit();
|
|
1331
|
+
else if (key.name === "r") this.reset();
|
|
1332
|
+
else return false;
|
|
1333
|
+
this.changed();
|
|
1334
|
+
key.preventDefault();
|
|
1335
|
+
key.stopPropagation();
|
|
1336
|
+
return true;
|
|
1337
|
+
}
|
|
1338
|
+
pauseRendering() {
|
|
1339
|
+
this.active = false;
|
|
1340
|
+
this.drag = void 0;
|
|
1341
|
+
}
|
|
1342
|
+
releaseScene() {
|
|
1343
|
+
const scene = this.scene;
|
|
1344
|
+
this.scene = void 0;
|
|
1345
|
+
this.camera = void 0;
|
|
1346
|
+
scene?.traverse((node) => {
|
|
1347
|
+
const mesh = node;
|
|
1348
|
+
mesh.geometry?.dispose();
|
|
1349
|
+
for (const material of Array.isArray(mesh.material) ? mesh.material : mesh.material ? [mesh.material] : []) material.dispose();
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
dispose() {
|
|
1353
|
+
if (this.cleanup) return this.cleanup;
|
|
1354
|
+
this.closing = true;
|
|
1355
|
+
this.active = false;
|
|
1356
|
+
this.epoch++;
|
|
1357
|
+
this.renderer.removeFrameCallback(this.frame);
|
|
1358
|
+
this.cleanup = (async () => {
|
|
1359
|
+
try {
|
|
1360
|
+
await this.loading;
|
|
1361
|
+
await this.drawing;
|
|
1362
|
+
} finally {
|
|
1363
|
+
try {
|
|
1364
|
+
this.releaseScene();
|
|
1365
|
+
} finally {
|
|
1366
|
+
try {
|
|
1367
|
+
this.engine?.destroy();
|
|
1368
|
+
} finally {
|
|
1369
|
+
this.engine = void 0;
|
|
1370
|
+
this.model = void 0;
|
|
1371
|
+
this.edges = void 0;
|
|
1372
|
+
this.resolveClosed();
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
})().catch((error) => {
|
|
1377
|
+
this.cleanupDiagnostic = plainText(error instanceof Error ? error.message : "3D preview cleanup failed").slice(0, 200);
|
|
1378
|
+
});
|
|
1379
|
+
return this.cleanup;
|
|
1380
|
+
}
|
|
1381
|
+
destroySelf() {
|
|
1382
|
+
void this.dispose();
|
|
1383
|
+
super.destroySelf();
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
|
|
741
1387
|
// packages/cli/src/tui/native/components/code.ts
|
|
742
1388
|
var aliases = {
|
|
743
1389
|
js: "javascript",
|
|
@@ -972,7 +1618,7 @@ var NativeBlockView = class {
|
|
|
972
1618
|
this.inline = inline;
|
|
973
1619
|
this.spec = spec;
|
|
974
1620
|
this.pixel = inline && spec.kind === "text" && Boolean(spec.actions?.length) && spec.actions.every((action) => action.id.startsWith("pixel:"));
|
|
975
|
-
this.root = new
|
|
1621
|
+
this.root = new BoxRenderable3(context.renderer, {
|
|
976
1622
|
id: `block:${spec.id}`,
|
|
977
1623
|
flexDirection: "column",
|
|
978
1624
|
flexShrink: inline && !this.pixel ? 1 : 0,
|
|
@@ -997,6 +1643,7 @@ var NativeBlockView = class {
|
|
|
997
1643
|
progress;
|
|
998
1644
|
image;
|
|
999
1645
|
media;
|
|
1646
|
+
model3d;
|
|
1000
1647
|
terminal;
|
|
1001
1648
|
collapsed = false;
|
|
1002
1649
|
previousModelCollapsed;
|
|
@@ -1016,7 +1663,7 @@ var NativeBlockView = class {
|
|
|
1016
1663
|
this.root.marginBottom = 0;
|
|
1017
1664
|
this.root.flexDirection = spec.kind === "row" ? "row" : "column";
|
|
1018
1665
|
if (spec.title) {
|
|
1019
|
-
this.title = new
|
|
1666
|
+
this.title = new TextRenderable3(renderer2, {
|
|
1020
1667
|
id: `block-title:${spec.id}`,
|
|
1021
1668
|
content: "",
|
|
1022
1669
|
fg: colors.foreground,
|
|
@@ -1040,7 +1687,7 @@ var NativeBlockView = class {
|
|
|
1040
1687
|
nativeControlFocus(this.title, 1);
|
|
1041
1688
|
this.root.add(this.title);
|
|
1042
1689
|
}
|
|
1043
|
-
this.body = new
|
|
1690
|
+
this.body = new BoxRenderable3(renderer2, {
|
|
1044
1691
|
id: `block-body:${spec.id}`,
|
|
1045
1692
|
flexDirection: spec.kind === "row" ? "row" : "column",
|
|
1046
1693
|
width: this.pixel ? "auto" : "100%",
|
|
@@ -1064,6 +1711,10 @@ var NativeBlockView = class {
|
|
|
1064
1711
|
this.media = new NativeMediaView(renderer2, spec.id, spec.media, colors, this.context.emit);
|
|
1065
1712
|
this.context.mediaViews?.add(this.media);
|
|
1066
1713
|
this.body.add(this.media);
|
|
1714
|
+
} else if (spec.kind === "model3d" && spec.model3d) {
|
|
1715
|
+
this.model3d = new NativeModel3DView(renderer2, spec.id, spec.model3d, colors);
|
|
1716
|
+
this.context.modelViews?.add(this.model3d);
|
|
1717
|
+
this.body.add(this.model3d);
|
|
1067
1718
|
} else if (spec.kind === "image" && spec.imagePath) {
|
|
1068
1719
|
this.image = new ImageRenderable2(renderer2, {
|
|
1069
1720
|
id: `image:${spec.id}`,
|
|
@@ -1076,7 +1727,7 @@ var NativeBlockView = class {
|
|
|
1076
1727
|
if (this.image) this.image.visible = false;
|
|
1077
1728
|
if (this.text) {
|
|
1078
1729
|
this.text.visible = true;
|
|
1079
|
-
if (this.text instanceof
|
|
1730
|
+
if (this.text instanceof TextRenderable3) this.text.content = styledText(this.spec.text ?? "Image unavailable");
|
|
1080
1731
|
}
|
|
1081
1732
|
this.context.emit({ type: "action", action: "image-error", id: spec.id, text: String(error) });
|
|
1082
1733
|
},
|
|
@@ -1086,7 +1737,7 @@ var NativeBlockView = class {
|
|
|
1086
1737
|
}
|
|
1087
1738
|
});
|
|
1088
1739
|
this.body.add(this.image);
|
|
1089
|
-
this.text = new
|
|
1740
|
+
this.text = new TextRenderable3(renderer2, { id: `image-fallback:${spec.id}`, content: "", visible: false, width: "100%", wrapMode: "word", fg: colors.dim, selectable: true });
|
|
1090
1741
|
this.body.add(this.text);
|
|
1091
1742
|
} else if (spec.kind === "markdown") {
|
|
1092
1743
|
this.text = new MarkdownRenderable(renderer2, {
|
|
@@ -1144,7 +1795,7 @@ var NativeBlockView = class {
|
|
|
1144
1795
|
});
|
|
1145
1796
|
this.body.add(this.text);
|
|
1146
1797
|
} else if (spec.text !== void 0) {
|
|
1147
|
-
this.text = new
|
|
1798
|
+
this.text = new TextRenderable3(renderer2, {
|
|
1148
1799
|
id: `text:${spec.id}`,
|
|
1149
1800
|
content: "",
|
|
1150
1801
|
width: this.pixel ? "auto" : "100%",
|
|
@@ -1157,7 +1808,7 @@ var NativeBlockView = class {
|
|
|
1157
1808
|
this.body.add(this.text);
|
|
1158
1809
|
}
|
|
1159
1810
|
if (spec.kind === "progress") {
|
|
1160
|
-
this.progress = new
|
|
1811
|
+
this.progress = new TextRenderable3(renderer2, {
|
|
1161
1812
|
id: `progress-track:${spec.id}`,
|
|
1162
1813
|
width: "100%",
|
|
1163
1814
|
height: 1,
|
|
@@ -1171,7 +1822,7 @@ var NativeBlockView = class {
|
|
|
1171
1822
|
this.body.add(this.progress);
|
|
1172
1823
|
}
|
|
1173
1824
|
this.children = new NativeBlockList(this.context, this.body);
|
|
1174
|
-
this.actions = new
|
|
1825
|
+
this.actions = new BoxRenderable3(renderer2, {
|
|
1175
1826
|
id: `block-actions:${spec.id}`,
|
|
1176
1827
|
flexDirection: "row",
|
|
1177
1828
|
gap: 1,
|
|
@@ -1185,6 +1836,11 @@ var NativeBlockView = class {
|
|
|
1185
1836
|
this.media.destroy();
|
|
1186
1837
|
this.media = void 0;
|
|
1187
1838
|
}
|
|
1839
|
+
if (this.model3d) {
|
|
1840
|
+
this.context.modelViews?.delete(this.model3d);
|
|
1841
|
+
this.model3d.destroy();
|
|
1842
|
+
this.model3d = void 0;
|
|
1843
|
+
}
|
|
1188
1844
|
this.children?.destroy();
|
|
1189
1845
|
this.markdownSections?.destroy();
|
|
1190
1846
|
this.markdownSections = void 0;
|
|
@@ -1222,7 +1878,7 @@ var NativeBlockView = class {
|
|
|
1222
1878
|
this.markdownSections.destroy();
|
|
1223
1879
|
this.markdownSections = void 0;
|
|
1224
1880
|
}
|
|
1225
|
-
if (this.text instanceof
|
|
1881
|
+
if (this.text instanceof TextRenderable3) this.text.content = styledText(spec.kind === "image" ? spec.text ?? "Image unavailable" : spec.text);
|
|
1226
1882
|
else if (this.text instanceof MarkdownRenderable || this.text instanceof CodeRenderable) {
|
|
1227
1883
|
const code = this.text instanceof CodeRenderable ? nativeCodeContent(plainText(spec.text), spec.language) : void 0;
|
|
1228
1884
|
this.text.content = sections ? "" : code?.content ?? plainText(spec.text);
|
|
@@ -1231,6 +1887,7 @@ var NativeBlockView = class {
|
|
|
1231
1887
|
else keepMarkdownFallback(this.text);
|
|
1232
1888
|
}
|
|
1233
1889
|
if (this.media && spec.media) this.media.update(spec.media);
|
|
1890
|
+
if (this.model3d && spec.model3d) this.model3d.update(spec.model3d);
|
|
1234
1891
|
if (this.image && spec.imagePath && this.image.source !== spec.imagePath) this.image.source = spec.imagePath;
|
|
1235
1892
|
if (this.terminal) this.terminal.height = spec.height ?? 14;
|
|
1236
1893
|
if (this.image) this.image.height = spec.height ?? 12;
|
|
@@ -1241,7 +1898,7 @@ var NativeBlockView = class {
|
|
|
1241
1898
|
this.actionsSignature = actionsSignature;
|
|
1242
1899
|
for (const child of [...this.actions.getChildren()]) child.destroy();
|
|
1243
1900
|
for (const action of spec.actions ?? []) {
|
|
1244
|
-
const button = new
|
|
1901
|
+
const button = new TextRenderable3(this.context.renderer, {
|
|
1245
1902
|
id: `block-action:${spec.id}:${action.id}`,
|
|
1246
1903
|
content: plainText(action.label),
|
|
1247
1904
|
fg: this.context.colors.foreground,
|
|
@@ -1295,13 +1952,17 @@ var NativeBlockView = class {
|
|
|
1295
1952
|
applyTheme() {
|
|
1296
1953
|
const colors = this.context.colors;
|
|
1297
1954
|
this.root.backgroundColor = colors.background;
|
|
1955
|
+
this.root.shouldFill = this.spec.kind !== "model3d";
|
|
1298
1956
|
if (this.spec.kind === "card") this.root.borderColor = colors.border;
|
|
1299
1957
|
else this.root.border = false;
|
|
1300
1958
|
if (this.title) {
|
|
1301
1959
|
this.title.fg = colors.foreground;
|
|
1302
1960
|
this.title.bg = colors.background;
|
|
1303
1961
|
}
|
|
1304
|
-
if (this.body)
|
|
1962
|
+
if (this.body) {
|
|
1963
|
+
this.body.backgroundColor = colors.background;
|
|
1964
|
+
this.body.shouldFill = this.spec.kind !== "model3d";
|
|
1965
|
+
}
|
|
1305
1966
|
if (this.text) {
|
|
1306
1967
|
this.text.fg = colors.foreground;
|
|
1307
1968
|
this.text.bg = colors.background;
|
|
@@ -1310,11 +1971,12 @@ var NativeBlockView = class {
|
|
|
1310
1971
|
this.progress.fg = colors.foreground;
|
|
1311
1972
|
this.progress.bg = colors.background;
|
|
1312
1973
|
}
|
|
1313
|
-
for (const action of this.actions?.getChildren() ?? []) if (action instanceof
|
|
1974
|
+
for (const action of this.actions?.getChildren() ?? []) if (action instanceof TextRenderable3) {
|
|
1314
1975
|
action.fg = colors.foreground;
|
|
1315
1976
|
action.bg = colors.background;
|
|
1316
1977
|
}
|
|
1317
1978
|
this.media?.applyTheme(colors);
|
|
1979
|
+
this.model3d?.applyTheme(colors);
|
|
1318
1980
|
this.children?.applyTheme();
|
|
1319
1981
|
this.markdownSections?.applyTheme();
|
|
1320
1982
|
}
|
|
@@ -1324,6 +1986,11 @@ var NativeBlockView = class {
|
|
|
1324
1986
|
this.media.destroy();
|
|
1325
1987
|
this.media = void 0;
|
|
1326
1988
|
}
|
|
1989
|
+
if (this.model3d) {
|
|
1990
|
+
this.context.modelViews?.delete(this.model3d);
|
|
1991
|
+
this.model3d.destroy();
|
|
1992
|
+
this.model3d = void 0;
|
|
1993
|
+
}
|
|
1327
1994
|
this.children?.destroy();
|
|
1328
1995
|
this.markdownSections?.destroy();
|
|
1329
1996
|
if (this.terminal) this.context.terminals.delete(this.spec.id);
|
|
@@ -1395,13 +2062,13 @@ var NativeBlockList = class {
|
|
|
1395
2062
|
|
|
1396
2063
|
// packages/cli/src/tui/native/components/modals.ts
|
|
1397
2064
|
import {
|
|
1398
|
-
BoxRenderable as
|
|
2065
|
+
BoxRenderable as BoxRenderable5,
|
|
1399
2066
|
CliRenderEvents as CliRenderEvents3,
|
|
1400
2067
|
InputRenderable,
|
|
1401
2068
|
ScrollBoxRenderable as ScrollBoxRenderable2,
|
|
1402
2069
|
TextareaRenderable,
|
|
1403
2070
|
TextAttributes as TextAttributes4,
|
|
1404
|
-
TextRenderable as
|
|
2071
|
+
TextRenderable as TextRenderable4
|
|
1405
2072
|
} from "@opentui/core";
|
|
1406
2073
|
|
|
1407
2074
|
// packages/cli/src/tui/native/components/select.ts
|
|
@@ -1554,7 +2221,7 @@ var NativeSelectRenderable = class extends SelectRenderable {
|
|
|
1554
2221
|
};
|
|
1555
2222
|
|
|
1556
2223
|
// packages/cli/src/tui/native/components/corner-frame.ts
|
|
1557
|
-
import { BoxRenderable as
|
|
2224
|
+
import { BoxRenderable as BoxRenderable4, CliRenderEvents as CliRenderEvents2, RenderableEvents as RenderableEvents2, TextAttributes as TextAttributes3 } from "@opentui/core";
|
|
1558
2225
|
function drawCornerFrame(buffer, panel, colors, progress = 1) {
|
|
1559
2226
|
const { x, y, width, height } = panel;
|
|
1560
2227
|
if (width <= 0 || height <= 0) return;
|
|
@@ -1593,7 +2260,7 @@ var NativeCornerFrame = class {
|
|
|
1593
2260
|
this.colors = colors;
|
|
1594
2261
|
this.renderer = renderer2;
|
|
1595
2262
|
this.container = container;
|
|
1596
|
-
this.chrome = new
|
|
2263
|
+
this.chrome = new BoxRenderable4(renderer2, {
|
|
1597
2264
|
id: `${panel.id}:corners`,
|
|
1598
2265
|
position: "absolute",
|
|
1599
2266
|
left: 0,
|
|
@@ -1808,7 +2475,9 @@ function nativeModalWidth(spec, columns) {
|
|
|
1808
2475
|
const blockWidth = (block, depth) => {
|
|
1809
2476
|
if (depth > 16) return 0;
|
|
1810
2477
|
const children = (block.children ?? []).slice(0, 256).map((child) => blockWidth(child, depth + 1));
|
|
2478
|
+
const mediaWidth = block.kind === "model3d" ? 96 : block.kind === "media" ? block.media?.kind === "image" ? 96 : 64 : 0;
|
|
1811
2479
|
return Math.min(limit, Math.max(
|
|
2480
|
+
mediaWidth,
|
|
1812
2481
|
longest(plainText(block.text)),
|
|
1813
2482
|
longest(block.title ?? ""),
|
|
1814
2483
|
actions(block.actions),
|
|
@@ -1840,7 +2509,7 @@ var NativeModalView = class {
|
|
|
1840
2509
|
this.close = close2;
|
|
1841
2510
|
this.spec = spec;
|
|
1842
2511
|
const { renderer: renderer2, colors } = context;
|
|
1843
|
-
this.root = new
|
|
2512
|
+
this.root = new BoxRenderable5(renderer2, {
|
|
1844
2513
|
id: `modal:${spec.id}`,
|
|
1845
2514
|
position: "absolute",
|
|
1846
2515
|
top: 0,
|
|
@@ -1862,7 +2531,7 @@ var NativeModalView = class {
|
|
|
1862
2531
|
}
|
|
1863
2532
|
}
|
|
1864
2533
|
});
|
|
1865
|
-
this.panel = new
|
|
2534
|
+
this.panel = new BoxRenderable5(renderer2, {
|
|
1866
2535
|
id: `modal-panel:${spec.id}`,
|
|
1867
2536
|
flexDirection: "column",
|
|
1868
2537
|
width: nativeModalWidth(spec, renderer2.terminalWidth),
|
|
@@ -1892,10 +2561,10 @@ var NativeModalView = class {
|
|
|
1892
2561
|
this.panel.add(this.body);
|
|
1893
2562
|
styleNativeScrollbars(this.body, colors);
|
|
1894
2563
|
this.breadcrumb = this.addText(`modal-breadcrumb:${spec.id}`);
|
|
1895
|
-
const header = new
|
|
1896
|
-
this.heading = new
|
|
2564
|
+
const header = new BoxRenderable5(renderer2, { id: `modal-heading:${spec.id}`, width: "100%", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
2565
|
+
this.heading = new TextRenderable4(renderer2, { id: `modal-title:${spec.id}`, content: "", width: 0, flexGrow: 1, flexShrink: 1, wrapMode: "word", fg: colors.foreground });
|
|
1897
2566
|
this.heading.maxHeight = 2;
|
|
1898
|
-
this.headerActions = new
|
|
2567
|
+
this.headerActions = new BoxRenderable5(renderer2, { id: `modal-header-actions:${spec.id}`, flexDirection: "row", gap: 1, flexShrink: 1, minWidth: 0, maxWidth: "60%" });
|
|
1899
2568
|
header.add(this.heading);
|
|
1900
2569
|
header.add(this.headerActions);
|
|
1901
2570
|
this.panel.add(header, 0);
|
|
@@ -1904,11 +2573,11 @@ var NativeModalView = class {
|
|
|
1904
2573
|
else if (spec.kind === "input") this.buildInput();
|
|
1905
2574
|
else if (spec.kind === "document") {
|
|
1906
2575
|
this.document = this.body;
|
|
1907
|
-
const documentBlocks = new
|
|
2576
|
+
const documentBlocks = new BoxRenderable5(renderer2, { id: `modal-document-blocks:${spec.id}`, width: "100%", flexDirection: "column", flexShrink: 0 });
|
|
1908
2577
|
this.body.add(documentBlocks);
|
|
1909
2578
|
this.blocks = new NativeBlockList(this.modalContext(), documentBlocks);
|
|
1910
2579
|
} else {
|
|
1911
|
-
this.progress = new
|
|
2580
|
+
this.progress = new TextRenderable4(renderer2, {
|
|
1912
2581
|
id: `modal-progress:${spec.id}`,
|
|
1913
2582
|
width: "100%",
|
|
1914
2583
|
height: 1,
|
|
@@ -1920,15 +2589,16 @@ var NativeModalView = class {
|
|
|
1920
2589
|
selectable: false
|
|
1921
2590
|
});
|
|
1922
2591
|
this.body.add(this.progress);
|
|
1923
|
-
const progressBlocks = new
|
|
2592
|
+
const progressBlocks = new BoxRenderable5(renderer2, { id: `modal-progress-blocks:${spec.id}`, flexDirection: "column", width: "100%" });
|
|
1924
2593
|
this.body.add(progressBlocks);
|
|
1925
2594
|
this.blocks = new NativeBlockList(this.modalContext(), progressBlocks);
|
|
1926
2595
|
}
|
|
1927
2596
|
this.error = this.addText(`modal-error:${spec.id}`);
|
|
1928
2597
|
this.hints = this.addText(`modal-hints:${spec.id}`, this.panel);
|
|
1929
2598
|
this.hints.maxHeight = 2;
|
|
1930
|
-
this.actions = new
|
|
2599
|
+
this.actions = new BoxRenderable5(renderer2, { id: `modal-actions:${spec.id}`, flexDirection: "row", flexWrap: "wrap", flexShrink: 0, gap: 1, width: "100%", marginTop: 0 });
|
|
1931
2600
|
this.panel.add(this.actions);
|
|
2601
|
+
this.panel.renderBefore = this.paintModelChrome;
|
|
1932
2602
|
this.update(spec);
|
|
1933
2603
|
renderer2.on(CliRenderEvents3.RESIZE, this.fit);
|
|
1934
2604
|
this.panel.on("resize", this.fit);
|
|
@@ -1967,15 +2637,42 @@ var NativeModalView = class {
|
|
|
1967
2637
|
optionSignature = "";
|
|
1968
2638
|
disposed = false;
|
|
1969
2639
|
revealFocused = false;
|
|
2640
|
+
mediaViews = /* @__PURE__ */ new Set();
|
|
2641
|
+
modelViews = /* @__PURE__ */ new Set();
|
|
2642
|
+
transparentModel = false;
|
|
2643
|
+
paintModelChrome = (buffer) => {
|
|
2644
|
+
if (!this.transparentModel || this.disposed || this.frame.animating) return;
|
|
2645
|
+
const left = this.panel.x + 1, right = this.panel.x + this.panel.width - 1;
|
|
2646
|
+
const top = this.panel.y + 1, bottom = this.panel.y + this.panel.height - 1;
|
|
2647
|
+
if (right <= left || bottom <= top) return;
|
|
2648
|
+
const viewport = this.body.viewport;
|
|
2649
|
+
const canvases = [...this.modelViews].flatMap((model) => {
|
|
2650
|
+
const canvas = [model.findDescendantById(`model3d-surface:${model.modelId}`), model.findDescendantById(`model3d-cpu:${model.modelId}`)].find((node) => node?.visible && !node.isDestroyed);
|
|
2651
|
+
if (!canvas) return [];
|
|
2652
|
+
const x = Math.max(left, viewport.x, canvas.x), y = Math.max(top, viewport.y, canvas.y);
|
|
2653
|
+
const endX = Math.min(right, viewport.x + viewport.width, canvas.x + canvas.width);
|
|
2654
|
+
const endY = Math.min(bottom, viewport.y + viewport.height, canvas.y + canvas.height);
|
|
2655
|
+
return endX > x && endY > y ? [{ x, y, endX, endY }] : [];
|
|
2656
|
+
}).sort((a, b) => a.x - b.x);
|
|
2657
|
+
for (let y = top; y < bottom; y++) {
|
|
2658
|
+
let x = left;
|
|
2659
|
+
for (const canvas of canvases) {
|
|
2660
|
+
if (y < canvas.y || y >= canvas.endY) continue;
|
|
2661
|
+
if (canvas.x > x) buffer.fillRect(x, y, canvas.x - x, 1, this.context.colors.background);
|
|
2662
|
+
x = Math.max(x, canvas.endX);
|
|
2663
|
+
}
|
|
2664
|
+
if (right > x) buffer.fillRect(x, y, right - x, 1, this.context.colors.background);
|
|
2665
|
+
}
|
|
2666
|
+
};
|
|
1970
2667
|
addText(id, parent = this.body) {
|
|
1971
|
-
const text = new
|
|
2668
|
+
const text = new TextRenderable4(this.context.renderer, { id, content: "", width: "100%", wrapMode: "word", flexShrink: 0, fg: this.context.colors.foreground, selectable: true });
|
|
1972
2669
|
parent.add(text);
|
|
1973
2670
|
return text;
|
|
1974
2671
|
}
|
|
1975
2672
|
replaceActions(container, actions, prefix = "") {
|
|
1976
2673
|
for (const child of [...container.getChildren()]) child.destroy();
|
|
1977
2674
|
for (const action of actions) {
|
|
1978
|
-
const button = new
|
|
2675
|
+
const button = new TextRenderable4(this.context.renderer, {
|
|
1979
2676
|
id: `modal-action:${this.spec.id}:${prefix}${action.id}`,
|
|
1980
2677
|
content: plainText(action.label),
|
|
1981
2678
|
minWidth: 0,
|
|
@@ -2114,7 +2811,17 @@ var NativeModalView = class {
|
|
|
2114
2811
|
this.refreshMask();
|
|
2115
2812
|
this.refreshOptions(patch.selectedIndex);
|
|
2116
2813
|
this.blocks?.replace(spec.blocks ?? []);
|
|
2117
|
-
|
|
2814
|
+
const transparentModel = spec.kind === "document" && Boolean(spec.blocks?.some((block) => block.kind === "model3d"));
|
|
2815
|
+
if (transparentModel !== this.transparentModel) {
|
|
2816
|
+
for (const box of [this.body, this.body.wrapper, this.body.viewport, this.body.content, this.blocks?.parent])
|
|
2817
|
+
if (box instanceof BoxRenderable5) box.shouldFill = !transparentModel;
|
|
2818
|
+
this.frame.chrome.shouldFill = !transparentModel;
|
|
2819
|
+
this.transparentModel = transparentModel;
|
|
2820
|
+
}
|
|
2821
|
+
if (this.progress) {
|
|
2822
|
+
this.progress.visible = spec.progress !== null;
|
|
2823
|
+
this.progress.content = nativeProgressText(spec.progress ?? void 0, true);
|
|
2824
|
+
}
|
|
2118
2825
|
const headerActionsSignature = JSON.stringify(spec.headerActions ?? []);
|
|
2119
2826
|
if (headerActionsSignature !== this.headerActionsSignature) {
|
|
2120
2827
|
this.headerActionsSignature = headerActionsSignature;
|
|
@@ -2229,12 +2936,27 @@ var NativeModalView = class {
|
|
|
2229
2936
|
}
|
|
2230
2937
|
modalContext() {
|
|
2231
2938
|
const scoped = Object.create(this.context);
|
|
2939
|
+
scoped.mediaViews = this.mediaViews;
|
|
2940
|
+
scoped.modelViews = this.modelViews;
|
|
2232
2941
|
scoped.emit = (event) => {
|
|
2233
2942
|
if (event.type === "action") this.emitAction(event.action, event.id);
|
|
2234
2943
|
else this.context.emit(event);
|
|
2235
2944
|
};
|
|
2236
2945
|
return scoped;
|
|
2237
2946
|
}
|
|
2947
|
+
reconcileMedia(active) {
|
|
2948
|
+
for (const media of this.mediaViews) media.reconcile(this.body.viewport, active && !this.frame.closing);
|
|
2949
|
+
for (const model of this.modelViews) model.reconcile(this.body.viewport, active && !this.frame.closing);
|
|
2950
|
+
}
|
|
2951
|
+
pauseMedia() {
|
|
2952
|
+
return [...[...this.mediaViews].map((media) => {
|
|
2953
|
+
media.pausePlayback();
|
|
2954
|
+
return media.closed;
|
|
2955
|
+
}), ...[...this.modelViews].map((model) => {
|
|
2956
|
+
model.pauseRendering();
|
|
2957
|
+
return model.closed;
|
|
2958
|
+
})];
|
|
2959
|
+
}
|
|
2238
2960
|
emitAction(action, value) {
|
|
2239
2961
|
const current = this.current();
|
|
2240
2962
|
this.context.emit({ type: "modal-action", id: this.spec.id, action, key: current?.item.key, index: current?.index, value });
|
|
@@ -2307,7 +3029,8 @@ var NativeModalView = class {
|
|
|
2307
3029
|
return consume();
|
|
2308
3030
|
}
|
|
2309
3031
|
const focusedId = this.context.renderer.currentFocusedRenderable?.id ?? "";
|
|
2310
|
-
|
|
3032
|
+
for (const model of this.modelViews) if (model.handleKey(key)) return consume();
|
|
3033
|
+
if ((key.name === "return" || key.sequence === " ") && /^(?:block-title:|block-action:|modal-action:|media-control:|media-preview:|model3d-control:)/.test(focusedId)) return false;
|
|
2311
3034
|
if (this.spec.kind === "select") {
|
|
2312
3035
|
if (key.name === "up" || key.name === "down" || key.name === "pageup" || key.name === "pagedown") {
|
|
2313
3036
|
const amount = key.name.startsWith("page") ? Math.max(1, Math.floor((this.select?.height ?? 5) / (this.select?.showDescription ? 2 : 1))) : 1;
|
|
@@ -2428,7 +3151,7 @@ var NativeModalView = class {
|
|
|
2428
3151
|
editor.placeholderColor = colors.foreground;
|
|
2429
3152
|
}
|
|
2430
3153
|
if (this.secretMask) this.secretMask.fg = colors.foreground;
|
|
2431
|
-
for (const action of [...this.actions.getChildren(), ...this.headerActions.getChildren()]) if (action instanceof
|
|
3154
|
+
for (const action of [...this.actions.getChildren(), ...this.headerActions.getChildren()]) if (action instanceof TextRenderable4) {
|
|
2432
3155
|
action.fg = colors.foreground;
|
|
2433
3156
|
action.bg = colors.background;
|
|
2434
3157
|
}
|
|
@@ -2453,6 +3176,14 @@ var NativeModalStack = class {
|
|
|
2453
3176
|
restoreFocus;
|
|
2454
3177
|
views = [];
|
|
2455
3178
|
byId = /* @__PURE__ */ new Map();
|
|
3179
|
+
pendingMedia = /* @__PURE__ */ new Set();
|
|
3180
|
+
trackMedia(promises) {
|
|
3181
|
+
for (const promise of promises) {
|
|
3182
|
+
if (this.pendingMedia.has(promise)) continue;
|
|
3183
|
+
this.pendingMedia.add(promise);
|
|
3184
|
+
void promise.then(() => this.pendingMedia.delete(promise), () => this.pendingMedia.delete(promise));
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
2456
3187
|
dimUnderlay = (buffer) => {
|
|
2457
3188
|
const panel = this.active?.panel;
|
|
2458
3189
|
if (!panel || panel.isDestroyed || !panel.visible) return;
|
|
@@ -2487,6 +3218,7 @@ var NativeModalStack = class {
|
|
|
2487
3218
|
close(id, result, notify = false) {
|
|
2488
3219
|
const view = this.byId.get(id);
|
|
2489
3220
|
if (!view) return;
|
|
3221
|
+
this.trackMedia(view.pauseMedia());
|
|
2490
3222
|
view.frame.close(() => {
|
|
2491
3223
|
const wasActive = view === this.active;
|
|
2492
3224
|
view.destroy();
|
|
@@ -2504,9 +3236,21 @@ var NativeModalStack = class {
|
|
|
2504
3236
|
applyTheme() {
|
|
2505
3237
|
for (const view of this.views) view.applyTheme();
|
|
2506
3238
|
}
|
|
3239
|
+
reconcileMedia() {
|
|
3240
|
+
for (const view of this.views) view.reconcileMedia(view === this.active);
|
|
3241
|
+
}
|
|
3242
|
+
pauseMedia() {
|
|
3243
|
+
return [...this.pendingMedia, ...this.views.flatMap((view) => view.pauseMedia())];
|
|
3244
|
+
}
|
|
3245
|
+
async settleMedia() {
|
|
3246
|
+
while (this.pendingMedia.size) await Promise.allSettled([...this.pendingMedia]);
|
|
3247
|
+
}
|
|
2507
3248
|
destroy() {
|
|
2508
3249
|
this.context.renderer.removePostProcessFn(this.dimUnderlay);
|
|
2509
|
-
for (const view of this.views)
|
|
3250
|
+
for (const view of this.views) {
|
|
3251
|
+
this.trackMedia(view.pauseMedia());
|
|
3252
|
+
view.destroy();
|
|
3253
|
+
}
|
|
2510
3254
|
this.views = [];
|
|
2511
3255
|
this.byId.clear();
|
|
2512
3256
|
}
|
|
@@ -2514,12 +3258,12 @@ var NativeModalStack = class {
|
|
|
2514
3258
|
|
|
2515
3259
|
// packages/cli/src/tui/native/components/instruments.ts
|
|
2516
3260
|
import {
|
|
2517
|
-
BoxRenderable as
|
|
2518
|
-
RGBA as
|
|
3261
|
+
BoxRenderable as BoxRenderable9,
|
|
3262
|
+
RGBA as RGBA3,
|
|
2519
3263
|
RenderableEvents as RenderableEvents6,
|
|
2520
3264
|
ScrollBoxRenderable as ScrollBoxRenderable6,
|
|
2521
3265
|
TextAttributes as TextAttributes8,
|
|
2522
|
-
TextRenderable as
|
|
3266
|
+
TextRenderable as TextRenderable8
|
|
2523
3267
|
} from "@opentui/core";
|
|
2524
3268
|
|
|
2525
3269
|
// packages/cli/src/tui/native/components/device-history.ts
|
|
@@ -2576,12 +3320,12 @@ function deviceHistoryGraph(samples, field, width) {
|
|
|
2576
3320
|
|
|
2577
3321
|
// packages/cli/src/tui/native/components/task-notes.ts
|
|
2578
3322
|
import {
|
|
2579
|
-
BoxRenderable as
|
|
3323
|
+
BoxRenderable as BoxRenderable6,
|
|
2580
3324
|
CliRenderEvents as CliRenderEvents4,
|
|
2581
3325
|
RenderableEvents as RenderableEvents3,
|
|
2582
3326
|
ScrollBoxRenderable as ScrollBoxRenderable3,
|
|
2583
3327
|
TextAttributes as TextAttributes5,
|
|
2584
|
-
TextRenderable as
|
|
3328
|
+
TextRenderable as TextRenderable5
|
|
2585
3329
|
} from "@opentui/core";
|
|
2586
3330
|
|
|
2587
3331
|
// packages/cli/src/tui/native/components/instrument-format.ts
|
|
@@ -2654,7 +3398,7 @@ var marks = ["▨", "▧", "▥", "▦"];
|
|
|
2654
3398
|
var reducedMotion = () => process.env["OMNIUS_TUI_REDUCE_MOTION"] === "1" || process.env["REDUCE_MOTION"] === "1";
|
|
2655
3399
|
var safe = (value) => typeof value === "string" ? plainText(value) : "";
|
|
2656
3400
|
var lines = (values) => Array.isArray(values) ? values.filter((value) => typeof value === "string").map(safe) : [];
|
|
2657
|
-
var column = (renderer2, id) => new
|
|
3401
|
+
var column = (renderer2, id) => new BoxRenderable6(renderer2, { id, width: "100%", flexDirection: "column", flexShrink: 0, minWidth: 0 });
|
|
2658
3402
|
function visible(node, renderer2) {
|
|
2659
3403
|
if (node.width < 1 || node.height < 1 || node.y >= renderer2.terminalHeight || node.y + node.height <= 0) return false;
|
|
2660
3404
|
for (let current = node; current; current = current.parent) {
|
|
@@ -2702,7 +3446,7 @@ var ActiveBlocks = class {
|
|
|
2702
3446
|
this.renderer.off(CliRenderEvents4.FRAME, this.sync);
|
|
2703
3447
|
}
|
|
2704
3448
|
};
|
|
2705
|
-
var Disclosure = class extends
|
|
3449
|
+
var Disclosure = class extends TextRenderable5 {
|
|
2706
3450
|
constructor(renderer2, id, activate, colors, ruled = false) {
|
|
2707
3451
|
super(renderer2, {
|
|
2708
3452
|
id,
|
|
@@ -2746,9 +3490,9 @@ var Disclosure = class extends TextRenderable4 {
|
|
|
2746
3490
|
open = true;
|
|
2747
3491
|
label = "";
|
|
2748
3492
|
base = TextAttributes5.BOLD;
|
|
2749
|
-
update(label3,
|
|
3493
|
+
update(label3, open2, attributes = TextAttributes5.BOLD) {
|
|
2750
3494
|
this.label = label3;
|
|
2751
|
-
this.open =
|
|
3495
|
+
this.open = open2;
|
|
2752
3496
|
this.base = attributes;
|
|
2753
3497
|
this.refresh();
|
|
2754
3498
|
this.style();
|
|
@@ -2791,13 +3535,13 @@ function layerStatus(layer) {
|
|
|
2791
3535
|
if (["verified", "integrated"].includes(status)) return `REPORTED ${status.toUpperCase()} · AUTHORITY NOT ATTESTED`;
|
|
2792
3536
|
return ["bound", "recorded", "tool complete", "tool failed", "compact", "hold", "accepted", "requested", "held", "incomplete verification", "incomplete_verification", "incomplete", "awaiting_input", "not attached", "proposed", "specified", "ready", "pending", "waiting", "leased", "running", "candidate", "verifying", "blocked", "retryable", "completed", "failed", "rejected", "cancelled", "superseded", "received", "queued", "acknowledged", "visible_in_request", "reconciliation_required", "reconciled", "first_affected_action", "consumed"].includes(status) ? status.replace(/_/g, " ").toUpperCase() : "UNKNOWN";
|
|
2793
3537
|
}
|
|
2794
|
-
var NativeTaskNotesView = class extends
|
|
3538
|
+
var NativeTaskNotesView = class extends BoxRenderable6 {
|
|
2795
3539
|
constructor(renderer2, colors, reveal) {
|
|
2796
3540
|
super(renderer2, { id: "omnius-task-notes", width: "100%", minWidth: 0, flexShrink: 0, flexDirection: "column", visible: false });
|
|
2797
3541
|
this.renderer = renderer2;
|
|
2798
3542
|
this.colors = colors;
|
|
2799
3543
|
this.reveal = reveal;
|
|
2800
|
-
const text = (id, attributes = 0) => new
|
|
3544
|
+
const text = (id, attributes = 0) => new TextRenderable5(renderer2, { id, content: "", width: "100%", minWidth: 0, flexShrink: 0, fg: colors.foreground, bg: colors.background, attributes, wrapMode: "word" });
|
|
2801
3545
|
const heading = (id, label3, key) => {
|
|
2802
3546
|
const node = new Disclosure(renderer2, id, () => {
|
|
2803
3547
|
this.presentation[key] = !this.presentation[key];
|
|
@@ -2874,7 +3618,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
2874
3618
|
const saved = state?.sessionId ? this.sessions.get(state.sessionId) : void 0;
|
|
2875
3619
|
this.presentation = saved ? { open: saved.open, tasks: saved.tasks, notes: saved.notes, layers: saved.layers } : { open: true, tasks: true, notes: true, layers: true };
|
|
2876
3620
|
this.disclosures.clear();
|
|
2877
|
-
if (saved) for (const [id,
|
|
3621
|
+
if (saved) for (const [id, open2] of Object.entries(saved.disclosures)) this.disclosures.set(id, open2);
|
|
2878
3622
|
}
|
|
2879
3623
|
this.state = state;
|
|
2880
3624
|
this.visible = !!state;
|
|
@@ -2907,7 +3651,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
2907
3651
|
this.refreshRow(row);
|
|
2908
3652
|
}, this.colors);
|
|
2909
3653
|
title.on(RenderableEvents3.FOCUSED, () => this.reveal?.(title));
|
|
2910
|
-
const details = new
|
|
3654
|
+
const details = new TextRenderable5(this.renderer, { id: `task:${item.id}:metadata`, content: "", width: "100%", minWidth: 0, wrapMode: "word", flexShrink: 0, fg: this.colors.foreground, bg: this.colors.background, attributes: TextAttributes5.DIM });
|
|
2911
3655
|
const detailButton = new Disclosure(this.renderer, `task:${item.id}:details`, () => {
|
|
2912
3656
|
const key = `meta:${item.id}`;
|
|
2913
3657
|
this.disclosures.set(key, !this.disclosures.get(key));
|
|
@@ -2971,7 +3715,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
2971
3715
|
const id = String(note.id);
|
|
2972
3716
|
let row = this.noteRows.get(id);
|
|
2973
3717
|
if (!row) {
|
|
2974
|
-
row = new
|
|
3718
|
+
row = new TextRenderable5(this.renderer, { id: `note:${id}`, content: "", width: "100%", minWidth: 0, wrapMode: "word", flexShrink: 0, fg: this.colors.foreground, bg: this.colors.background });
|
|
2975
3719
|
this.noteRows.set(id, row);
|
|
2976
3720
|
}
|
|
2977
3721
|
const text = `□ ${safe(note.category).toUpperCase()} · ${safe(note.content)}${note.file ? `
|
|
@@ -2992,7 +3736,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
2992
3736
|
const id = safe(layer.id);
|
|
2993
3737
|
let row = this.layerRows.get(id);
|
|
2994
3738
|
if (!row) {
|
|
2995
|
-
row = new
|
|
3739
|
+
row = new TextRenderable5(this.renderer, { id: `work-layer:${id}`, content: "", width: "100%", minWidth: 0, wrapMode: "word", flexShrink: 0, fg: this.colors.foreground, bg: this.colors.background });
|
|
2996
3740
|
this.layerRows.set(id, row);
|
|
2997
3741
|
}
|
|
2998
3742
|
const progress = typeof layer.progress === "number" && Number.isFinite(layer.progress) && layer.progress >= 0 && layer.progress <= 1 ? ` · ${Math.round(layer.progress * 100)}%` : "";
|
|
@@ -3051,7 +3795,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
3051
3795
|
if (!state) return;
|
|
3052
3796
|
this.presentation = { open: state.open, tasks: state.tasks, notes: state.notes, layers: state.layers };
|
|
3053
3797
|
this.disclosures.clear();
|
|
3054
|
-
for (const [id,
|
|
3798
|
+
for (const [id, open2] of Object.entries(state.disclosures)) this.disclosures.set(id, open2);
|
|
3055
3799
|
for (const row of this.rows.values()) this.refreshRow(row);
|
|
3056
3800
|
this.applyPresentation();
|
|
3057
3801
|
}
|
|
@@ -3059,7 +3803,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
3059
3803
|
const targets = [];
|
|
3060
3804
|
const visit = (node) => {
|
|
3061
3805
|
if (!node.visible) return;
|
|
3062
|
-
if (node instanceof
|
|
3806
|
+
if (node instanceof TextRenderable5 && node.focusable) targets.push(node);
|
|
3063
3807
|
for (const child of node.getChildren()) visit(child);
|
|
3064
3808
|
};
|
|
3065
3809
|
if (this.visible) visit(this);
|
|
@@ -3068,7 +3812,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
3068
3812
|
applyTheme(colors) {
|
|
3069
3813
|
this.colors = colors;
|
|
3070
3814
|
const visit = (node) => {
|
|
3071
|
-
if (node instanceof
|
|
3815
|
+
if (node instanceof TextRenderable5) {
|
|
3072
3816
|
node.fg = colors.foreground;
|
|
3073
3817
|
node.bg = colors.background;
|
|
3074
3818
|
}
|
|
@@ -3082,7 +3826,7 @@ var NativeTaskNotesView = class extends BoxRenderable5 {
|
|
|
3082
3826
|
super.destroySelf();
|
|
3083
3827
|
}
|
|
3084
3828
|
};
|
|
3085
|
-
var NativeTaskStrip = class extends
|
|
3829
|
+
var NativeTaskStrip = class extends BoxRenderable6 {
|
|
3086
3830
|
constructor(renderer2, colors, inspect) {
|
|
3087
3831
|
super(renderer2, {
|
|
3088
3832
|
id: "omnius-task-strip",
|
|
@@ -3101,7 +3845,7 @@ var NativeTaskStrip = class extends BoxRenderable5 {
|
|
|
3101
3845
|
this.renderer = renderer2;
|
|
3102
3846
|
this.colors = colors;
|
|
3103
3847
|
this.inspect = inspect;
|
|
3104
|
-
this.label = new
|
|
3848
|
+
this.label = new TextRenderable5(renderer2, {
|
|
3105
3849
|
id: "omnius-task-strip:heading",
|
|
3106
3850
|
content: "TASKS ",
|
|
3107
3851
|
height: 1,
|
|
@@ -3200,7 +3944,7 @@ var NativeTaskStrip = class extends BoxRenderable5 {
|
|
|
3200
3944
|
for (const [index, item] of items.entries()) {
|
|
3201
3945
|
let chip = this.chips.get(item.id);
|
|
3202
3946
|
if (!chip) {
|
|
3203
|
-
const label3 = new
|
|
3947
|
+
const label3 = new TextRenderable5(this.renderer, {
|
|
3204
3948
|
id: `task-strip:${item.id}`,
|
|
3205
3949
|
content: "",
|
|
3206
3950
|
height: 1,
|
|
@@ -3280,26 +4024,26 @@ var NativeTaskStrip = class extends BoxRenderable5 {
|
|
|
3280
4024
|
|
|
3281
4025
|
// packages/cli/src/tui/native/components/work-queue.ts
|
|
3282
4026
|
import {
|
|
3283
|
-
BoxRenderable as
|
|
4027
|
+
BoxRenderable as BoxRenderable7,
|
|
3284
4028
|
CliRenderEvents as CliRenderEvents5,
|
|
3285
4029
|
RenderableEvents as RenderableEvents4,
|
|
3286
4030
|
ScrollBoxRenderable as ScrollBoxRenderable4,
|
|
3287
4031
|
TextAttributes as TextAttributes6,
|
|
3288
|
-
TextRenderable as
|
|
4032
|
+
TextRenderable as TextRenderable6
|
|
3289
4033
|
} from "@opentui/core";
|
|
3290
4034
|
var frames = ["▨", "▧", "▥", "▦"];
|
|
3291
4035
|
var actionLabels = { queue: "QUEUE", apply: "APPLY", override: "OVERRIDE", cancel: "CANCEL", retry: "RETRY", up: "UP", down: "DOWN" };
|
|
3292
4036
|
var safe2 = (value) => typeof value === "string" ? plainText(value) : "";
|
|
3293
4037
|
var label = (value) => safe2(value).replace(/[\r\n\t]+/g, " ");
|
|
3294
4038
|
var reducedMotion2 = () => process.env["OMNIUS_TUI_REDUCE_MOTION"] === "1" || process.env["REDUCE_MOTION"] === "1";
|
|
3295
|
-
var column2 = (renderer2, id) => new
|
|
4039
|
+
var column2 = (renderer2, id) => new BoxRenderable7(renderer2, { id, width: "100%", minWidth: 0, flexDirection: "column", flexShrink: 0 });
|
|
3296
4040
|
var historyStates = /* @__PURE__ */ new Set(["completed", "applied", "failed", "cancelled"]);
|
|
3297
4041
|
var activeStates = /* @__PURE__ */ new Set(["claiming", "running", "admitted"]);
|
|
3298
4042
|
var receiptTime = (at) => {
|
|
3299
4043
|
const date = new Date(typeof at === "number" ? at : NaN);
|
|
3300
4044
|
return Number.isFinite(date.getTime()) ? date.toISOString() : "";
|
|
3301
4045
|
};
|
|
3302
|
-
var WorkControl = class extends
|
|
4046
|
+
var WorkControl = class extends TextRenderable6 {
|
|
3303
4047
|
constructor(renderer2, id, activate, colors, disclosure = false, ruled = false, fixedWidth) {
|
|
3304
4048
|
super(renderer2, {
|
|
3305
4049
|
id,
|
|
@@ -3342,9 +4086,9 @@ var WorkControl = class extends TextRenderable5 {
|
|
|
3342
4086
|
open = false;
|
|
3343
4087
|
caption = "";
|
|
3344
4088
|
base = 0;
|
|
3345
|
-
update(caption,
|
|
4089
|
+
update(caption, open2 = false, attributes = 0) {
|
|
3346
4090
|
this.caption = caption;
|
|
3347
|
-
this.open =
|
|
4091
|
+
this.open = open2;
|
|
3348
4092
|
this.base = attributes;
|
|
3349
4093
|
this.refresh();
|
|
3350
4094
|
this.style();
|
|
@@ -3361,7 +4105,7 @@ var WorkControl = class extends TextRenderable5 {
|
|
|
3361
4105
|
if (this.plainText !== value) this.content = value;
|
|
3362
4106
|
}
|
|
3363
4107
|
};
|
|
3364
|
-
var NativeWorkQueueView = class extends
|
|
4108
|
+
var NativeWorkQueueView = class extends BoxRenderable7 {
|
|
3365
4109
|
constructor(renderer2, colors, onAction, reveal) {
|
|
3366
4110
|
super(renderer2, { id: "omnius-work-queue", width: "100%", minWidth: 0, flexDirection: "column", flexShrink: 0, visible: false });
|
|
3367
4111
|
this.renderer = renderer2;
|
|
@@ -3422,7 +4166,7 @@ var NativeWorkQueueView = class extends BoxRenderable6 {
|
|
|
3422
4166
|
frame = 0;
|
|
3423
4167
|
disposed = false;
|
|
3424
4168
|
text(id, attributes = 0) {
|
|
3425
|
-
return new
|
|
4169
|
+
return new TextRenderable6(this.renderer, { id, content: "", width: "100%", minWidth: 0, flexShrink: 0, wrapMode: "word", fg: this.colors.foreground, bg: this.colors.background, attributes });
|
|
3426
4170
|
}
|
|
3427
4171
|
control(id, activate, disclosure = false, ruled = false, width) {
|
|
3428
4172
|
const node = new WorkControl(this.renderer, id, activate, this.colors, disclosure, ruled, width);
|
|
@@ -3504,22 +4248,22 @@ var NativeWorkQueueView = class extends BoxRenderable6 {
|
|
|
3504
4248
|
const metadata2 = this.text(`${id}:metadata`, TextAttributes6.DIM), original = this.text(`${id}:original`);
|
|
3505
4249
|
details.add(original);
|
|
3506
4250
|
details.add(metadata2);
|
|
3507
|
-
const controls = new
|
|
4251
|
+
const controls = new BoxRenderable7(this.renderer, { id: `${id}:actions`, width: "100%", minWidth: 0, flexDirection: "row", flexWrap: "wrap", flexShrink: 0 });
|
|
3508
4252
|
details.add(controls);
|
|
3509
4253
|
const row = { item, root, title, details, original, metadata: metadata2, controls, actions: /* @__PURE__ */ new Map() };
|
|
3510
4254
|
this.rows.set(item.id, row);
|
|
3511
4255
|
return row;
|
|
3512
4256
|
}
|
|
3513
4257
|
refreshRow(row) {
|
|
3514
|
-
const item = row.item,
|
|
4258
|
+
const item = row.item, open2 = this.presentation.disclosures[item.id] === true;
|
|
3515
4259
|
const state = label(item.state).replace(/_/g, " ").toUpperCase();
|
|
3516
4260
|
const mark = item.state === "reviewing" || item.state === "claiming" ? frames[this.frame % frames.length] : item.state === "running" ? "▨" : item.state === "needs_review" || item.state === "interrupted" ? "▣" : historyStates.has(item.state) ? "■" : "□";
|
|
3517
4261
|
row.title.update(
|
|
3518
4262
|
`${mark} ${row.position === void 0 ? "" : `${row.position}. `}${state} · ${label(item.title) || "Untitled request"}`,
|
|
3519
|
-
|
|
4263
|
+
open2,
|
|
3520
4264
|
item.state === "queued" ? TextAttributes6.DIM : item.state === "running" || item.state === "needs_review" ? TextAttributes6.BOLD : 0
|
|
3521
4265
|
);
|
|
3522
|
-
row.details.visible =
|
|
4266
|
+
row.details.visible = open2;
|
|
3523
4267
|
const original = `ORIGINAL
|
|
3524
4268
|
${safe2(item.originalText)}`;
|
|
3525
4269
|
if (row.original.plainText !== original) row.original.content = original;
|
|
@@ -3607,7 +4351,7 @@ RUN ${label(receipt.runId)}` : ""}`)
|
|
|
3607
4351
|
const targets = [];
|
|
3608
4352
|
const visit = (node) => {
|
|
3609
4353
|
if (!node.visible) return;
|
|
3610
|
-
if (node instanceof
|
|
4354
|
+
if (node instanceof TextRenderable6 && node.focusable) targets.push(node);
|
|
3611
4355
|
for (const child of node.getChildren()) visit(child);
|
|
3612
4356
|
};
|
|
3613
4357
|
if (this.visible) visit(this);
|
|
@@ -3616,7 +4360,7 @@ RUN ${label(receipt.runId)}` : ""}`)
|
|
|
3616
4360
|
applyTheme(colors) {
|
|
3617
4361
|
this.colors = colors;
|
|
3618
4362
|
const visit = (node) => {
|
|
3619
|
-
if (node instanceof
|
|
4363
|
+
if (node instanceof TextRenderable6) {
|
|
3620
4364
|
node.fg = colors.foreground;
|
|
3621
4365
|
node.bg = colors.background;
|
|
3622
4366
|
}
|
|
@@ -3635,11 +4379,11 @@ RUN ${label(receipt.runId)}` : ""}`)
|
|
|
3635
4379
|
|
|
3636
4380
|
// packages/cli/src/tui/native/components/workspace-files.ts
|
|
3637
4381
|
import {
|
|
3638
|
-
BoxRenderable as
|
|
4382
|
+
BoxRenderable as BoxRenderable8,
|
|
3639
4383
|
RenderableEvents as RenderableEvents5,
|
|
3640
4384
|
ScrollBoxRenderable as ScrollBoxRenderable5,
|
|
3641
4385
|
TextAttributes as TextAttributes7,
|
|
3642
|
-
TextRenderable as
|
|
4386
|
+
TextRenderable as TextRenderable7
|
|
3643
4387
|
} from "@opentui/core";
|
|
3644
4388
|
var label2 = (value) => plainText(value).replace(/[\r\n\t]/g, " ");
|
|
3645
4389
|
var identity = (state) => state ? `${state.projectRoot}\0${state.sessionId ?? ""}` : "";
|
|
@@ -3651,7 +4395,7 @@ var activityLabel = (item) => {
|
|
|
3651
4395
|
const kind = { read: "R", write: "W", create: "+", delete: "−" }[item.activity.kind];
|
|
3652
4396
|
return kind + (item.activity.phase === "verified" ? "✓" : item.activity.phase === "failed" ? "!" : "…");
|
|
3653
4397
|
};
|
|
3654
|
-
var FileControl = class extends
|
|
4398
|
+
var FileControl = class extends TextRenderable7 {
|
|
3655
4399
|
constructor(renderer2, id, colors, activate, ruled = false, width) {
|
|
3656
4400
|
super(renderer2, {
|
|
3657
4401
|
id,
|
|
@@ -3689,9 +4433,9 @@ var FileControl = class extends TextRenderable6 {
|
|
|
3689
4433
|
ruled;
|
|
3690
4434
|
caption = "";
|
|
3691
4435
|
open = false;
|
|
3692
|
-
setLabel(value,
|
|
4436
|
+
setLabel(value, open2 = false) {
|
|
3693
4437
|
this.caption = value;
|
|
3694
|
-
this.open =
|
|
4438
|
+
this.open = open2;
|
|
3695
4439
|
this.refresh();
|
|
3696
4440
|
this.style();
|
|
3697
4441
|
}
|
|
@@ -3706,7 +4450,7 @@ var FileControl = class extends TextRenderable6 {
|
|
|
3706
4450
|
this.content = this.ruled ? formatSectionBanner(this.caption, this.width, this.open) : fitInstrumentText(this.caption, this.width);
|
|
3707
4451
|
}
|
|
3708
4452
|
};
|
|
3709
|
-
var NativeWorkspaceFilesView = class extends
|
|
4453
|
+
var NativeWorkspaceFilesView = class extends BoxRenderable8 {
|
|
3710
4454
|
constructor(renderer2, colors, onAction, reveal) {
|
|
3711
4455
|
super(renderer2, { id: "omnius-workspace-files", width: "100%", minWidth: 0, flexDirection: "column", flexShrink: 0, visible: false });
|
|
3712
4456
|
this.renderer = renderer2;
|
|
@@ -3715,9 +4459,9 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3715
4459
|
this.reveal = reveal;
|
|
3716
4460
|
this.header = new FileControl(renderer2, "omnius-workspace-files:heading", colors, () => this.setOpen(!this.open), true);
|
|
3717
4461
|
this.add(this.header);
|
|
3718
|
-
this.body = new
|
|
4462
|
+
this.body = new BoxRenderable8(renderer2, { id: "omnius-workspace-files:body", width: "100%", minWidth: 0, minHeight: 0, flexDirection: "column", flexGrow: 1, flexBasis: 0, flexShrink: 1, visible: false });
|
|
3719
4463
|
this.add(this.body);
|
|
3720
|
-
const heading = new
|
|
4464
|
+
const heading = new BoxRenderable8(renderer2, { id: "omnius-workspace-files:location", width: "100%", minWidth: 0, height: 1, flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
3721
4465
|
this.body.add(heading);
|
|
3722
4466
|
this.rootLabel = this.text("omnius-workspace-files:root");
|
|
3723
4467
|
this.rootLabel.width = 0;
|
|
@@ -3751,7 +4495,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3751
4495
|
contentOptions: { flexDirection: "column", paddingRight: 1 }
|
|
3752
4496
|
});
|
|
3753
4497
|
this.body.add(this.scroll);
|
|
3754
|
-
this.rootPages = new
|
|
4498
|
+
this.rootPages = new BoxRenderable8(renderer2, { id: "omnius-workspace-files:pages", width: "100%", height: 1, flexDirection: "row", gap: 2, flexShrink: 0 });
|
|
3755
4499
|
this.body.add(this.rootPages);
|
|
3756
4500
|
this.rootStart = new FileControl(renderer2, "omnius-workspace-files:start", colors, () => {
|
|
3757
4501
|
this.lastClick = void 0;
|
|
@@ -3800,7 +4544,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3800
4544
|
layoutMinimum = 0;
|
|
3801
4545
|
layoutExpanded = false;
|
|
3802
4546
|
text(id) {
|
|
3803
|
-
return new
|
|
4547
|
+
return new TextRenderable7(this.renderer, { id, content: "", width: "100%", minWidth: 0, flexShrink: 0, wrapMode: "word", fg: this.colors.foreground, bg: this.colors.background });
|
|
3804
4548
|
}
|
|
3805
4549
|
update(state) {
|
|
3806
4550
|
if (state === this.state) return;
|
|
@@ -3861,7 +4605,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3861
4605
|
if (!pagePaths.has(item.path)) return;
|
|
3862
4606
|
let page = this.pagination.get(item.path);
|
|
3863
4607
|
if (!page) {
|
|
3864
|
-
const root = new
|
|
4608
|
+
const root = new BoxRenderable8(this.renderer, { id: `${rowId(item.path)}:pages`, width: "100%", height: 1, minWidth: 0, flexDirection: "row", gap: 2, paddingLeft: Math.min(16, (item.depth + 1) * 2), flexShrink: 0 });
|
|
3865
4609
|
const start = new FileControl(this.renderer, `${root.id}:start`, this.colors, () => {
|
|
3866
4610
|
this.lastClick = void 0;
|
|
3867
4611
|
this.action("start", item.path);
|
|
@@ -3911,7 +4655,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3911
4655
|
}
|
|
3912
4656
|
}
|
|
3913
4657
|
createRow(item) {
|
|
3914
|
-
const root = new
|
|
4658
|
+
const root = new BoxRenderable8(this.renderer, { id: rowId(item.path), width: "100%", minWidth: 0, height: 1, flexShrink: 0, flexDirection: "row" });
|
|
3915
4659
|
const disclosure = new FileControl(this.renderer, `${root.id}:disclosure`, this.colors, () => {
|
|
3916
4660
|
const current = this.rows.get(item.path)?.item;
|
|
3917
4661
|
this.lastClick = void 0;
|
|
@@ -3922,7 +4666,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
3922
4666
|
}, false, 2);
|
|
3923
4667
|
disclosure.focusable = false;
|
|
3924
4668
|
root.add(disclosure);
|
|
3925
|
-
const name = new
|
|
4669
|
+
const name = new TextRenderable7(this.renderer, {
|
|
3926
4670
|
id: `${root.id}:name`,
|
|
3927
4671
|
content: "",
|
|
3928
4672
|
width: 0,
|
|
@@ -4026,12 +4770,12 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
4026
4770
|
if (!state) return;
|
|
4027
4771
|
this.onAction?.({ type: "workspace-action", action, path, projectRoot: state.projectRoot, sessionId: state.sessionId, revision: state.revision, epoch: state.epoch, ...action === "visibility" ? { open: this.open } : {} });
|
|
4028
4772
|
}
|
|
4029
|
-
setOpen(
|
|
4030
|
-
this.open =
|
|
4773
|
+
setOpen(open2) {
|
|
4774
|
+
this.open = open2;
|
|
4031
4775
|
this.lastClick = void 0;
|
|
4032
4776
|
this.applyPresentation();
|
|
4033
4777
|
this.action("visibility", "");
|
|
4034
|
-
if (
|
|
4778
|
+
if (open2) this.reveal?.(this.header);
|
|
4035
4779
|
}
|
|
4036
4780
|
get isOpen() {
|
|
4037
4781
|
return this.open;
|
|
@@ -4074,7 +4818,7 @@ var NativeWorkspaceFilesView = class extends BoxRenderable7 {
|
|
|
4074
4818
|
applyTheme(colors) {
|
|
4075
4819
|
this.colors = colors;
|
|
4076
4820
|
const visit = (node) => {
|
|
4077
|
-
if (node instanceof
|
|
4821
|
+
if (node instanceof TextRenderable7) {
|
|
4078
4822
|
node.fg = colors.foreground;
|
|
4079
4823
|
node.bg = colors.background;
|
|
4080
4824
|
}
|
|
@@ -4151,9 +4895,9 @@ var NativeWorkspaceReferenceRow = class extends ScrollBoxRenderable5 {
|
|
|
4151
4895
|
};
|
|
4152
4896
|
|
|
4153
4897
|
// packages/cli/src/tui/native/components/instruments.ts
|
|
4154
|
-
var foreground =
|
|
4155
|
-
var background =
|
|
4156
|
-
var SectionBanner = class extends
|
|
4898
|
+
var foreground = RGBA3.defaultForeground();
|
|
4899
|
+
var background = RGBA3.defaultBackground();
|
|
4900
|
+
var SectionBanner = class extends TextRenderable8 {
|
|
4157
4901
|
constructor(renderer2, title, id, activate) {
|
|
4158
4902
|
super(renderer2, {
|
|
4159
4903
|
id,
|
|
@@ -4208,7 +4952,7 @@ var SectionBanner = class extends TextRenderable7 {
|
|
|
4208
4952
|
if (this.plainText !== next) this.content = next;
|
|
4209
4953
|
}
|
|
4210
4954
|
};
|
|
4211
|
-
var TelemetryRow = class extends
|
|
4955
|
+
var TelemetryRow = class extends TextRenderable8 {
|
|
4212
4956
|
constructor(renderer2, label3, id, reserved = 12) {
|
|
4213
4957
|
super(renderer2, {
|
|
4214
4958
|
id,
|
|
@@ -4254,7 +4998,7 @@ var SignalMeter = class extends TelemetryRow {
|
|
|
4254
4998
|
this.update(formatSignalMeter(value, maximum));
|
|
4255
4999
|
}
|
|
4256
5000
|
};
|
|
4257
|
-
var InstrumentDivider = class extends
|
|
5001
|
+
var InstrumentDivider = class extends TextRenderable8 {
|
|
4258
5002
|
constructor(renderer2, actions) {
|
|
4259
5003
|
super(renderer2, {
|
|
4260
5004
|
id: "omnius-instrument-divider",
|
|
@@ -4351,17 +5095,17 @@ var InstrumentDivider = class extends TextRenderable7 {
|
|
|
4351
5095
|
this.attributes = this.focused ? TextAttributes8.INVERSE : TextAttributes8.DIM;
|
|
4352
5096
|
}
|
|
4353
5097
|
};
|
|
4354
|
-
var DeviceMonitor = class extends
|
|
5098
|
+
var DeviceMonitor = class extends BoxRenderable9 {
|
|
4355
5099
|
constructor(renderer2, action) {
|
|
4356
5100
|
super(renderer2, { id: "omnius-devices", width: "100%", height: 5, minHeight: 3, flexShrink: 0, flexDirection: "column", visible: false });
|
|
4357
5101
|
this.action = action;
|
|
4358
5102
|
this.heading = new SectionBanner(renderer2, "DEVICES", "omnius-devices:heading", () => this.toggle());
|
|
4359
5103
|
this.heading.update("DEVICES", false);
|
|
4360
5104
|
this.add(this.heading);
|
|
4361
|
-
this.summary = new
|
|
5105
|
+
this.summary = new TextRenderable8(renderer2, { id: "omnius-devices:summary", content: "--", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
4362
5106
|
this.add(this.summary);
|
|
4363
|
-
this.compactLoad = new
|
|
4364
|
-
this.compactMemory = new
|
|
5107
|
+
this.compactLoad = new TextRenderable8(renderer2, { id: "omnius-devices:load-history", content: "", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
5108
|
+
this.compactMemory = new TextRenderable8(renderer2, { id: "omnius-devices:memory-history", content: "", width: "100%", height: 1, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true });
|
|
4365
5109
|
this.add(this.compactLoad);
|
|
4366
5110
|
this.add(this.compactMemory);
|
|
4367
5111
|
this.scroll = new ScrollBoxRenderable6(renderer2, {
|
|
@@ -4381,7 +5125,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4381
5125
|
this.add(this.scroll);
|
|
4382
5126
|
for (const [key, title] of [["cpu", "CPU"], ["memory", "MEMORY"], ["disk", "DISK"], ["network", "NETWORK"], ["gpu", "GPU"]])
|
|
4383
5127
|
this.createSection(renderer2, key, title);
|
|
4384
|
-
this.notes = new
|
|
5128
|
+
this.notes = new TextRenderable8(renderer2, {
|
|
4385
5129
|
id: "omnius-devices:notes",
|
|
4386
5130
|
content: "",
|
|
4387
5131
|
width: "100%",
|
|
@@ -4393,7 +5137,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4393
5137
|
truncate: true
|
|
4394
5138
|
});
|
|
4395
5139
|
this.sections.get("gpu").body.add(this.notes);
|
|
4396
|
-
const controls = new
|
|
5140
|
+
const controls = new BoxRenderable9(renderer2, { id: "omnius-devices:controls", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2 });
|
|
4397
5141
|
this.add(controls);
|
|
4398
5142
|
this.policy = this.button(renderer2, "omnius-devices:policy", "GPU POLICY", () => {
|
|
4399
5143
|
if (this.canSelect()) this.action?.("/gpu");
|
|
@@ -4422,7 +5166,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4422
5166
|
historySource = "";
|
|
4423
5167
|
rows = /* @__PURE__ */ new Map();
|
|
4424
5168
|
createSection(renderer2, key, title) {
|
|
4425
|
-
const root = new
|
|
5169
|
+
const root = new BoxRenderable9(renderer2, {
|
|
4426
5170
|
id: `omnius-devices:${key}`,
|
|
4427
5171
|
width: "100%",
|
|
4428
5172
|
minWidth: 0,
|
|
@@ -4438,7 +5182,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4438
5182
|
});
|
|
4439
5183
|
const header = new SectionBanner(renderer2, title, `${root.id}:heading`, () => this.toggleDeviceSection(key));
|
|
4440
5184
|
header.on(RenderableEvents6.FOCUSED, () => this.revealReading(header));
|
|
4441
|
-
const body = new
|
|
5185
|
+
const body = new BoxRenderable9(renderer2, { id: `${root.id}:body`, width: "100%", minWidth: 0, flexShrink: 0, flexDirection: "column", visible: this.sectionState[key] });
|
|
4442
5186
|
root.add(header);
|
|
4443
5187
|
root.add(body);
|
|
4444
5188
|
this.scroll.add(root);
|
|
@@ -4449,7 +5193,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4449
5193
|
readings.set(label3, row);
|
|
4450
5194
|
body.add(row);
|
|
4451
5195
|
}
|
|
4452
|
-
const detail = key !== "gpu" ? new
|
|
5196
|
+
const detail = key !== "gpu" ? new TextRenderable8(renderer2, {
|
|
4453
5197
|
id: `${root.id}:detail`,
|
|
4454
5198
|
content: "",
|
|
4455
5199
|
width: "100%",
|
|
@@ -4529,7 +5273,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4529
5273
|
this.sections.get("network").detail.content = system?.network.source === "proc-net-dev" ? "All non-loopback interfaces" : system?.network.source === "netstat" ? "Interface en0" : "Interface counters unavailable";
|
|
4530
5274
|
}
|
|
4531
5275
|
button(renderer2, id, label3, activate) {
|
|
4532
|
-
const button = new
|
|
5276
|
+
const button = new TextRenderable8(renderer2, {
|
|
4533
5277
|
id,
|
|
4534
5278
|
content: label3,
|
|
4535
5279
|
height: 1,
|
|
@@ -4592,7 +5336,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4592
5336
|
for (const device of snapshot?.devices ?? []) {
|
|
4593
5337
|
let row = this.rows.get(device.uuid);
|
|
4594
5338
|
if (!row) {
|
|
4595
|
-
const root = new
|
|
5339
|
+
const root = new BoxRenderable9(this._ctx, {
|
|
4596
5340
|
id: `omnius-device:${device.uuid}`,
|
|
4597
5341
|
width: "100%",
|
|
4598
5342
|
flexDirection: "column",
|
|
@@ -4611,9 +5355,9 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4611
5355
|
title.on(RenderableEvents6.FOCUSED, () => this.revealReading(title));
|
|
4612
5356
|
const load = new TelemetryRow(this._ctx, "LOAD", `${root.id}:load`, 16);
|
|
4613
5357
|
const memory = new TelemetryRow(this._ctx, "VRAM", `${root.id}:memory`, 16);
|
|
4614
|
-
const plot = (name) => new
|
|
5358
|
+
const plot = (name) => new TextRenderable8(this._ctx, { id: `${root.id}:${name}-history`, content: "", width: "100%", height: 3, flexShrink: 0, fg: foreground, bg: background, wrapMode: "none", truncate: true, selectable: false });
|
|
4615
5359
|
const loadGraph = plot("load"), memoryGraph = plot("memory"), history = new DeviceHistory();
|
|
4616
|
-
const reason = new
|
|
5360
|
+
const reason = new TextRenderable8(this._ctx, {
|
|
4617
5361
|
id: `${root.id}:reason`,
|
|
4618
5362
|
content: "",
|
|
4619
5363
|
width: "100%",
|
|
@@ -4757,7 +5501,7 @@ var DeviceMonitor = class extends BoxRenderable8 {
|
|
|
4757
5501
|
];
|
|
4758
5502
|
}
|
|
4759
5503
|
};
|
|
4760
|
-
var ChannelMap = class extends
|
|
5504
|
+
var ChannelMap = class extends BoxRenderable9 {
|
|
4761
5505
|
constructor(renderer2, id, inspect, reveal) {
|
|
4762
5506
|
super(renderer2, {
|
|
4763
5507
|
id,
|
|
@@ -4789,7 +5533,7 @@ var ChannelMap = class extends BoxRenderable8 {
|
|
|
4789
5533
|
if (!this.channels.has(agent.id))
|
|
4790
5534
|
this.channels.set(agent.id, this.channels.size + 1);
|
|
4791
5535
|
if (!this.rows.has(agent.id)) {
|
|
4792
|
-
const row = new
|
|
5536
|
+
const row = new TextRenderable8(this._ctx, {
|
|
4793
5537
|
id: `${this.id}:channel:${agent.id}`,
|
|
4794
5538
|
content: "",
|
|
4795
5539
|
width: "100%",
|
|
@@ -4855,7 +5599,7 @@ var ChannelMap = class extends BoxRenderable8 {
|
|
|
4855
5599
|
}
|
|
4856
5600
|
}
|
|
4857
5601
|
};
|
|
4858
|
-
var InstrumentRail = class extends
|
|
5602
|
+
var InstrumentRail = class extends BoxRenderable9 {
|
|
4859
5603
|
workQueue;
|
|
4860
5604
|
workspaceFiles;
|
|
4861
5605
|
taskNotes;
|
|
@@ -4942,7 +5686,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
4942
5686
|
() => this.reveal(this.inferenceHeader)
|
|
4943
5687
|
);
|
|
4944
5688
|
this.scroll.add(this.inferenceHeader);
|
|
4945
|
-
this.inference = new
|
|
5689
|
+
this.inference = new BoxRenderable9(renderer2, {
|
|
4946
5690
|
id: `${id}:inference-body`,
|
|
4947
5691
|
width: "100%",
|
|
4948
5692
|
flexDirection: "column",
|
|
@@ -4957,7 +5701,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
4957
5701
|
};
|
|
4958
5702
|
addRow(this.inference, "route", "ROUTE");
|
|
4959
5703
|
addRow(this.inference, "backend", "BACKEND");
|
|
4960
|
-
this.model = new
|
|
5704
|
+
this.model = new TextRenderable8(renderer2, {
|
|
4961
5705
|
id: `${id}:model`,
|
|
4962
5706
|
content: "MODEL --",
|
|
4963
5707
|
width: "100%",
|
|
@@ -4986,7 +5730,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
4986
5730
|
});
|
|
4987
5731
|
this.contextHeader.on(RenderableEvents6.FOCUSED, () => this.reveal(this.contextHeader));
|
|
4988
5732
|
this.inference.add(this.contextHeader);
|
|
4989
|
-
this.contextDetails = new
|
|
5733
|
+
this.contextDetails = new BoxRenderable9(renderer2, { id: `${id}:context-detail-body`, width: "100%", flexDirection: "column", flexShrink: 0, visible: false });
|
|
4990
5734
|
this.inference.add(this.contextDetails);
|
|
4991
5735
|
this.contextHeader.update("CONTEXT DETAILS", false);
|
|
4992
5736
|
addRow(this.contextDetails, "messages", "MESSAGES");
|
|
@@ -5002,7 +5746,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
5002
5746
|
this.routeAttemptsHeader.visible = false;
|
|
5003
5747
|
this.routeAttemptsHeader.on(RenderableEvents6.FOCUSED, () => this.reveal(this.routeAttemptsHeader));
|
|
5004
5748
|
this.inference.add(this.routeAttemptsHeader);
|
|
5005
|
-
this.routeAttempts = new
|
|
5749
|
+
this.routeAttempts = new BoxRenderable9(renderer2, { id: `${id}:route-attempt-body`, width: "100%", flexDirection: "column", flexShrink: 0, visible: false });
|
|
5006
5750
|
this.inference.add(this.routeAttempts);
|
|
5007
5751
|
this.sessionHeader = new SectionBanner(
|
|
5008
5752
|
renderer2,
|
|
@@ -5015,7 +5759,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
5015
5759
|
() => this.reveal(this.sessionHeader)
|
|
5016
5760
|
);
|
|
5017
5761
|
this.scroll.add(this.sessionHeader);
|
|
5018
|
-
this.session = new
|
|
5762
|
+
this.session = new BoxRenderable9(renderer2, {
|
|
5019
5763
|
id: `${id}:session-body`,
|
|
5020
5764
|
width: "100%",
|
|
5021
5765
|
flexDirection: "column",
|
|
@@ -5113,9 +5857,9 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
5113
5857
|
let row = this.routeAttemptRows[index];
|
|
5114
5858
|
if (!row) {
|
|
5115
5859
|
const id = `${this.routeAttempts.id}:${index}`;
|
|
5116
|
-
const box = new
|
|
5117
|
-
const title2 = new
|
|
5118
|
-
const detail2 = new
|
|
5860
|
+
const box = new BoxRenderable9(this.ctx, { id, width: "100%", flexDirection: "column", flexShrink: 0 });
|
|
5861
|
+
const title2 = new TextRenderable8(this.ctx, { id: `${id}:title`, width: "100%", height: 1, content: "", fg: foreground, bg: background, wrapMode: "none", truncate: true, flexShrink: 0 });
|
|
5862
|
+
const detail2 = new TextRenderable8(this.ctx, { id: `${id}:detail`, width: "100%", content: "", fg: foreground, bg: background, attributes: TextAttributes8.DIM, wrapMode: "word", flexShrink: 0 });
|
|
5119
5863
|
box.add(title2);
|
|
5120
5864
|
box.add(detail2);
|
|
5121
5865
|
this.routeAttempts.add(box);
|
|
@@ -5138,7 +5882,7 @@ var InstrumentRail = class extends BoxRenderable8 {
|
|
|
5138
5882
|
applyTheme(colors) {
|
|
5139
5883
|
this.backgroundColor = colors.background;
|
|
5140
5884
|
const visit = (node) => {
|
|
5141
|
-
if (node instanceof
|
|
5885
|
+
if (node instanceof TextRenderable8) {
|
|
5142
5886
|
node.fg = colors.foreground;
|
|
5143
5887
|
node.bg = colors.background;
|
|
5144
5888
|
}
|
|
@@ -6691,7 +7435,7 @@ var VimComposer = class {
|
|
|
6691
7435
|
};
|
|
6692
7436
|
|
|
6693
7437
|
// packages/cli/src/tui/native/components/selection-menu.ts
|
|
6694
|
-
import { BoxRenderable as
|
|
7438
|
+
import { BoxRenderable as BoxRenderable10, CliRenderEvents as CliRenderEvents6, TextAttributes as TextAttributes9, TextRenderable as TextRenderable9 } from "@opentui/core";
|
|
6695
7439
|
var NativeSelectionMenu = class {
|
|
6696
7440
|
constructor(renderer2, colors, copy, restoreFocus) {
|
|
6697
7441
|
this.renderer = renderer2;
|
|
@@ -6719,7 +7463,7 @@ var NativeSelectionMenu = class {
|
|
|
6719
7463
|
this.selectedText = text;
|
|
6720
7464
|
this.anchor = { x, y };
|
|
6721
7465
|
this.previousFocus = this.renderer.currentFocusedRenderable;
|
|
6722
|
-
this.overlay = new
|
|
7466
|
+
this.overlay = new BoxRenderable10(this.renderer, {
|
|
6723
7467
|
id: "omnius-selection-menu",
|
|
6724
7468
|
position: "absolute",
|
|
6725
7469
|
left: 0,
|
|
@@ -6735,7 +7479,7 @@ var NativeSelectionMenu = class {
|
|
|
6735
7479
|
event.stopPropagation();
|
|
6736
7480
|
}
|
|
6737
7481
|
});
|
|
6738
|
-
this.panel = new
|
|
7482
|
+
this.panel = new BoxRenderable10(this.renderer, {
|
|
6739
7483
|
id: "omnius-selection-menu-panel",
|
|
6740
7484
|
position: "absolute",
|
|
6741
7485
|
width: 14,
|
|
@@ -6749,7 +7493,7 @@ var NativeSelectionMenu = class {
|
|
|
6749
7493
|
event.stopPropagation();
|
|
6750
7494
|
}
|
|
6751
7495
|
});
|
|
6752
|
-
const action = new
|
|
7496
|
+
const action = new TextRenderable9(this.renderer, {
|
|
6753
7497
|
id: "omnius-selection-copy",
|
|
6754
7498
|
content: "COPY",
|
|
6755
7499
|
height: 1,
|
|
@@ -6798,7 +7542,7 @@ var NativeSelectionMenu = class {
|
|
|
6798
7542
|
if (!this.panel) return;
|
|
6799
7543
|
this.panel.backgroundColor = colors.background;
|
|
6800
7544
|
this.frame?.setColors(colors);
|
|
6801
|
-
for (const child of this.panel.getChildren()) if (child instanceof
|
|
7545
|
+
for (const child of this.panel.getChildren()) if (child instanceof TextRenderable9) {
|
|
6802
7546
|
child.fg = colors.foreground;
|
|
6803
7547
|
child.bg = colors.background;
|
|
6804
7548
|
}
|
|
@@ -6824,8 +7568,8 @@ var NativeSelectionMenu = class {
|
|
|
6824
7568
|
};
|
|
6825
7569
|
|
|
6826
7570
|
// packages/cli/src/tui/native/components/tab-strip.ts
|
|
6827
|
-
import { BoxRenderable as
|
|
6828
|
-
var NativeTabStrip = class extends
|
|
7571
|
+
import { BoxRenderable as BoxRenderable11, CliRenderEvents as CliRenderEvents7, ScrollBoxRenderable as ScrollBoxRenderable7, SliderRenderable, TextAttributes as TextAttributes10, TextRenderable as TextRenderable10 } from "@opentui/core";
|
|
7572
|
+
var NativeTabStrip = class extends BoxRenderable11 {
|
|
6829
7573
|
constructor(renderer2, options) {
|
|
6830
7574
|
super(renderer2, {
|
|
6831
7575
|
id: options.id,
|
|
@@ -6908,7 +7652,7 @@ var NativeTabStrip = class extends BoxRenderable10 {
|
|
|
6908
7652
|
for (const action of items) {
|
|
6909
7653
|
let entry = this.buttons.get(action.id);
|
|
6910
7654
|
if (!entry) {
|
|
6911
|
-
const button = new
|
|
7655
|
+
const button = new TextRenderable10(this.renderer, {
|
|
6912
7656
|
id: `${this.options.prefix}:${action.id}`,
|
|
6913
7657
|
content: "",
|
|
6914
7658
|
height: 1,
|
|
@@ -6936,7 +7680,7 @@ var NativeTabStrip = class extends BoxRenderable10 {
|
|
|
6936
7680
|
});
|
|
6937
7681
|
button.on("blurred", () => this.style(entry));
|
|
6938
7682
|
if (this.options.close) {
|
|
6939
|
-
const close2 = new
|
|
7683
|
+
const close2 = new TextRenderable10(this.renderer, {
|
|
6940
7684
|
id: `${this.options.prefix}-close:${action.id}`,
|
|
6941
7685
|
content: "×",
|
|
6942
7686
|
width: 1,
|
|
@@ -7071,13 +7815,13 @@ var NativeFrontend = class {
|
|
|
7071
7815
|
this.renderer = renderer2;
|
|
7072
7816
|
this.emit = emit;
|
|
7073
7817
|
const colors = palette(initialTheme);
|
|
7074
|
-
this.context = { renderer: renderer2, colors, syntax: SyntaxStyle2.fromStyles({}, renderer2.nativeScene), emit, terminals: /* @__PURE__ */ new Map(), mediaViews: /* @__PURE__ */ new Set() };
|
|
7818
|
+
this.context = { renderer: renderer2, colors, syntax: SyntaxStyle2.fromStyles({}, renderer2.nativeScene), emit, terminals: /* @__PURE__ */ new Map(), mediaViews: /* @__PURE__ */ new Set(), modelViews: /* @__PURE__ */ new Set() };
|
|
7075
7819
|
this.disposeSelectionContrast = installDefaultSelectionContrast(renderer2);
|
|
7076
7820
|
this.clipboard = options.clipboard ?? createClipboard({ host: createHostClipboard({ timeoutMs: 1500 }), terminal: createRendererClipboardAdapter(renderer2) });
|
|
7077
7821
|
this.selectionMenu = new NativeSelectionMenu(renderer2, colors, (text) => {
|
|
7078
7822
|
void this.copy(text);
|
|
7079
7823
|
}, () => this.restoreFocus());
|
|
7080
|
-
this.root = new
|
|
7824
|
+
this.root = new BoxRenderable12(renderer2, {
|
|
7081
7825
|
id: "omnius-native",
|
|
7082
7826
|
width: "100%",
|
|
7083
7827
|
height: "100%",
|
|
@@ -7085,7 +7829,7 @@ var NativeFrontend = class {
|
|
|
7085
7829
|
backgroundColor: colors.background
|
|
7086
7830
|
});
|
|
7087
7831
|
renderer2.root.add(this.root);
|
|
7088
|
-
this.header = new
|
|
7832
|
+
this.header = new BoxRenderable12(renderer2, {
|
|
7089
7833
|
id: "omnius-header",
|
|
7090
7834
|
width: "100%",
|
|
7091
7835
|
minWidth: 0,
|
|
@@ -7109,9 +7853,9 @@ var NativeFrontend = class {
|
|
|
7109
7853
|
TextAttributes11.DIM
|
|
7110
7854
|
);
|
|
7111
7855
|
};
|
|
7112
|
-
const headerRow = new
|
|
7856
|
+
const headerRow = new BoxRenderable12(renderer2, { id: "omnius-header-row", width: "100%", minWidth: 0, minHeight: 1, flexDirection: "row", gap: 1 });
|
|
7113
7857
|
this.header.add(headerRow);
|
|
7114
|
-
this.identityMarker = new
|
|
7858
|
+
this.identityMarker = new TextRenderable11(renderer2, {
|
|
7115
7859
|
id: "omnius-marker",
|
|
7116
7860
|
content: "■",
|
|
7117
7861
|
width: 1,
|
|
@@ -7121,7 +7865,7 @@ var NativeFrontend = class {
|
|
|
7121
7865
|
selectable: false
|
|
7122
7866
|
});
|
|
7123
7867
|
headerRow.add(this.identityMarker);
|
|
7124
|
-
this.identity = new
|
|
7868
|
+
this.identity = new TextRenderable11(renderer2, {
|
|
7125
7869
|
id: "omnius-identity",
|
|
7126
7870
|
content: "OMNIUS",
|
|
7127
7871
|
fg: colors.foreground,
|
|
@@ -7159,9 +7903,9 @@ var NativeFrontend = class {
|
|
|
7159
7903
|
verticalScrollbarOptions: { visible: false }
|
|
7160
7904
|
});
|
|
7161
7905
|
headerRow.add(this.headerActions);
|
|
7162
|
-
this.headerPanel = new
|
|
7906
|
+
this.headerPanel = new TextRenderable11(renderer2, { id: "omnius-header-panel", content: "", width: "100%", wrapMode: "word", visible: false });
|
|
7163
7907
|
this.header.add(this.headerPanel);
|
|
7164
|
-
this.detailButton = new
|
|
7908
|
+
this.detailButton = new TextRenderable11(renderer2, {
|
|
7165
7909
|
id: "omnius-details-toggle",
|
|
7166
7910
|
content: "+ DETAILS",
|
|
7167
7911
|
height: 1,
|
|
@@ -7202,7 +7946,7 @@ var NativeFrontend = class {
|
|
|
7202
7946
|
}, 600);
|
|
7203
7947
|
this.identityMarkerTimer.unref?.();
|
|
7204
7948
|
}
|
|
7205
|
-
this.sessionRow = new
|
|
7949
|
+
this.sessionRow = new BoxRenderable12(renderer2, {
|
|
7206
7950
|
id: "omnius-sessions-row",
|
|
7207
7951
|
width: "100%",
|
|
7208
7952
|
height: 1,
|
|
@@ -7221,7 +7965,7 @@ var NativeFrontend = class {
|
|
|
7221
7965
|
close: (id) => this.emitAction("session-close", id)
|
|
7222
7966
|
});
|
|
7223
7967
|
this.sessionRow.add(this.sessions);
|
|
7224
|
-
this.newSession = new
|
|
7968
|
+
this.newSession = new TextRenderable11(renderer2, {
|
|
7225
7969
|
id: "omnius-session-new",
|
|
7226
7970
|
content: "+ NEW",
|
|
7227
7971
|
width: 5,
|
|
@@ -7250,7 +7994,7 @@ var NativeFrontend = class {
|
|
|
7250
7994
|
this.newSession.on("focused", styleNew);
|
|
7251
7995
|
this.newSession.on("blurred", styleNew);
|
|
7252
7996
|
this.sessionRow.add(this.newSession);
|
|
7253
|
-
this.sessionPicker = new
|
|
7997
|
+
this.sessionPicker = new TextRenderable11(renderer2, {
|
|
7254
7998
|
id: "omnius-session-picker",
|
|
7255
7999
|
content: "SESSIONS",
|
|
7256
8000
|
width: 8,
|
|
@@ -7279,9 +8023,9 @@ var NativeFrontend = class {
|
|
|
7279
8023
|
this.sessionPicker.on("focused", stylePicker);
|
|
7280
8024
|
this.sessionPicker.on("blurred", stylePicker);
|
|
7281
8025
|
this.sessionRow.add(this.sessionPicker);
|
|
7282
|
-
this.routeWarning = new
|
|
8026
|
+
this.routeWarning = new TextRenderable11(renderer2, { id: "omnius-route-warning", content: "", width: "100%", wrapMode: "word", fg: colors.warning, attributes: TextAttributes11.BOLD | TextAttributes11.UNDERLINE, visible: false, flexShrink: 0 });
|
|
7283
8027
|
this.root.add(this.routeWarning);
|
|
7284
|
-
this.taskPane = new
|
|
8028
|
+
this.taskPane = new BoxRenderable12(renderer2, { id: "omnius-tasks", width: "100%", flexDirection: "column", maxHeight: 6, flexShrink: 0, overflow: "hidden", visible: false });
|
|
7285
8029
|
this.tasks = new NativeBlockList(this.context, this.taskPane);
|
|
7286
8030
|
this.root.add(this.taskPane);
|
|
7287
8031
|
this.taskStrip = new NativeTaskStrip(renderer2, colors, (id) => {
|
|
@@ -7292,9 +8036,9 @@ var NativeFrontend = class {
|
|
|
7292
8036
|
renderer2.requestRender();
|
|
7293
8037
|
});
|
|
7294
8038
|
this.root.add(this.taskStrip);
|
|
7295
|
-
this.body = new
|
|
8039
|
+
this.body = new BoxRenderable12(renderer2, { id: "omnius-body", width: "100%", flexDirection: "row", flexGrow: 1, minHeight: 1 });
|
|
7296
8040
|
this.root.add(this.body);
|
|
7297
|
-
this.transcriptPane = new
|
|
8041
|
+
this.transcriptPane = new BoxRenderable12(renderer2, { id: "omnius-transcript-pane", flexDirection: "column", flexGrow: 1, flexShrink: 1, minWidth: 0, minHeight: 1 });
|
|
7298
8042
|
this.body.add(this.transcriptPane);
|
|
7299
8043
|
this.scroll = new ScrollBoxRenderable8(renderer2, {
|
|
7300
8044
|
id: "omnius-conversation",
|
|
@@ -7381,7 +8125,7 @@ var NativeFrontend = class {
|
|
|
7381
8125
|
}
|
|
7382
8126
|
});
|
|
7383
8127
|
this.body.add(this.instruments);
|
|
7384
|
-
this.embeddedPane = new
|
|
8128
|
+
this.embeddedPane = new BoxRenderable12(renderer2, {
|
|
7385
8129
|
id: "omnius-editor-pane",
|
|
7386
8130
|
width: "50%",
|
|
7387
8131
|
flexShrink: 0,
|
|
@@ -7392,7 +8136,7 @@ var NativeFrontend = class {
|
|
|
7392
8136
|
visible: false
|
|
7393
8137
|
});
|
|
7394
8138
|
this.body.add(this.embeddedPane);
|
|
7395
|
-
this.liveButton = new
|
|
8139
|
+
this.liveButton = new TextRenderable11(renderer2, {
|
|
7396
8140
|
id: "omnius-live-button",
|
|
7397
8141
|
content: "↓ Live",
|
|
7398
8142
|
width: "100%",
|
|
@@ -7415,7 +8159,7 @@ var NativeFrontend = class {
|
|
|
7415
8159
|
});
|
|
7416
8160
|
this.liveButton.focusable = true;
|
|
7417
8161
|
this.transcriptPane.add(this.liveButton);
|
|
7418
|
-
this.queue = new
|
|
8162
|
+
this.queue = new TextRenderable11(renderer2, { id: "omnius-steering-queue", content: "", width: "100%", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, visible: false, flexShrink: 0 });
|
|
7419
8163
|
this.transcriptPane.add(this.queue);
|
|
7420
8164
|
this.suggestions = new NativeSelectRenderable(renderer2, {
|
|
7421
8165
|
id: "omnius-suggestions",
|
|
@@ -7434,9 +8178,9 @@ var NativeFrontend = class {
|
|
|
7434
8178
|
this.suggestions.onActivate = () => this.acceptSuggestion();
|
|
7435
8179
|
this.suggestions.on("itemSelected", () => this.acceptSuggestion());
|
|
7436
8180
|
this.transcriptPane.add(this.suggestions);
|
|
7437
|
-
this.status = new
|
|
8181
|
+
this.status = new BoxRenderable12(renderer2, { id: "omnius-live-status", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 2, visible: false });
|
|
7438
8182
|
this.transcriptPane.add(this.status);
|
|
7439
|
-
this.footer = new
|
|
8183
|
+
this.footer = new BoxRenderable12(renderer2, {
|
|
7440
8184
|
id: "omnius-input-box",
|
|
7441
8185
|
width: "100%",
|
|
7442
8186
|
flexShrink: 0,
|
|
@@ -7445,7 +8189,7 @@ var NativeFrontend = class {
|
|
|
7445
8189
|
flexDirection: "column"
|
|
7446
8190
|
});
|
|
7447
8191
|
this.root.add(this.footer);
|
|
7448
|
-
this.viewTabsRow = new
|
|
8192
|
+
this.viewTabsRow = new BoxRenderable12(renderer2, {
|
|
7449
8193
|
id: "omnius-view-tabs-row",
|
|
7450
8194
|
width: "100%",
|
|
7451
8195
|
height: 1,
|
|
@@ -7478,7 +8222,7 @@ var NativeFrontend = class {
|
|
|
7478
8222
|
TextAttributes11.DIM
|
|
7479
8223
|
);
|
|
7480
8224
|
};
|
|
7481
|
-
this.footerRule = new
|
|
8225
|
+
this.footerRule = new BoxRenderable12(renderer2, {
|
|
7482
8226
|
id: "omnius-input-rule",
|
|
7483
8227
|
width: "100%",
|
|
7484
8228
|
height: 1,
|
|
@@ -7499,9 +8243,9 @@ var NativeFrontend = class {
|
|
|
7499
8243
|
this.emit(event);
|
|
7500
8244
|
});
|
|
7501
8245
|
this.footer.add(this.workspaceReferences);
|
|
7502
|
-
const inputRow = new
|
|
8246
|
+
const inputRow = new BoxRenderable12(renderer2, { id: "omnius-input-row", width: "100%", flexDirection: "row", gap: 1 });
|
|
7503
8247
|
this.footer.add(inputRow);
|
|
7504
|
-
this.prompt = new
|
|
8248
|
+
this.prompt = new TextRenderable11(renderer2, { id: "omnius-prompt", content: "❯", fg: colors.accent, wrapMode: "none", selectable: false, flexShrink: 0 });
|
|
7505
8249
|
inputRow.add(this.prompt);
|
|
7506
8250
|
this.editor = new TextareaRenderable2(renderer2, {
|
|
7507
8251
|
id: "omnius-input",
|
|
@@ -7521,7 +8265,7 @@ var NativeFrontend = class {
|
|
|
7521
8265
|
onCursorChange: () => this.editorChanged(),
|
|
7522
8266
|
onSubmit: () => this.submit()
|
|
7523
8267
|
});
|
|
7524
|
-
this.vimMode = new
|
|
8268
|
+
this.vimMode = new TextRenderable11(renderer2, {
|
|
7525
8269
|
id: "omnius-vim-mode",
|
|
7526
8270
|
content: "INSERT",
|
|
7527
8271
|
height: 1,
|
|
@@ -7542,17 +8286,17 @@ var NativeFrontend = class {
|
|
|
7542
8286
|
this.renderer.requestRender();
|
|
7543
8287
|
});
|
|
7544
8288
|
inputRow.add(this.editor);
|
|
7545
|
-
this.enhance = new
|
|
8289
|
+
this.enhance = new BoxRenderable12(renderer2, { id: "omnius-enhance", flexDirection: "row", gap: 1, flexShrink: 0, visible: false });
|
|
7546
8290
|
inputRow.add(this.enhance);
|
|
7547
|
-
this.activity = new
|
|
8291
|
+
this.activity = new TextRenderable11(renderer2, { id: "omnius-activity", content: "", flexGrow: 1, minWidth: 0, height: 1, wrapMode: "none", truncate: true, visible: false, fg: colors.accent });
|
|
7548
8292
|
this.status.add(this.activity);
|
|
7549
|
-
this.media = new
|
|
7550
|
-
this.mediaText = new
|
|
8293
|
+
this.media = new BoxRenderable12(renderer2, { id: "omnius-media", height: 1, minWidth: 0, flexShrink: 1, flexDirection: "row", gap: 1, visible: false });
|
|
8294
|
+
this.mediaText = new TextRenderable11(renderer2, { id: "omnius-media-text", content: "", flexGrow: 1, minWidth: 0, wrapMode: "none", truncate: true, fg: colors.accent });
|
|
7551
8295
|
this.media.add(this.mediaText);
|
|
7552
|
-
this.micTrack = new
|
|
8296
|
+
this.micTrack = new TextRenderable11(renderer2, { id: "omnius-mic-meter", width: 12, height: 1, flexShrink: 0, fg: colors.foreground, visible: false });
|
|
7553
8297
|
this.media.add(this.micTrack);
|
|
7554
8298
|
this.status.add(this.media);
|
|
7555
|
-
this.copyFeedback = new
|
|
8299
|
+
this.copyFeedback = new TextRenderable11(renderer2, {
|
|
7556
8300
|
id: "omnius-copy-feedback",
|
|
7557
8301
|
content: "",
|
|
7558
8302
|
height: 1,
|
|
@@ -7563,14 +8307,14 @@ var NativeFrontend = class {
|
|
|
7563
8307
|
visible: false
|
|
7564
8308
|
});
|
|
7565
8309
|
this.status.add(this.copyFeedback);
|
|
7566
|
-
this.metricsRow = new
|
|
7567
|
-
this.keyHints = new
|
|
8310
|
+
this.metricsRow = new BoxRenderable12(renderer2, { id: "omnius-metrics-row", width: "100%", height: 1, flexShrink: 0, flexDirection: "row", gap: 1 });
|
|
8311
|
+
this.keyHints = new TextRenderable11(renderer2, { id: "omnius-key-hints", content: "F1 HELP TAB FOCUS", height: 1, flexShrink: 0, attributes: TextAttributes11.DIM, fg: colors.foreground, selectable: false });
|
|
7568
8312
|
this.metricsRow.add(this.keyHints);
|
|
7569
|
-
this.metricsStartActions = new
|
|
8313
|
+
this.metricsStartActions = new BoxRenderable12(renderer2, { id: "omnius-metrics-start-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
7570
8314
|
this.metricsRow.add(this.metricsStartActions);
|
|
7571
|
-
this.metrics = new
|
|
8315
|
+
this.metrics = new TextRenderable11(renderer2, { id: "omnius-metrics", content: "", height: 1, wrapMode: "none", truncate: true, fg: colors.dim, flexShrink: 1, flexGrow: 1, minWidth: 0 });
|
|
7572
8316
|
this.metricsRow.add(this.metrics);
|
|
7573
|
-
this.metricsEndActions = new
|
|
8317
|
+
this.metricsEndActions = new BoxRenderable12(renderer2, { id: "omnius-metrics-end-actions", flexDirection: "row", gap: 1, flexShrink: 0 });
|
|
7574
8318
|
this.metricsRow.add(this.metricsEndActions);
|
|
7575
8319
|
this.root.add(this.metricsRow);
|
|
7576
8320
|
this.modals = new NativeModalStack(this.context, () => this.restoreFocus());
|
|
@@ -7769,7 +8513,7 @@ var NativeFrontend = class {
|
|
|
7769
8513
|
for (const action of actions) {
|
|
7770
8514
|
const colors = this.context.colors;
|
|
7771
8515
|
const attributes = action.disabled ? TextAttributes11.DIM : action.active ? TextAttributes11.BOLD | TextAttributes11.UNDERLINE : 0;
|
|
7772
|
-
const button = new
|
|
8516
|
+
const button = new TextRenderable11(this.renderer, {
|
|
7773
8517
|
id: `${prefix}:${action.id}`,
|
|
7774
8518
|
content: styledText(action.label),
|
|
7775
8519
|
flexShrink: 0,
|
|
@@ -8006,7 +8750,9 @@ var NativeFrontend = class {
|
|
|
8006
8750
|
const height = Math.max(1, Math.min(8, this.editor.editorView.getTotalVirtualLineCount(), this.renderer.terminalHeight - 8));
|
|
8007
8751
|
if (height !== this.editor.height) this.editor.height = height;
|
|
8008
8752
|
this.layoutTabStrips();
|
|
8009
|
-
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);
|
|
8753
|
+
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 && !this.modals.active);
|
|
8754
|
+
for (const model of this.context.modelViews ?? []) model.reconcile(this.scroll.viewport, !this.paused && !this.modals.active);
|
|
8755
|
+
this.modals.reconcileMedia();
|
|
8010
8756
|
const offset2 = this.offset;
|
|
8011
8757
|
if (offset2 === 0) this.newEntries = 0;
|
|
8012
8758
|
this.liveButton.visible = offset2 > 0;
|
|
@@ -8451,6 +9197,8 @@ var NativeFrontend = class {
|
|
|
8451
9197
|
}
|
|
8452
9198
|
pauseMedia() {
|
|
8453
9199
|
for (const media of this.context.mediaViews ?? []) media.pausePlayback();
|
|
9200
|
+
for (const model of this.context.modelViews ?? []) model.pauseRendering();
|
|
9201
|
+
this.modals.pauseMedia();
|
|
8454
9202
|
}
|
|
8455
9203
|
captureInterfaceState() {
|
|
8456
9204
|
this.flushLatestInput();
|
|
@@ -8515,10 +9263,16 @@ var NativeFrontend = class {
|
|
|
8515
9263
|
media.pausePlayback();
|
|
8516
9264
|
return media.closed;
|
|
8517
9265
|
});
|
|
9266
|
+
mediaClosed.push(...[...this.context.modelViews ?? []].map((model) => {
|
|
9267
|
+
model.pauseRendering();
|
|
9268
|
+
return model.closed;
|
|
9269
|
+
}));
|
|
9270
|
+
mediaClosed.push(...this.modals.pauseMedia());
|
|
8518
9271
|
this.modals.destroy();
|
|
8519
9272
|
this.content.destroy();
|
|
8520
9273
|
this.tasks.destroy();
|
|
8521
9274
|
await Promise.allSettled(mediaClosed);
|
|
9275
|
+
await this.modals.settleMedia();
|
|
8522
9276
|
this.root.destroyRecursively();
|
|
8523
9277
|
this.context.syntax.destroy();
|
|
8524
9278
|
await this.clipboard.dispose();
|
|
@@ -8663,7 +9417,7 @@ try {
|
|
|
8663
9417
|
screenMode: "alternate-screen",
|
|
8664
9418
|
consoleMode: "disabled",
|
|
8665
9419
|
externalOutputMode: "passthrough",
|
|
8666
|
-
backgroundColor:
|
|
9420
|
+
backgroundColor: RGBA4.defaultBackground(),
|
|
8667
9421
|
openConsoleOnError: false,
|
|
8668
9422
|
targetFps: 60,
|
|
8669
9423
|
maxFps: 60,
|