mimetic-cli 0.1.3 → 0.1.5
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/README.md +67 -12
- package/dist/env-file.d.ts +14 -0
- package/dist/env-file.js +108 -0
- package/dist/env-file.js.map +1 -0
- package/dist/feedback.d.ts +7 -5
- package/dist/feedback.js +61 -4
- package/dist/feedback.js.map +1 -1
- package/dist/init-templates.js +29 -0
- package/dist/init-templates.js.map +1 -1
- package/dist/lab-app-runner.d.ts +78 -0
- package/dist/lab-app-runner.js +403 -0
- package/dist/lab-app-runner.js.map +1 -0
- package/dist/labs.d.ts +67 -0
- package/dist/labs.js +257 -0
- package/dist/labs.js.map +1 -0
- package/dist/observer-assets.js +473 -25
- package/dist/observer-assets.js.map +1 -1
- package/dist/observer.d.ts +6 -0
- package/dist/observer.js +49 -8
- package/dist/observer.js.map +1 -1
- package/dist/oss-lab.d.ts +1 -1
- package/dist/oss-lab.js +6 -6
- package/dist/oss-lab.js.map +1 -1
- package/dist/oss-meta-lab.d.ts +113 -1
- package/dist/oss-meta-lab.js +2753 -200
- package/dist/oss-meta-lab.js.map +1 -1
- package/dist/oss-remote-telemetry.d.ts +77 -0
- package/dist/oss-remote-telemetry.js +393 -0
- package/dist/oss-remote-telemetry.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.js +668 -70
- package/dist/program.js.map +1 -1
- package/dist/run.d.ts +105 -3
- package/dist/run.js +684 -22
- package/dist/run.js.map +1 -1
- package/docs/architecture/local-codex-tui-actor.md +9 -6
- package/docs/architecture/oss-lab-poc.md +119 -47
- package/docs/architecture/project-layout.md +40 -6
- package/docs/assets/mimetic-oss-lab-observer.png +0 -0
- package/docs/contracts/feedback.md +15 -12
- package/docs/contracts/policy.md +9 -2
- package/docs/contracts/run-bundle.md +62 -0
- package/docs/contracts/schemas.md +21 -0
- package/docs/goals/current.md +50 -17
- package/docs/product/open-source-install-experience.md +63 -8
- package/docs/ramp/README.md +26 -8
- package/docs/roadmap/world-class-open-source-v0.md +41 -20
- package/package.json +9 -6
- package/skills/mimetic-cli/SKILL.md +89 -4
- package/skills/mimetic-cli/agents/openai.yaml +1 -1
package/dist/observer-assets.js
CHANGED
|
@@ -416,6 +416,10 @@ a { color: inherit; text-decoration: none; }
|
|
|
416
416
|
|
|
417
417
|
/* ============================================================ STREAM SURFACES */
|
|
418
418
|
.surface-fill { position: absolute; inset: 0; width: 100%; height: 100%; }
|
|
419
|
+
.live-stream-mount { position: absolute; inset: 0; overflow: hidden; background: #000; }
|
|
420
|
+
.live-stream-overlay { position: absolute; overflow: hidden; pointer-events: none; z-index: 2; }
|
|
421
|
+
.live-stream-overlay[data-focus="true"] .bw-lab-dock { max-height: 86px; }
|
|
422
|
+
.live-stream-overlay[data-focus="true"] .bw-chip-v { max-width: min(420px, 38vw); }
|
|
419
423
|
|
|
420
424
|
/* browser/ui mock */
|
|
421
425
|
.bw { position: absolute; inset: 0; display: flex; flex-direction: column; background: #0b0d10; }
|
|
@@ -435,6 +439,35 @@ a { color: inherit; text-decoration: none; }
|
|
|
435
439
|
.bw-viewport { flex: 1; position: relative; overflow: hidden; background: #fbfcfd; }
|
|
436
440
|
.bw-app-wait { position: absolute; inset: 0; display: grid; place-items: center; align-content: center; gap: 8px; background: #fbfcfd; color: #5a626c; text-align: center; padding: 16px; }
|
|
437
441
|
.bw-app-wait .wait-spinner { border-color: rgba(20,28,40,.12); border-top-color: var(--accent); }
|
|
442
|
+
.bw-lab-dock {
|
|
443
|
+
position: absolute; left: 8px; right: 8px; bottom: 8px; z-index: 8;
|
|
444
|
+
display: flex; align-items: flex-end; gap: 5px; flex-wrap: wrap;
|
|
445
|
+
max-height: 54px; overflow: hidden; pointer-events: none;
|
|
446
|
+
}
|
|
447
|
+
.bw-lab-chip {
|
|
448
|
+
min-width: 0; max-width: 100%; pointer-events: auto;
|
|
449
|
+
display: inline-flex; align-items: center; gap: 5px;
|
|
450
|
+
padding: 3px 7px; border-radius: 6px;
|
|
451
|
+
background: rgba(8,10,13,.78); backdrop-filter: blur(8px);
|
|
452
|
+
border: 1px solid rgba(255,255,255,.12);
|
|
453
|
+
color: var(--text-2); box-shadow: var(--shadow-1);
|
|
454
|
+
}
|
|
455
|
+
a.bw-lab-chip:hover { border-color: rgba(255,255,255,.22); color: var(--text-1); }
|
|
456
|
+
.bw-lab-chip[data-tone="live"] { color: var(--accent-2); border-color: color-mix(in oklab, var(--accent) 35%, transparent); }
|
|
457
|
+
.bw-lab-chip[data-tone="ok"] { color: var(--green); border-color: color-mix(in oklab, var(--green) 34%, transparent); }
|
|
458
|
+
.bw-lab-chip[data-tone="warn"] { color: var(--amber); border-color: color-mix(in oklab, var(--amber) 34%, transparent); }
|
|
459
|
+
.bw-lab-chip[data-tone="err"] { color: var(--red); border-color: color-mix(in oklab, var(--red) 34%, transparent); }
|
|
460
|
+
.bw-chip-k {
|
|
461
|
+
flex: none; font-family: var(--mono); font-size: 8.5px; letter-spacing: .08em;
|
|
462
|
+
text-transform: uppercase; color: currentColor;
|
|
463
|
+
}
|
|
464
|
+
.bw-chip-v {
|
|
465
|
+
min-width: 0; max-width: min(240px, 42vw);
|
|
466
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
467
|
+
font-family: var(--mono); font-size: 9px; color: var(--text-2);
|
|
468
|
+
}
|
|
469
|
+
.focus-stage-area .bw-lab-dock { max-height: 86px; }
|
|
470
|
+
.focus-stage-area .bw-chip-v { max-width: min(420px, 38vw); }
|
|
438
471
|
.bw-cursor {
|
|
439
472
|
position: absolute; width: 16px; height: 16px; z-index: 5; pointer-events: none;
|
|
440
473
|
transition: left 1.1s var(--ease), top 1.1s var(--ease);
|
|
@@ -611,12 +644,47 @@ a { color: inherit; text-decoration: none; }
|
|
|
611
644
|
|
|
612
645
|
.file-row { display: flex; align-items: center; gap: 11px; padding: 11px 16px; border-bottom: 1px solid var(--line); transition: background .14s; }
|
|
613
646
|
.file-row:hover { background: var(--surface-1); }
|
|
647
|
+
.file-row[data-selected="true"] { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--accent); }
|
|
648
|
+
.file-row > button, .file-row > a:not(.file-open) { display: flex; align-items: center; gap: 11px; min-width: 0; flex: 1; text-align: left; }
|
|
614
649
|
.file-ic { width: 28px; height: 28px; border-radius: 7px; display: grid; place-items: center; background: var(--surface-2); border: 1px solid var(--line); color: var(--text-2); flex: none; }
|
|
615
650
|
.file-ic svg { width: 14px; height: 14px; }
|
|
616
651
|
.file-meta { min-width: 0; flex: 1; }
|
|
617
652
|
.file-name { font-size: 12.5px; color: var(--text-1); }
|
|
618
653
|
.file-path { font-family: var(--mono); font-size: 9.5px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
619
654
|
.file-kind { font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); padding: 2px 7px; border-radius: 5px; background: var(--surface-2); flex: none; }
|
|
655
|
+
.file-open { font-family: var(--mono); font-size: 9px; color: var(--accent-2); padding: 3px 6px; border-radius: 5px; border: 1px solid var(--line); flex: none; }
|
|
656
|
+
.file-open:hover { background: var(--surface-3); }
|
|
657
|
+
.file-inspector { border-bottom: 1px solid var(--line); background: var(--surface-1); }
|
|
658
|
+
.fi-head { padding: 14px 16px 12px; border-bottom: 1px solid var(--line); }
|
|
659
|
+
.fi-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
660
|
+
.fi-title h3 { margin: 0; font-size: 13px; font-weight: 600; letter-spacing: -0.01em; }
|
|
661
|
+
.fi-status { font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .08em; padding: 2px 7px; border-radius: 999px; background: var(--surface-3); color: var(--text-2); }
|
|
662
|
+
.fi-status[data-status="passed"] { background: var(--green-soft); color: var(--green); }
|
|
663
|
+
.fi-status[data-status="needs_review"], .fi-status[data-status="blocked"] { background: var(--amber-soft); color: var(--amber); }
|
|
664
|
+
.fi-summary { margin-top: 7px; color: var(--text-2); font-size: 11.5px; line-height: 1.45; }
|
|
665
|
+
.fi-section { padding: 12px 16px; border-bottom: 1px solid var(--line); }
|
|
666
|
+
.fi-section:last-child { border-bottom: 0; }
|
|
667
|
+
.fi-section-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
|
|
668
|
+
.fi-section-title span:first-child { font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-3); }
|
|
669
|
+
.fi-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
|
|
670
|
+
.fi-stat { padding: 8px; border: 1px solid var(--line); border-radius: 7px; background: var(--surface-0); min-width: 0; }
|
|
671
|
+
.fi-stat-k { font-family: var(--mono); font-size: 8.5px; color: var(--text-3); text-transform: uppercase; letter-spacing: .08em; }
|
|
672
|
+
.fi-stat-v { margin-top: 2px; font-size: 13px; font-weight: 600; color: var(--text-1); overflow-wrap: anywhere; }
|
|
673
|
+
.fi-check { display: grid; grid-template-columns: auto 1fr; gap: 8px; padding: 8px 0; border-top: 1px solid var(--line); }
|
|
674
|
+
.fi-check:first-child { border-top: 0; padding-top: 0; }
|
|
675
|
+
.fi-dot { width: 18px; height: 18px; border-radius: 6px; display: grid; place-items: center; background: var(--surface-2); border: 1px solid var(--line); color: var(--text-3); }
|
|
676
|
+
.fi-check[data-ok="true"] .fi-dot { color: var(--green); border-color: color-mix(in oklab, var(--green) 30%, transparent); background: var(--green-soft); }
|
|
677
|
+
.fi-check[data-ok="false"] .fi-dot { color: var(--amber); border-color: color-mix(in oklab, var(--amber) 30%, transparent); background: var(--amber-soft); }
|
|
678
|
+
.fi-check-name { font-size: 12px; color: var(--text-1); }
|
|
679
|
+
.fi-check-detail { margin-top: 2px; font-size: 11px; color: var(--text-3); line-height: 1.4; }
|
|
680
|
+
.fi-tree { max-height: 260px; overflow: auto; border: 1px solid var(--line); border-radius: 7px; background: var(--surface-0); padding: 7px 0; }
|
|
681
|
+
.fi-tree-row { display: grid; grid-template-columns: auto 1fr auto; gap: 7px; padding: 3px 9px; font-family: var(--mono); font-size: 9.5px; color: var(--text-2); }
|
|
682
|
+
.fi-tree-row[data-type="directory"] { color: var(--accent-2); }
|
|
683
|
+
.fi-tree-size { color: var(--text-4); }
|
|
684
|
+
.fi-pre { margin: 0; max-height: 320px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font-family: var(--mono); font-size: 10px; line-height: 1.45; background: var(--surface-0); border: 1px solid var(--line); border-radius: 7px; padding: 10px; color: var(--text-2); }
|
|
685
|
+
.fi-preview + .fi-preview { margin-top: 10px; }
|
|
686
|
+
.fi-preview-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 5px; font-family: var(--mono); font-size: 9.5px; color: var(--text-3); }
|
|
687
|
+
.fi-load { padding: 24px 16px; color: var(--text-3); text-align: center; }
|
|
620
688
|
|
|
621
689
|
.tab-empty { padding: 36px 24px; text-align: center; color: var(--text-3); font-size: 12px; }
|
|
622
690
|
|
|
@@ -679,16 +747,25 @@ html[data-theme="light"] .scrim { background: rgba(20,28,40,.32); }
|
|
|
679
747
|
.lane-count .lc-label { display: none; }
|
|
680
748
|
}
|
|
681
749
|
@media (max-width: 860px) {
|
|
682
|
-
.focus {
|
|
750
|
+
.focus { display: block; height: 100%; min-height: 0; overflow-y: auto; }
|
|
683
751
|
.focus-rail { display: none; }
|
|
752
|
+
.focus-stage { min-height: auto; }
|
|
753
|
+
.focus-bar { position: sticky; top: 0; z-index: 25; }
|
|
754
|
+
.focus-stage-area {
|
|
755
|
+
display: block; min-height: min(60vh, 560px); height: auto;
|
|
756
|
+
padding: 14px; overflow: visible;
|
|
757
|
+
}
|
|
758
|
+
.focus-frame {
|
|
759
|
+
width: 100%; height: auto; max-height: none;
|
|
760
|
+
min-height: 280px;
|
|
761
|
+
}
|
|
684
762
|
.focus-side {
|
|
685
|
-
position:
|
|
686
|
-
max-height:
|
|
687
|
-
border-radius:
|
|
688
|
-
transform: translateY(calc(100% - 52px)); transition: transform .3s var(--ease);
|
|
763
|
+
position: relative; left: auto; right: auto; bottom: auto; top: auto; z-index: auto;
|
|
764
|
+
min-height: 360px; max-height: none; border-left: none; border-top: 1px solid var(--line-2);
|
|
765
|
+
border-radius: 0; box-shadow: none; transform: none;
|
|
689
766
|
}
|
|
690
|
-
.focus-side[data-sheet="open"] { transform:
|
|
691
|
-
.sheet-grip { display:
|
|
767
|
+
.focus-side[data-sheet="open"], .focus-side[data-sheet="closed"] { transform: none; }
|
|
768
|
+
.sheet-grip { display: none; }
|
|
692
769
|
}
|
|
693
770
|
.sheet-grip { display: none; align-items: center; justify-content: center; gap: 8px; height: 40px; flex: none; border-bottom: 1px solid var(--line); cursor: grab; }
|
|
694
771
|
.sheet-grip::before { content: ""; width: 36px; height: 4px; border-radius: 2px; background: var(--line-3); }
|
|
@@ -892,6 +969,7 @@ export function observerClientJs() {
|
|
|
892
969
|
|
|
893
970
|
// ---------------------------------------------------------------- hydrate
|
|
894
971
|
var DATA_FILE = "observer-data.json";
|
|
972
|
+
var REFRESH_MS = 5000;
|
|
895
973
|
var dataEl = document.getElementById("observer-data");
|
|
896
974
|
var currentData = null;
|
|
897
975
|
try { currentData = JSON.parse((dataEl && dataEl.textContent) || "null"); } catch (e) { currentData = null; }
|
|
@@ -924,9 +1002,10 @@ export function observerClientJs() {
|
|
|
924
1002
|
}
|
|
925
1003
|
|
|
926
1004
|
// ---------------------------------------------------------------- state
|
|
1005
|
+
var initialFocusId = focusFromHash();
|
|
927
1006
|
var S = {
|
|
928
|
-
view: "grid",
|
|
929
|
-
focusedId:
|
|
1007
|
+
view: initialFocusId ? "focus" : "grid",
|
|
1008
|
+
focusedId: initialFocusId,
|
|
930
1009
|
statusSel: [],
|
|
931
1010
|
kindSel: [],
|
|
932
1011
|
query: "",
|
|
@@ -935,6 +1014,7 @@ export function observerClientJs() {
|
|
|
935
1014
|
detailsOpen: false,
|
|
936
1015
|
tweaksOpen: false,
|
|
937
1016
|
consoleOpen: false,
|
|
1017
|
+
filePath: null,
|
|
938
1018
|
railCollapsed: !!readPref("railCollapsed", false),
|
|
939
1019
|
sideCollapsed: !!readPref("sideCollapsed", false),
|
|
940
1020
|
sheetOpen: false,
|
|
@@ -945,6 +1025,10 @@ export function observerClientJs() {
|
|
|
945
1025
|
statusViz: readPref("statusViz", "badges"),
|
|
946
1026
|
motion: readPref("motion", "full")
|
|
947
1027
|
};
|
|
1028
|
+
var artifactCache = {};
|
|
1029
|
+
var liveStreamFrames = {};
|
|
1030
|
+
var liveStreamHost = null;
|
|
1031
|
+
var liveStreamLayoutRaf = null;
|
|
948
1032
|
|
|
949
1033
|
// ---------------------------------------------------------------- tone / labels
|
|
950
1034
|
var TONE = {
|
|
@@ -1009,7 +1093,7 @@ export function observerClientJs() {
|
|
|
1009
1093
|
|
|
1010
1094
|
// ---------------------------------------------------------------- derive (observer-data.v1 -> display)
|
|
1011
1095
|
function laneName(s) { return s.label || (s.sim && s.sim.summary) || s.id || "lane"; }
|
|
1012
|
-
function laneRoute(s) { return (s.ui && s.ui.route) || s.url || (s.terminal && s.terminal.title) || ""; }
|
|
1096
|
+
function laneRoute(s) { return (s.ui && (s.ui.route || s.ui.appUrl || s.ui.nestedObserverUrl)) || s.url || (s.terminal && s.terminal.title) || ""; }
|
|
1013
1097
|
function laneProgress(s) {
|
|
1014
1098
|
if (s.sim && typeof s.sim.progress === "number") return Math.max(0, Math.min(100, Math.round(s.sim.progress)));
|
|
1015
1099
|
var t = tone(s.status);
|
|
@@ -1086,6 +1170,107 @@ export function observerClientJs() {
|
|
|
1086
1170
|
while (arr.length && arr[arr.length - 1].trim() === "") arr.pop();
|
|
1087
1171
|
return arr.map(function (line) { return { text: line, cls: classify(line) }; });
|
|
1088
1172
|
}
|
|
1173
|
+
function clip(v, n) {
|
|
1174
|
+
var s = String(v == null ? "" : v).trim();
|
|
1175
|
+
if (!s) return "";
|
|
1176
|
+
return s.length > n ? (s.slice(0, Math.max(0, n - 1)) + "…") : s;
|
|
1177
|
+
}
|
|
1178
|
+
function shortSurfaceValue(v) {
|
|
1179
|
+
var s = String(v == null ? "" : v).trim();
|
|
1180
|
+
if (!s) return "";
|
|
1181
|
+
var cut = s.split("?")[0].split("#")[0];
|
|
1182
|
+
var parts = cut.split("/");
|
|
1183
|
+
var tail = parts.filter(function (p) { return !!p; }).slice(-2).join("/");
|
|
1184
|
+
return clip(tail || cut || s, 48);
|
|
1185
|
+
}
|
|
1186
|
+
function linkHref(v, artifactPath) {
|
|
1187
|
+
var raw = String(v == null ? "" : v).trim();
|
|
1188
|
+
var low = raw.toLowerCase();
|
|
1189
|
+
if (!raw) return "";
|
|
1190
|
+
if (low.indexOf("http://") === 0 || low.indexOf("https://") === 0 || low.indexOf("file:") === 0) return raw;
|
|
1191
|
+
if (raw.indexOf("://") >= 0) return "";
|
|
1192
|
+
if (raw.charAt(0) === "/" || raw.indexOf("..") >= 0) return "";
|
|
1193
|
+
return artifactPath ? ("../" + raw) : raw;
|
|
1194
|
+
}
|
|
1195
|
+
function firstArtifactKind(s, kind) {
|
|
1196
|
+
var arts = laneArtifacts(s);
|
|
1197
|
+
for (var i = 0; i < arts.length; i += 1) {
|
|
1198
|
+
if (arts[i] && arts[i].kind === kind) return arts[i];
|
|
1199
|
+
}
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
function artifactKinds(arts) {
|
|
1203
|
+
var seen = {}, out = [];
|
|
1204
|
+
arts.forEach(function (a) {
|
|
1205
|
+
var k = (a && a.kind) || "file";
|
|
1206
|
+
if (!seen[k]) { seen[k] = true; out.push(k); }
|
|
1207
|
+
});
|
|
1208
|
+
var shown = out.slice(0, 3).join("+");
|
|
1209
|
+
return shown + (out.length > 3 ? "+" : "");
|
|
1210
|
+
}
|
|
1211
|
+
function terminalExcerpt(s) {
|
|
1212
|
+
var lines = termLines(s).filter(function (ln) { return !!String(ln.text || "").trim(); });
|
|
1213
|
+
if (!lines.length) return "";
|
|
1214
|
+
return clip(lines[lines.length - 1].text, 88);
|
|
1215
|
+
}
|
|
1216
|
+
function completionTone(c) {
|
|
1217
|
+
var t = tone(c && c.status);
|
|
1218
|
+
return t === "running" ? "live" : t === "complete" ? "ok" : t === "blocked" ? "warn" : c && c.status === "failed" ? "err" : "info";
|
|
1219
|
+
}
|
|
1220
|
+
function completionText(c) {
|
|
1221
|
+
if (!c) return "";
|
|
1222
|
+
var bits = [statusLabel(c.status)];
|
|
1223
|
+
if (typeof c.exitCode === "number") bits.push("exit " + c.exitCode);
|
|
1224
|
+
if (typeof c.nestedObserverPresent === "boolean") bits.push("observer " + (c.nestedObserverPresent ? "present" : "missing"));
|
|
1225
|
+
if (typeof c.nestedVerifyPassed === "boolean") bits.push("verify " + (c.nestedVerifyPassed ? "passed" : "failed"));
|
|
1226
|
+
if (c.reason) bits.push(c.reason);
|
|
1227
|
+
return clip(bits.join(" · "), 110);
|
|
1228
|
+
}
|
|
1229
|
+
function labChip(kind, label, detail, href, toneName) {
|
|
1230
|
+
var title = label + (detail ? ": " + detail : "");
|
|
1231
|
+
var inner = '<span class="bw-chip-k">' + esc(label) + '</span>' + (detail ? '<span class="bw-chip-v">' + esc(detail) + '</span>' : "");
|
|
1232
|
+
var attrs = ' class="bw-lab-chip" data-kind="' + esc(kind) + '" data-tone="' + esc(toneName || "info") + '" title="' + esc(title) + '"';
|
|
1233
|
+
if (href) return '<a' + attrs + ' href="' + esc(href) + '" target="_blank" rel="noopener noreferrer" data-action="external">' + inner + '</a>';
|
|
1234
|
+
return '<span' + attrs + '>' + inner + '</span>';
|
|
1235
|
+
}
|
|
1236
|
+
function browserLiveUrl(s) {
|
|
1237
|
+
return (s.embed && s.embed.kind === "iframe" && s.embed.url) || s.url || "";
|
|
1238
|
+
}
|
|
1239
|
+
function liveStreamMount(s, liveUrl) {
|
|
1240
|
+
return '<div class="live-stream-mount surface-fill" data-live-stream-id="' + esc(s.id) + '" data-live-stream-url="' + esc(liveUrl) + '" data-live-stream-title="' + esc(laneName(s) || "live stream") + '">'
|
|
1241
|
+
+ '<div class="bw-app-wait"><div class="wait-spinner" style="width:24px;height:24px"></div>'
|
|
1242
|
+
+ '<div class="mono" style="font-size:9px">connecting live stream</div></div></div>';
|
|
1243
|
+
}
|
|
1244
|
+
function browserShot(s) {
|
|
1245
|
+
var art = firstArtifactKind(s, "screenshot");
|
|
1246
|
+
return (s.ui && s.ui.screenshotUrl) || (s.embed && s.embed.kind === "screenshot" && s.embed.url) || (art && linkHref(art.path, true)) || "";
|
|
1247
|
+
}
|
|
1248
|
+
function browserHasLabSignals(s) {
|
|
1249
|
+
var ui = s.ui || {};
|
|
1250
|
+
return !!(browserLiveUrl(s) || browserShot(s) || ui.appUrl || ui.nestedObserverUrl || ui.nestedObserverPath || ui.state || s.completion || terminalExcerpt(s) || laneArtifacts(s).length);
|
|
1251
|
+
}
|
|
1252
|
+
function browserLabDock(s, shot) {
|
|
1253
|
+
var ui = s.ui || {};
|
|
1254
|
+
var chips = [];
|
|
1255
|
+
var appUrl = ui.appUrl || "";
|
|
1256
|
+
var nestedArt = firstArtifactKind(s, "observer");
|
|
1257
|
+
var nested = ui.nestedObserverUrl || ui.nestedObserverPath || (nestedArt && nestedArt.path) || "";
|
|
1258
|
+
var completion = s.completion || null;
|
|
1259
|
+
var shotArt = firstArtifactKind(s, "screenshot");
|
|
1260
|
+
var arts = laneArtifacts(s);
|
|
1261
|
+
var tail = terminalExcerpt(s);
|
|
1262
|
+
|
|
1263
|
+
if (appUrl) chips.push(labChip("app", "app", shortSurfaceValue(appUrl), linkHref(appUrl, false), "live"));
|
|
1264
|
+
if (nested) chips.push(labChip("observer", "observer", shortSurfaceValue(nested), linkHref(nested, !!(nestedArt && nested === nestedArt.path)), "info"));
|
|
1265
|
+
else if (completion && typeof completion.nestedObserverPresent === "boolean") chips.push(labChip("observer", "observer", completion.nestedObserverPresent ? "present" : "missing", "", completion.nestedObserverPresent ? "ok" : "warn"));
|
|
1266
|
+
if (completion) chips.push(labChip("completion", "status", completionText(completion), "", completionTone(completion)));
|
|
1267
|
+
if (tail) chips.push(labChip("terminal", "terminal", tail, "", "info"));
|
|
1268
|
+
if (shot || shotArt) chips.push(labChip("screenshot", "shot", shot ? (S.media === "screenshot" ? "viewing fallback" : "fallback ready") : "artifact", shot ? linkHref(shot, false) : linkHref(shotArt.path, true), "info"));
|
|
1269
|
+
if (arts.length) chips.push(labChip("artifact", "files", arts.length + " " + artifactKinds(arts), "", "info"));
|
|
1270
|
+
if (ui.state && !completion) chips.push(labChip("state", "state", clip(ui.state, 72), "", "info"));
|
|
1271
|
+
if (!chips.length) return "";
|
|
1272
|
+
return '<div class="bw-lab-dock" aria-label="Browser lane lab surfaces">' + chips.slice(0, 6).join("") + '</div>';
|
|
1273
|
+
}
|
|
1089
1274
|
|
|
1090
1275
|
function consoleLines() {
|
|
1091
1276
|
var rows = [];
|
|
@@ -1159,16 +1344,19 @@ export function observerClientJs() {
|
|
|
1159
1344
|
function browserSurface(s) {
|
|
1160
1345
|
var live = tone(s.status) === "running";
|
|
1161
1346
|
var route = laneRoute(s) || "(local)";
|
|
1162
|
-
var
|
|
1347
|
+
var liveUrl = browserLiveUrl(s);
|
|
1348
|
+
var shot = browserShot(s);
|
|
1349
|
+
var dock = browserLabDock(s, shot);
|
|
1163
1350
|
var body;
|
|
1164
|
-
if (
|
|
1351
|
+
if (liveUrl && S.media === "live") body = liveStreamMount(s, liveUrl);
|
|
1352
|
+
else if (shot) body = '<img class="surface-fill" style="object-fit:cover;object-position:top" src="' + esc(shot) + '" alt="viewport screenshot"/>';
|
|
1165
1353
|
else body = '<div class="bw-app-wait"><div class="wait-spinner" style="width:24px;height:24px"></div>'
|
|
1166
1354
|
+ '<div class="mono" style="font-size:9px">' + esc(route) + '</div>'
|
|
1167
1355
|
+ '<div style="font-size:10px">' + esc(laneStep(s)) + '</div></div>';
|
|
1168
1356
|
return '<div class="bw">'
|
|
1169
1357
|
+ '<div class="bw-chrome"><div class="bw-dots"><i></i><i></i><i></i></div>'
|
|
1170
1358
|
+ '<div class="bw-url">' + icon("lock", 8) + '<span>' + esc(route) + '</span></div></div>'
|
|
1171
|
-
+ '<div class="bw-viewport">' + body + '</div>'
|
|
1359
|
+
+ '<div class="bw-viewport">' + body + (liveUrl && S.media === "live" ? "" : dock) + '</div>'
|
|
1172
1360
|
+ (live ? liveTag() : "")
|
|
1173
1361
|
+ '</div>';
|
|
1174
1362
|
}
|
|
@@ -1210,9 +1398,9 @@ export function observerClientJs() {
|
|
|
1210
1398
|
function streamSurface(s, focus) {
|
|
1211
1399
|
var k = s.kind, st = s.status;
|
|
1212
1400
|
var hasTail = !!(s.terminal && s.terminal.tail && String(s.terminal.tail).trim());
|
|
1213
|
-
if ((st === "blocked" || st === "timed_out") && !hasTail) return waitSurface(s);
|
|
1401
|
+
if ((st === "blocked" || st === "timed_out") && !hasTail && !((k === "ui" || k === "browser") && browserHasLabSignals(s))) return waitSurface(s);
|
|
1214
1402
|
if (k === "ui" || k === "browser") {
|
|
1215
|
-
if (st === "blocked" || st === "timed_out" || st === "failed" || st === "contract_proof_only") return waitSurface(s);
|
|
1403
|
+
if ((st === "blocked" || st === "timed_out" || st === "failed" || st === "contract_proof_only") && !browserHasLabSignals(s)) return waitSurface(s);
|
|
1216
1404
|
return browserSurface(s);
|
|
1217
1405
|
}
|
|
1218
1406
|
if (k === "terminal" || k === "tui") return hasTail ? terminalSurface(s, focus) : waitSurface(s);
|
|
@@ -1393,6 +1581,113 @@ export function observerClientJs() {
|
|
|
1393
1581
|
if (kind === "codex-ui") return "spark";
|
|
1394
1582
|
return "globe";
|
|
1395
1583
|
}
|
|
1584
|
+
function artifactHref(a) {
|
|
1585
|
+
return a && a.path ? linkHref(a.path, true) : "";
|
|
1586
|
+
}
|
|
1587
|
+
function ensureArtifactLoaded(a) {
|
|
1588
|
+
if (!a || !a.path || a.kind !== "filesystem") return;
|
|
1589
|
+
var key = a.path;
|
|
1590
|
+
if (artifactCache[key]) return;
|
|
1591
|
+
if (location.protocol === "file:") {
|
|
1592
|
+
artifactCache[key] = { status: "offline", text: "", json: null };
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
var href = artifactHref(a);
|
|
1596
|
+
if (!href) {
|
|
1597
|
+
artifactCache[key] = { status: "error", text: "", json: null, error: "Artifact path is not fetchable." };
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
artifactCache[key] = { status: "loading", text: "", json: null };
|
|
1601
|
+
fetch(href, { cache: "no-store" }).then(function (r) {
|
|
1602
|
+
if (!r.ok) throw new Error("HTTP " + r.status);
|
|
1603
|
+
return r.text();
|
|
1604
|
+
}).then(function (text) {
|
|
1605
|
+
var json = null;
|
|
1606
|
+
try { json = JSON.parse(text); } catch (e) {}
|
|
1607
|
+
artifactCache[key] = { status: "loaded", text: text, json: json };
|
|
1608
|
+
render();
|
|
1609
|
+
}).catch(function (e) {
|
|
1610
|
+
artifactCache[key] = { status: "error", text: "", json: null, error: e && e.message ? e.message : "Fetch failed." };
|
|
1611
|
+
render();
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
function formatBytes(n) {
|
|
1615
|
+
if (typeof n !== "number" || !isFinite(n)) return "";
|
|
1616
|
+
if (n < 1024) return n + "b";
|
|
1617
|
+
if (n < 1024 * 1024) return Math.round(n / 102.4) / 10 + "kb";
|
|
1618
|
+
return Math.round(n / 1024 / 102.4) / 10 + "mb";
|
|
1619
|
+
}
|
|
1620
|
+
function renderGenericArtifact(a, state) {
|
|
1621
|
+
if (!state || state.status === "loading") return '<div class="fi-load"><span class="wait-spinner" style="width:18px;height:18px;display:inline-block;vertical-align:middle;margin-right:8px"></span>Loading artifact…</div>';
|
|
1622
|
+
if (state.status === "offline") return '<div class="fi-load">Static file view cannot hydrate artifacts inline. Open the artifact link directly.</div>';
|
|
1623
|
+
if (state.status === "error") return '<div class="fi-load">Could not load artifact: ' + esc(state.error || "unknown error") + '</div>';
|
|
1624
|
+
return '<div class="file-inspector"><div class="fi-head"><div class="fi-title"><h3>' + esc(a.label || a.path) + '</h3><span class="fi-status">artifact</span></div>'
|
|
1625
|
+
+ '<div class="fi-summary mono">' + esc(a.path) + '</div></div>'
|
|
1626
|
+
+ '<div class="fi-section"><pre class="fi-pre">' + esc(state.text || "") + '</pre></div></div>';
|
|
1627
|
+
}
|
|
1628
|
+
function renderSetupQualityArtifact(a, state) {
|
|
1629
|
+
if (!state || state.status !== "loaded" || !state.json || state.json.schema !== "mimetic.setup-quality.v1") {
|
|
1630
|
+
return renderGenericArtifact(a, state);
|
|
1631
|
+
}
|
|
1632
|
+
var q = state.json;
|
|
1633
|
+
var checks = q.checks || [];
|
|
1634
|
+
var mim = q.mimetic || {};
|
|
1635
|
+
var scripts = q.packageScripts || {};
|
|
1636
|
+
var tree = q.tree || [];
|
|
1637
|
+
var previews = q.previews || [];
|
|
1638
|
+
var scriptRows = Object.keys(scripts).sort().slice(0, 18).map(function (key) {
|
|
1639
|
+
return '<div class="fi-tree-row"><span>$</span><span>' + esc(key) + '</span><span class="fi-tree-size">' + esc(scripts[key]) + '</span></div>';
|
|
1640
|
+
}).join("");
|
|
1641
|
+
var treeRows = tree.slice(0, 160).map(function (entry) {
|
|
1642
|
+
return '<div class="fi-tree-row" data-type="' + esc(entry.type || "file") + '"><span>' + (entry.type === "directory" ? "dir" : "file") + '</span><span>' + esc(entry.path) + '</span><span class="fi-tree-size">' + esc(formatBytes(entry.sizeBytes)) + '</span></div>';
|
|
1643
|
+
}).join("");
|
|
1644
|
+
var previewRows = previews.length ? previews.map(function (preview) {
|
|
1645
|
+
return '<div class="fi-preview"><div class="fi-preview-head"><span>' + esc(preview.path) + '</span><span>' + esc(preview.language || "text") + (preview.truncated ? " · truncated" : "") + '</span></div><pre class="fi-pre">' + esc(preview.text || "") + '</pre></div>';
|
|
1646
|
+
}).join("") : '<div class="tab-empty">No raw file previews persisted for this run.</div>';
|
|
1647
|
+
return '<div class="file-inspector"><div class="fi-head"><div class="fi-title"><h3>Setup quality</h3><span class="fi-status" data-status="' + esc(q.status || "unknown") + '">' + esc(q.status || "unknown") + '</span></div>'
|
|
1648
|
+
+ '<div class="fi-summary">' + esc(q.summary || "") + '</div><div class="fi-summary mono">' + esc(a.path) + '</div></div>'
|
|
1649
|
+
+ '<div class="fi-section"><div class="fi-grid">'
|
|
1650
|
+
+ '<div class="fi-stat"><div class="fi-stat-k">personas</div><div class="fi-stat-v">' + esc(mim.personaCount || 0) + '</div></div>'
|
|
1651
|
+
+ '<div class="fi-stat"><div class="fi-stat-k">scenarios</div><div class="fi-stat-v">' + esc(mim.scenarioCount || 0) + '</div></div>'
|
|
1652
|
+
+ '<div class="fi-stat"><div class="fi-stat-k">config</div><div class="fi-stat-v">' + (mim.configPresent ? "present" : "missing") + '</div></div>'
|
|
1653
|
+
+ '<div class="fi-stat"><div class="fi-stat-k">runtime ignore</div><div class="fi-stat-v">' + (mim.gitignoreContainsRuntimeIgnore ? "present" : "missing") + '</div></div>'
|
|
1654
|
+
+ '</div></div>'
|
|
1655
|
+
+ '<div class="fi-section"><div class="fi-section-title"><span>Checks</span><span class="mono">' + checks.filter(function (c) { return c.ok; }).length + ' / ' + checks.length + '</span></div>'
|
|
1656
|
+
+ checks.map(function (check) { return '<div class="fi-check" data-ok="' + (check.ok ? "true" : "false") + '"><span class="fi-dot">' + icon(check.ok ? "check" : "alert", 11) + '</span><div><div class="fi-check-name">' + esc(check.label) + '</div><div class="fi-check-detail">' + esc(check.detail) + '</div></div></div>'; }).join("") + '</div>'
|
|
1657
|
+
+ '<div class="fi-section"><div class="fi-section-title"><span>Package scripts</span><span class="mono">' + Object.keys(scripts).length + '</span></div><div class="fi-tree">' + (scriptRows || '<div class="tab-empty">No package scripts captured.</div>') + '</div></div>'
|
|
1658
|
+
+ '<div class="fi-section"><div class="fi-section-title"><span>Tree</span><span class="mono">' + tree.length + '</span></div><div class="fi-tree">' + (treeRows || '<div class="tab-empty">No tree entries captured.</div>') + '</div></div>'
|
|
1659
|
+
+ '<div class="fi-section"><div class="fi-section-title"><span>Previews</span><span class="mono">' + previews.length + '</span></div>' + previewRows + '</div></div>';
|
|
1660
|
+
}
|
|
1661
|
+
function buildFilesTab(s) {
|
|
1662
|
+
var arts = laneArtifacts(s);
|
|
1663
|
+
if (!arts.length) return '<div class="tab-empty">No evidence artifacts linked.</div>';
|
|
1664
|
+
var selected = null;
|
|
1665
|
+
for (var i = 0; i < arts.length; i += 1) {
|
|
1666
|
+
if (arts[i].path === S.filePath) { selected = arts[i]; break; }
|
|
1667
|
+
}
|
|
1668
|
+
if (!selected) {
|
|
1669
|
+
for (var j = 0; j < arts.length; j += 1) {
|
|
1670
|
+
if (arts[j].kind === "filesystem") { selected = arts[j]; break; }
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
var inspector = "";
|
|
1674
|
+
if (selected && selected.kind === "filesystem") {
|
|
1675
|
+
ensureArtifactLoaded(selected);
|
|
1676
|
+
inspector = renderSetupQualityArtifact(selected, artifactCache[selected.path]);
|
|
1677
|
+
}
|
|
1678
|
+
var rows = arts.map(function (a) {
|
|
1679
|
+
var href = artifactHref(a);
|
|
1680
|
+
var isSelected = selected && selected.path === a.path;
|
|
1681
|
+
var inspectable = a.kind === "filesystem";
|
|
1682
|
+
var main = inspectable
|
|
1683
|
+
? '<button data-action="inspect-file:' + esc(a.path) + '"><span class="file-ic">' + icon("file", 14) + '</span><span class="file-meta"><div class="file-name">' + esc(a.label) + '</div><div class="file-path mono">' + esc(a.path) + '</div></span><span class="file-kind">' + esc(a.kind) + '</span></button>'
|
|
1684
|
+
: '<a href="' + esc(href) + '" target="_blank" rel="noopener noreferrer" data-action="external"><span class="file-ic">' + icon("file", 14) + '</span><span class="file-meta"><div class="file-name">' + esc(a.label) + '</div><div class="file-path mono">' + esc(a.path) + '</div></span><span class="file-kind">' + esc(a.kind) + '</span></a>';
|
|
1685
|
+
return '<div class="file-row" data-selected="' + (isSelected ? "true" : "false") + '">' + main
|
|
1686
|
+
+ (href ? '<a class="file-open" href="' + esc(href) + '" target="_blank" rel="noopener noreferrer" data-action="external">open</a>' : "")
|
|
1687
|
+
+ '</div>';
|
|
1688
|
+
}).join("");
|
|
1689
|
+
return inspector + rows;
|
|
1690
|
+
}
|
|
1396
1691
|
function buildSideBody(s) {
|
|
1397
1692
|
if (S.tab === "events") {
|
|
1398
1693
|
var evs = laneEvents(s);
|
|
@@ -1404,13 +1699,7 @@ export function observerClientJs() {
|
|
|
1404
1699
|
}).join("");
|
|
1405
1700
|
}
|
|
1406
1701
|
if (S.tab === "files") {
|
|
1407
|
-
|
|
1408
|
-
if (!arts.length) return '<div class="tab-empty">No evidence artifacts linked.</div>';
|
|
1409
|
-
return arts.map(function (a) {
|
|
1410
|
-
return '<a class="file-row" href="../' + esc(a.path) + '"><span class="file-ic">' + icon("file", 14) + '</span>'
|
|
1411
|
-
+ '<span class="file-meta"><div class="file-name">' + esc(a.label) + '</div><div class="file-path mono">' + esc(a.path) + '</div></span>'
|
|
1412
|
-
+ '<span class="file-kind">' + esc(a.kind) + '</span></a>';
|
|
1413
|
-
}).join("");
|
|
1702
|
+
return buildFilesTab(s);
|
|
1414
1703
|
}
|
|
1415
1704
|
var lines = termLines(s);
|
|
1416
1705
|
if (!lines.length) lines = [{ text: "No log text recorded for this lane.", cls: "dim" }];
|
|
@@ -1596,6 +1885,141 @@ export function observerClientJs() {
|
|
|
1596
1885
|
menu.style.left = left + "px";
|
|
1597
1886
|
menu.style.visibility = "visible";
|
|
1598
1887
|
}
|
|
1888
|
+
function ensureLiveStreamHost() {
|
|
1889
|
+
if (liveStreamHost) return liveStreamHost;
|
|
1890
|
+
if (!document.createElement) return null;
|
|
1891
|
+
var host = document.body || document.documentElement;
|
|
1892
|
+
if (!host || !host.appendChild) return null;
|
|
1893
|
+
liveStreamHost = document.createElement("div");
|
|
1894
|
+
liveStreamHost.setAttribute("data-live-stream-host", "true");
|
|
1895
|
+
liveStreamHost.style.position = "fixed";
|
|
1896
|
+
liveStreamHost.style.inset = "0";
|
|
1897
|
+
liveStreamHost.style.overflow = "visible";
|
|
1898
|
+
liveStreamHost.style.pointerEvents = "none";
|
|
1899
|
+
liveStreamHost.style.zIndex = "20";
|
|
1900
|
+
host.appendChild(liveStreamHost);
|
|
1901
|
+
return liveStreamHost;
|
|
1902
|
+
}
|
|
1903
|
+
function createLiveStreamRecord(id, url, title) {
|
|
1904
|
+
var host = ensureLiveStreamHost();
|
|
1905
|
+
if (!host) return null;
|
|
1906
|
+
var wrapper = document.createElement("div");
|
|
1907
|
+
wrapper.setAttribute("data-live-stream-wrapper", id);
|
|
1908
|
+
wrapper.style.position = "fixed";
|
|
1909
|
+
wrapper.style.overflow = "hidden";
|
|
1910
|
+
wrapper.style.background = "#000";
|
|
1911
|
+
wrapper.style.pointerEvents = "none";
|
|
1912
|
+
wrapper.style.display = "none";
|
|
1913
|
+
var frame = document.createElement("iframe");
|
|
1914
|
+
frame.style.position = "absolute";
|
|
1915
|
+
frame.style.border = "0";
|
|
1916
|
+
frame.style.margin = "0";
|
|
1917
|
+
frame.style.display = "block";
|
|
1918
|
+
frame.setAttribute("allow", "clipboard-read; clipboard-write; fullscreen");
|
|
1919
|
+
frame.setAttribute("referrerpolicy", "no-referrer");
|
|
1920
|
+
frame.setAttribute("title", title || "live stream");
|
|
1921
|
+
frame.setAttribute("data-live-stream-frame", id);
|
|
1922
|
+
frame.src = url;
|
|
1923
|
+
var overlay = document.createElement("div");
|
|
1924
|
+
overlay.className = "live-stream-overlay";
|
|
1925
|
+
overlay.style.position = "absolute";
|
|
1926
|
+
overlay.style.overflow = "hidden";
|
|
1927
|
+
overlay.style.pointerEvents = "none";
|
|
1928
|
+
overlay.style.zIndex = "2";
|
|
1929
|
+
wrapper.appendChild(frame);
|
|
1930
|
+
wrapper.appendChild(overlay);
|
|
1931
|
+
host.appendChild(wrapper);
|
|
1932
|
+
return { url: url, wrapper: wrapper, frame: frame, overlay: overlay, overlayHtml: "" };
|
|
1933
|
+
}
|
|
1934
|
+
function removeLiveStreamRecord(id) {
|
|
1935
|
+
var rec = liveStreamFrames[id];
|
|
1936
|
+
if (rec && rec.wrapper && rec.wrapper.parentNode) rec.wrapper.parentNode.removeChild(rec.wrapper);
|
|
1937
|
+
delete liveStreamFrames[id];
|
|
1938
|
+
}
|
|
1939
|
+
function hideLiveStreamRecord(rec) {
|
|
1940
|
+
if (!rec || !rec.wrapper) return;
|
|
1941
|
+
rec.wrapper.style.display = "none";
|
|
1942
|
+
rec.wrapper.style.pointerEvents = "none";
|
|
1943
|
+
}
|
|
1944
|
+
function clipRect(rect) {
|
|
1945
|
+
var stage = app.querySelector && app.querySelector(".stage");
|
|
1946
|
+
var s = stage && stage.getBoundingClientRect ? stage.getBoundingClientRect() : null;
|
|
1947
|
+
var left = Math.max(rect.left, 0, s ? s.left : 0);
|
|
1948
|
+
var top = Math.max(rect.top, 0, s ? s.top : 0);
|
|
1949
|
+
var right = Math.min(rect.right, window.innerWidth || rect.right, s ? s.right : rect.right);
|
|
1950
|
+
var bottom = Math.min(rect.bottom, window.innerHeight || rect.bottom, s ? s.bottom : rect.bottom);
|
|
1951
|
+
return { left: left, top: top, right: right, bottom: bottom, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
|
|
1952
|
+
}
|
|
1953
|
+
function layoutLiveStreamRecord(rec, mount, overlayHtml) {
|
|
1954
|
+
if (!rec || !mount || !mount.getBoundingClientRect) return hideLiveStreamRecord(rec);
|
|
1955
|
+
var rect = mount.getBoundingClientRect();
|
|
1956
|
+
var clipped = clipRect(rect);
|
|
1957
|
+
if (rect.width < 2 || rect.height < 2 || clipped.width < 2 || clipped.height < 2) return hideLiveStreamRecord(rec);
|
|
1958
|
+
rec.wrapper.style.display = "block";
|
|
1959
|
+
rec.wrapper.style.left = clipped.left + "px";
|
|
1960
|
+
rec.wrapper.style.top = clipped.top + "px";
|
|
1961
|
+
rec.wrapper.style.width = clipped.width + "px";
|
|
1962
|
+
rec.wrapper.style.height = clipped.height + "px";
|
|
1963
|
+
rec.wrapper.style.pointerEvents = S.view === "focus" ? "auto" : "none";
|
|
1964
|
+
rec.frame.style.left = (rect.left - clipped.left) + "px";
|
|
1965
|
+
rec.frame.style.top = (rect.top - clipped.top) + "px";
|
|
1966
|
+
rec.frame.style.width = rect.width + "px";
|
|
1967
|
+
rec.frame.style.height = rect.height + "px";
|
|
1968
|
+
rec.frame.style.pointerEvents = S.view === "focus" ? "auto" : "none";
|
|
1969
|
+
if (rec.overlay) {
|
|
1970
|
+
rec.overlay.style.left = rec.frame.style.left;
|
|
1971
|
+
rec.overlay.style.top = rec.frame.style.top;
|
|
1972
|
+
rec.overlay.style.width = rec.frame.style.width;
|
|
1973
|
+
rec.overlay.style.height = rec.frame.style.height;
|
|
1974
|
+
rec.overlay.setAttribute("data-focus", S.view === "focus" ? "true" : "false");
|
|
1975
|
+
if (rec.overlayHtml !== overlayHtml) {
|
|
1976
|
+
rec.overlay.innerHTML = overlayHtml || "";
|
|
1977
|
+
rec.overlayHtml = overlayHtml || "";
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
function reconcileLiveStreams() {
|
|
1982
|
+
if (!app.querySelectorAll || !document.createElement) return;
|
|
1983
|
+
var known = {};
|
|
1984
|
+
currentData.streams.forEach(function (s) {
|
|
1985
|
+
var url = browserLiveUrl(s);
|
|
1986
|
+
if (url) known[s.id] = { url: url, stream: s };
|
|
1987
|
+
});
|
|
1988
|
+
var mounts = app.querySelectorAll("[data-live-stream-id]");
|
|
1989
|
+
var visible = {};
|
|
1990
|
+
Array.prototype.forEach.call(mounts, function (mount) {
|
|
1991
|
+
var id = mount.getAttribute("data-live-stream-id");
|
|
1992
|
+
var url = mount.getAttribute("data-live-stream-url") || "";
|
|
1993
|
+
var title = mount.getAttribute("data-live-stream-title") || "live stream";
|
|
1994
|
+
if (!id || !url) return;
|
|
1995
|
+
var knownStream = known[id] && known[id].stream;
|
|
1996
|
+
var overlayHtml = knownStream ? browserLabDock(knownStream, browserShot(knownStream)) : "";
|
|
1997
|
+
var rec = liveStreamFrames[id];
|
|
1998
|
+
if (!rec || rec.url !== url) {
|
|
1999
|
+
removeLiveStreamRecord(id);
|
|
2000
|
+
rec = createLiveStreamRecord(id, url, title);
|
|
2001
|
+
if (!rec) return;
|
|
2002
|
+
liveStreamFrames[id] = rec;
|
|
2003
|
+
} else {
|
|
2004
|
+
rec.frame.setAttribute("title", title);
|
|
2005
|
+
}
|
|
2006
|
+
visible[id] = true;
|
|
2007
|
+
layoutLiveStreamRecord(rec, mount, overlayHtml);
|
|
2008
|
+
});
|
|
2009
|
+
Object.keys(liveStreamFrames).forEach(function (id) {
|
|
2010
|
+
var rec = liveStreamFrames[id];
|
|
2011
|
+
if (!known[id] || (rec && rec.url !== known[id].url)) removeLiveStreamRecord(id);
|
|
2012
|
+
else if (!visible[id]) hideLiveStreamRecord(rec);
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
function scheduleLiveStreamLayout() {
|
|
2016
|
+
if (liveStreamLayoutRaf != null) return;
|
|
2017
|
+
var raf = window.requestAnimationFrame || function (fn) { return window.setTimeout(fn, 16); };
|
|
2018
|
+
liveStreamLayoutRaf = raf(function () {
|
|
2019
|
+
liveStreamLayoutRaf = null;
|
|
2020
|
+
reconcileLiveStreams();
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
1599
2023
|
|
|
1600
2024
|
function render() {
|
|
1601
2025
|
var docEl = document.documentElement;
|
|
@@ -1631,6 +2055,7 @@ export function observerClientJs() {
|
|
|
1631
2055
|
if (inp) { inp.focus(); try { inp.setSelectionRange(caret, caret); } catch (e) {} }
|
|
1632
2056
|
}
|
|
1633
2057
|
placeMenus();
|
|
2058
|
+
reconcileLiveStreams();
|
|
1634
2059
|
var cb = document.getElementById("console-body");
|
|
1635
2060
|
if (cb && scrolls[".console-body"] == null) cb.scrollTop = cb.scrollHeight;
|
|
1636
2061
|
}
|
|
@@ -1689,6 +2114,7 @@ export function observerClientJs() {
|
|
|
1689
2114
|
if (arg === "status") toggleArr(S.statusSel, arg2); else toggleArr(S.kindSel, arg2);
|
|
1690
2115
|
render(); break;
|
|
1691
2116
|
case "toggle-console": S.consoleOpen = !S.consoleOpen; render(); break;
|
|
2117
|
+
case "inspect-file": S.filePath = action.slice("inspect-file:".length); S.tab = "files"; render(); break;
|
|
1692
2118
|
case "toggle-details": S.detailsOpen = !S.detailsOpen; S.tweaksOpen = false; render(); break;
|
|
1693
2119
|
case "toggle-tweaks": S.tweaksOpen = !S.tweaksOpen; S.detailsOpen = false; render(); break;
|
|
1694
2120
|
case "toggle-theme": S.theme = (S.theme === "light" ? "dark" : "light"); writePref("theme", S.theme); render(); break;
|
|
@@ -1758,11 +2184,33 @@ export function observerClientJs() {
|
|
|
1758
2184
|
S.focusedId = next; if (S.view !== "focus") S.view = "focus"; render();
|
|
1759
2185
|
}
|
|
1760
2186
|
});
|
|
1761
|
-
window.addEventListener("resize", function () { if (openDd) placeMenus(); });
|
|
2187
|
+
window.addEventListener("resize", function () { if (openDd) placeMenus(); scheduleLiveStreamLayout(); });
|
|
2188
|
+
app.addEventListener("scroll", scheduleLiveStreamLayout, true);
|
|
1762
2189
|
|
|
1763
2190
|
// ================================================================ POLLING
|
|
1764
2191
|
function dataKey(d) {
|
|
1765
|
-
|
|
2192
|
+
var streams = (d.streams || []).map(function (s) {
|
|
2193
|
+
return {
|
|
2194
|
+
id: s.id,
|
|
2195
|
+
status: s.status,
|
|
2196
|
+
progress: laneProgress(s),
|
|
2197
|
+
step: laneStep(s),
|
|
2198
|
+
updatedAt: s.updatedAt,
|
|
2199
|
+
url: browserLiveUrl(s),
|
|
2200
|
+
route: laneRoute(s),
|
|
2201
|
+
tail: (s.terminalPlain || (s.terminal && s.terminal.tail) || "").slice(-1200),
|
|
2202
|
+
artifacts: (s.artifacts || []).map(function (a) { return [a.kind, a.path, a.label]; }),
|
|
2203
|
+
completion: s.completion || null
|
|
2204
|
+
};
|
|
2205
|
+
});
|
|
2206
|
+
var events = (d.events || []).slice(-200).map(function (e) { return [e.at, e.level, e.type, e.simId, e.streamId, e.message]; });
|
|
2207
|
+
var run = d.run || {};
|
|
2208
|
+
return JSON.stringify({
|
|
2209
|
+
run: [run.runId, run.status, (run.lifecycle || []).length, (run.knownGaps || []).length],
|
|
2210
|
+
summary: d.summary || {},
|
|
2211
|
+
streams: streams,
|
|
2212
|
+
events: events
|
|
2213
|
+
});
|
|
1766
2214
|
}
|
|
1767
2215
|
function refresh() {
|
|
1768
2216
|
if (location.protocol === "file:") return Promise.resolve();
|
|
@@ -1794,7 +2242,7 @@ export function observerClientJs() {
|
|
|
1794
2242
|
render();
|
|
1795
2243
|
refresh().then(function () {
|
|
1796
2244
|
if (location.protocol !== "file:") {
|
|
1797
|
-
refreshTimer = setInterval(refresh,
|
|
2245
|
+
refreshTimer = setInterval(refresh, REFRESH_MS);
|
|
1798
2246
|
refreshHistoryIndex();
|
|
1799
2247
|
historyTimer = setInterval(refreshHistoryIndex, 30000);
|
|
1800
2248
|
}
|