@loompad/cli 1.2.2 → 1.2.3
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/CHANGELOG.md +28 -0
- package/dist/cli/index.js +33 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/core/crew.d.ts +16 -1
- package/dist/core/crew.js +26 -2
- package/dist/core/crew.js.map +1 -1
- package/dist/core/orchestra.d.ts +36 -0
- package/dist/core/orchestra.js +149 -82
- package/dist/core/orchestra.js.map +1 -1
- package/dist/core/team-hub.d.ts +2 -1
- package/dist/core/team-hub.js +1 -1
- package/dist/core/team-hub.js.map +1 -1
- package/dist/core/team-leases.d.ts +7 -0
- package/dist/core/team-leases.js +19 -0
- package/dist/core/team-leases.js.map +1 -1
- package/dist/daemon/client.d.ts +9 -1
- package/dist/daemon/client.js +2 -2
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/routes/brain.js +2 -2
- package/dist/daemon/routes/brain.js.map +1 -1
- package/dist/daemon/routes/orchestra.js +1 -0
- package/dist/daemon/routes/orchestra.js.map +1 -1
- package/dist/daemon/runner.d.ts +11 -0
- package/dist/daemon/runner.js +96 -3
- package/dist/daemon/runner.js.map +1 -1
- package/dist/daemon/runtime/briefings.js +12 -1
- package/dist/daemon/runtime/briefings.js.map +1 -1
- package/dist/daemon/runtime.d.ts +9 -2
- package/dist/daemon/runtime.js +8 -4
- package/dist/daemon/runtime.js.map +1 -1
- package/dist/daemon/team-coordinator.d.ts +27 -3
- package/dist/daemon/team-coordinator.js +54 -2
- package/dist/daemon/team-coordinator.js.map +1 -1
- package/dist/daemon/team.d.ts +9 -1
- package/dist/daemon/team.js +44 -1
- package/dist/daemon/team.js.map +1 -1
- package/dist/hub/supabase-client.d.ts +4 -2
- package/dist/hub/supabase-client.js +21 -12
- package/dist/hub/supabase-client.js.map +1 -1
- package/dist/web/app.css +4 -0
- package/dist/web/app.js +96 -27
- package/dist/web/app.js.map +3 -3
- package/docs/release-notes/v1.2.3.md +29 -0
- package/docs/teams.md +28 -0
- package/package.json +1 -1
package/dist/web/app.js
CHANGED
|
@@ -875,9 +875,36 @@
|
|
|
875
875
|
}
|
|
876
876
|
__name(copyText, "copyText");
|
|
877
877
|
|
|
878
|
+
// src/web/mode.js
|
|
879
|
+
var KEY = "loomDevMode";
|
|
880
|
+
function devMode() {
|
|
881
|
+
try {
|
|
882
|
+
return localStorage.getItem(KEY) === "1";
|
|
883
|
+
} catch (e) {
|
|
884
|
+
return false;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
__name(devMode, "devMode");
|
|
888
|
+
function applyMode() {
|
|
889
|
+
var dev = devMode();
|
|
890
|
+
document.documentElement.classList.toggle("simple", !dev);
|
|
891
|
+
document.documentElement.classList.toggle("devmode", dev);
|
|
892
|
+
}
|
|
893
|
+
__name(applyMode, "applyMode");
|
|
894
|
+
function setDevMode(on) {
|
|
895
|
+
try {
|
|
896
|
+
localStorage.setItem(KEY, on ? "1" : "0");
|
|
897
|
+
} catch (e) {
|
|
898
|
+
}
|
|
899
|
+
applyMode();
|
|
900
|
+
}
|
|
901
|
+
__name(setDevMode, "setDevMode");
|
|
902
|
+
var SIMPLE_TABS = ["thread", "team", "fleet", "board", "brain"];
|
|
903
|
+
|
|
878
904
|
// src/web/layout.js
|
|
879
905
|
var RAIL_KEY = "loomRail";
|
|
880
906
|
function railOpen() {
|
|
907
|
+
if (document.documentElement.classList.contains("simple")) return false;
|
|
881
908
|
var v = localStorage.getItem(RAIL_KEY);
|
|
882
909
|
return v === null ? (window.innerWidth || 0) >= 1440 : v === "1";
|
|
883
910
|
}
|
|
@@ -1853,6 +1880,8 @@
|
|
|
1853
1880
|
__name(patchCfg, "patchCfg");
|
|
1854
1881
|
function renderPrefs() {
|
|
1855
1882
|
var h = '<div class="setphead">Preferences</div>';
|
|
1883
|
+
h += '<div class="sgrouph">Mode</div>';
|
|
1884
|
+
h += '<div class="prow"><div class="pl"><div class="pt">Developer mode</div><div class="pd">' + (devMode() ? "On: Orchestra, Crew, Insights and its metrics, the terminal, console, browser, the right-hand panel, MCPs and skills, and the cost meter." : "Off: Loom shows chat, your team, your agents, the board and memory. Turn it on for Orchestra, Crew, metrics, the terminal and the rest.") + '</div></div><div class="pc">' + seg("devmode", [{ v: "simple", l: "Simple" }, { v: "dev", l: "Developer" }], devMode() ? "dev" : "simple") + "</div></div>";
|
|
1856
1885
|
h += '<div class="sgrouph">Appearance</div>';
|
|
1857
1886
|
h += '<div class="prow"><div class="pl"><div class="pt">Theme</div><div class="pd">Light or dark. Open terminals repaint to match.</div></div><div class="pc">' + seg("theme", [{ v: "light", l: "Light" }, { v: "dark", l: "Dark" }, { v: "system", l: "System" }], themePref()) + "</div></div>";
|
|
1858
1887
|
h += '<div class="prow"><div class="pl"><div class="pt">Text size</div><div class="pd">Scales the whole app on this device.</div></div><div class="pc">' + seg("textsize", [{ v: "s", l: "S" }, { v: "m", l: "M" }, { v: "l", l: "L" }, { v: "xl", l: "XL" }], appearancePref("textsize", "m")) + "</div></div>";
|
|
@@ -1866,6 +1895,12 @@
|
|
|
1866
1895
|
h += '<div class="prow"><div class="pl"><div class="pt">Chime</div><div class="pd">A soft two-note sound with it.</div></div><div class="pc">' + seg("chime", [{ v: "on", l: "On" }, { v: "off", l: "Off" }], devicePref("chime", false) ? "on" : "off") + "</div></div>";
|
|
1867
1896
|
h += '<div id="projprefs"></div>';
|
|
1868
1897
|
pane.innerHTML = h;
|
|
1898
|
+
bindSeg("devmode", function(v) {
|
|
1899
|
+
setDevMode(v === "dev");
|
|
1900
|
+
toast(v === "dev" ? "Developer mode on \u2014 every tool is back" : "Simple mode \u2014 just what you need");
|
|
1901
|
+
if (state.rerender) state.rerender();
|
|
1902
|
+
renderPrefs();
|
|
1903
|
+
});
|
|
1869
1904
|
bindSeg("notifydone", function(v) {
|
|
1870
1905
|
setDevicePref("notifyDone", v === "on");
|
|
1871
1906
|
if (v === "on" && !window.loomNative && window.Notification && Notification.permission === "default") {
|
|
@@ -3373,6 +3408,10 @@
|
|
|
3373
3408
|
}
|
|
3374
3409
|
return true;
|
|
3375
3410
|
}, "needProject");
|
|
3411
|
+
if (!devMode() && devOnly(item)) {
|
|
3412
|
+
toast("That\u2019s a Developer mode tool \u2014 turn it on in Settings \u2192 Preferences");
|
|
3413
|
+
return;
|
|
3414
|
+
}
|
|
3376
3415
|
if (item.indexOf("tab:") === 0) {
|
|
3377
3416
|
if (needProject()) state.showTab(item.slice(4));
|
|
3378
3417
|
return;
|
|
@@ -3614,6 +3653,12 @@
|
|
|
3614
3653
|
].map(function(c) {
|
|
3615
3654
|
return { id: c[0], label: c[1], keys: c[2], icon: c[3], needsProject: c[4] };
|
|
3616
3655
|
});
|
|
3656
|
+
var DEV_COMMANDS = { orchestrate: 1, crew: 1, prompts: 1, tools: 1, "toggle-rail": 1, "toggle-terminal": 1, "toggle-browser": 1, console: 1 };
|
|
3657
|
+
function devOnly(id) {
|
|
3658
|
+
if (id.indexOf("tab:") === 0) return SIMPLE_TABS.indexOf(id.slice(4)) < 0;
|
|
3659
|
+
return !!DEV_COMMANDS[id];
|
|
3660
|
+
}
|
|
3661
|
+
__name(devOnly, "devOnly");
|
|
3617
3662
|
|
|
3618
3663
|
// src/web/palette.js
|
|
3619
3664
|
function openPalette() {
|
|
@@ -3694,14 +3739,15 @@
|
|
|
3694
3739
|
__name(shq, "shq");
|
|
3695
3740
|
var CMDS = buildCommands();
|
|
3696
3741
|
function buildCommands() {
|
|
3742
|
+
var dev = devMode();
|
|
3697
3743
|
var C = COMMANDS.filter(function(c) {
|
|
3698
|
-
return !c.needsProject || pid;
|
|
3744
|
+
return (!c.needsProject || pid) && (dev || !devOnly(c.id));
|
|
3699
3745
|
}).map(function(c) {
|
|
3700
3746
|
return { icon: c.icon, label: c.label, sub: c.keys || "", run: /* @__PURE__ */ __name(function() {
|
|
3701
3747
|
runCommand(c.id);
|
|
3702
3748
|
}, "run") };
|
|
3703
3749
|
});
|
|
3704
|
-
if (pid && state.showRail) {
|
|
3750
|
+
if (pid && state.showRail && dev) {
|
|
3705
3751
|
C.push({ icon: ICONS.files, label: "Explorer", sub: "panel", run: /* @__PURE__ */ __name(function() {
|
|
3706
3752
|
state.showRail("explorer");
|
|
3707
3753
|
}, "run") });
|
|
@@ -3714,10 +3760,10 @@
|
|
|
3714
3760
|
if (state.openSubagents) C.push({ icon: ICONS.agents, label: "Subagents", sub: "dock", run: /* @__PURE__ */ __name(function() {
|
|
3715
3761
|
state.openSubagents();
|
|
3716
3762
|
}, "run") });
|
|
3717
|
-
if (state.pid) C.push({ icon: ICONS.download, label: "Import chats from your agents", sub: "Claude, Codex, OpenCode", run: /* @__PURE__ */ __name(function() {
|
|
3718
|
-
openImportChats(state.pid);
|
|
3719
|
-
}, "run") });
|
|
3720
3763
|
}
|
|
3764
|
+
if (pid) C.push({ icon: ICONS.download, label: "Import chats from your agents", sub: "Claude, Codex, OpenCode", run: /* @__PURE__ */ __name(function() {
|
|
3765
|
+
openImportChats(pid);
|
|
3766
|
+
}, "run") });
|
|
3721
3767
|
C.push({ icon: ICONS.console, label: "Diagnostics", sub: "loom doctor", run: /* @__PURE__ */ __name(function() {
|
|
3722
3768
|
openSettingsModal("diagnostics");
|
|
3723
3769
|
}, "run") });
|
|
@@ -4973,7 +5019,7 @@
|
|
|
4973
5019
|
if (!n && view.brainKind !== k) return;
|
|
4974
5020
|
chips += '<button class="bkind bk-' + k + (view.brainKind === k ? " on" : "") + '" data-kind="' + k + '">' + k + ' <span class="kn">' + n + "</span></button>";
|
|
4975
5021
|
});
|
|
4976
|
-
var head = '<div class="bhead">' + brainSwitchHtml() + '<div class="bkinds">' + chips + '</div><div class="bio"><button type="button" class="btn xs ghost" id="bexport" title="download what this project knows, as JSON">' + ICONS.download + 'Export</button><button type="button" class="btn xs ghost" id="bimport" title="bring in a brain exported from Loom (duplicates are skipped)">' + ICONS.plus + 'Import</button><input type="file" id="bimportf" accept="application/json,.json" hidden></div></div><div class="bsort"><span>Sort</span><button type="button" data-bsort="new" class="' + (state.brainSort !== "used" ? "on" : "") + '">Newest</button><button type="button" data-bsort="used" class="' + (state.brainSort === "used" ? "on" : "") + '" title="how often each memory reached an agent\u2019s prompt">Most used</button><span
|
|
5022
|
+
var head = '<div class="bhead">' + brainSwitchHtml() + '<div class="bkinds">' + chips + '</div><div class="bio"><button type="button" class="btn xs ghost" id="bexport" title="download what this project knows, as JSON">' + ICONS.download + 'Export</button><button type="button" class="btn xs ghost" id="bimport" title="bring in a brain exported from Loom (duplicates are skipped)">' + ICONS.plus + 'Import</button><input type="file" id="bimportf" accept="application/json,.json" hidden></div></div><div class="bsort"><span>Sort</span><button type="button" data-bsort="new" class="' + (state.brainSort !== "used" ? "on" : "") + '">Newest</button><button type="button" data-bsort="used" class="' + (state.brainSort === "used" ? "on" : "") + '" title="how often each memory reached an agent\u2019s prompt">Most used</button><span class="bview devonly"><span>View</span><button type="button" data-bgv="list" class="' + (!state.brainGraph ? "on" : "") + '">List</button><button type="button" data-bgv="graph" class="' + (state.brainGraph ? "on" : "") + '" title="memories joined by the files and symbols they share">Graph</button></span></div>';
|
|
4977
5023
|
if (continuity.enabled) head += '<div class="bsec">Native continuity <button class="lnk" id="continuity-inspect">Inspect packets and delivery</button></div><div class="bsec">Legacy memories below are retained for compatibility and are not injected by native continuity.</div>';
|
|
4978
5024
|
var shown = view.brainKind ? memories.filter(function(x) {
|
|
4979
5025
|
return x.kind === view.brainKind;
|
|
@@ -4986,7 +5032,7 @@
|
|
|
4986
5032
|
var list;
|
|
4987
5033
|
if (!shown.length) {
|
|
4988
5034
|
list = '<div class="bempty">' + (memories.length ? "" : emptyArt("brain")) + (memories.length ? "No " + esc(view.brainKind) + " memories yet." : continuity.enabled ? "Your original user messages are protected automatically. Review packets and source-backed checkpoints through native continuity diagnostics." : "Nothing learned yet. As agents finish turns, Loom reads each one and records what's worth keeping \u2014 constraints, decisions, and the failures worth not repeating. Add a decision below to seed it, or let an agent take a turn.") + "</div>";
|
|
4989
|
-
} else if (state.brainGraph) {
|
|
5035
|
+
} else if (state.brainGraph && devMode()) {
|
|
4990
5036
|
list = '<div class="bgraph" id="bgraph"></div>';
|
|
4991
5037
|
} else {
|
|
4992
5038
|
list = '<div class="bmems">' + shown.map(function(x) {
|
|
@@ -5007,7 +5053,7 @@
|
|
|
5007
5053
|
}).join("") + "</div>" : '<div class="bempty sm">No native ADE memory found (CLAUDE.md, AGENTS.md, .kiro/steering). Loom reads these but never writes to them.</div>';
|
|
5008
5054
|
el.innerHTML = '<div class="pane-inner brain">' + head + seed + '<div id="bconflicts"></div>' + list + src + "</div>";
|
|
5009
5055
|
wireBrainSwitch(el);
|
|
5010
|
-
if (state.brainGraph && shown.length) view.drawMemGraph(document.getElementById("bgraph"), shown, usage);
|
|
5056
|
+
if (state.brainGraph && devMode() && shown.length) view.drawMemGraph(document.getElementById("bgraph"), shown, usage);
|
|
5011
5057
|
Array.prototype.forEach.call(el.querySelectorAll("[data-bgv]"), function(b) {
|
|
5012
5058
|
b.onclick = function() {
|
|
5013
5059
|
state.brainGraph = b.getAttribute("data-bgv") === "graph";
|
|
@@ -5913,7 +5959,7 @@
|
|
|
5913
5959
|
var lastSend = Promise.resolve();
|
|
5914
5960
|
var pendingSubmission;
|
|
5915
5961
|
function send() {
|
|
5916
|
-
if (state.cmode === "orch") return view.sendOrchestra();
|
|
5962
|
+
if (state.cmode === "orch" && devMode()) return view.sendOrchestra();
|
|
5917
5963
|
var box = document.getElementById("box");
|
|
5918
5964
|
var text = (box.value || "").trim();
|
|
5919
5965
|
if (!text && !view.attach.length) return;
|
|
@@ -7076,6 +7122,7 @@
|
|
|
7076
7122
|
}
|
|
7077
7123
|
} catch (e) {
|
|
7078
7124
|
}
|
|
7125
|
+
if (!devMode()) state.cmode = "chat";
|
|
7079
7126
|
view.setComposerMode(state.cmode || "chat");
|
|
7080
7127
|
refreshSkillCount();
|
|
7081
7128
|
var micB = document.getElementById("micbtn");
|
|
@@ -7242,7 +7289,7 @@
|
|
|
7242
7289
|
}
|
|
7243
7290
|
var mode = permOf(cur), cell = permProfile(cur.kind).modes[mode] || {};
|
|
7244
7291
|
pc.style.display = "";
|
|
7245
|
-
pc.className = "cperm " + mode;
|
|
7292
|
+
pc.className = "cperm devonly " + mode;
|
|
7246
7293
|
pc.setAttribute("data-mode", mode);
|
|
7247
7294
|
pc.title = "permissions \xB7 " + (cell.label || PERM_NAMES[mode]) + " \u2014 click to change";
|
|
7248
7295
|
pc.setAttribute("aria-label", "permissions: " + (PERM_NAMES[mode] || mode));
|
|
@@ -9104,7 +9151,7 @@
|
|
|
9104
9151
|
return a ? a.kind : null;
|
|
9105
9152
|
}, "kindIn");
|
|
9106
9153
|
var h = hue(String(info.id || info.name || "?"));
|
|
9107
|
-
var out = '<div class="fproj" data-fproj="' + esc(info.id) + '"><div class="fph"><span class="fpg" style="background:color-mix(in srgb, hsl(' + h + ",60%,50%) 18%, transparent);color:hsl(" + h + ',60%,var(--agent-l))">' + esc(String(info.name || info.id || "?").slice(0, 1)) + '</span><span class="fpn">' + esc(info.name || info.id) + "</span>" + (info.id === view.pid ? '<span class="fcur">this project</span>' : "") + '<span class="fpm">' + (busy ? busy + " working" : "idle") + (holder ? " \xB7 baton
|
|
9154
|
+
var out = '<div class="fproj" data-fproj="' + esc(info.id) + '"><div class="fph"><span class="fpg" style="background:color-mix(in srgb, hsl(' + h + ",60%,50%) 18%, transparent);color:hsl(" + h + ',60%,var(--agent-l))">' + esc(String(info.name || info.id || "?").slice(0, 1)) + '</span><span class="fpn">' + esc(info.name || info.id) + "</span>" + (info.id === view.pid ? '<span class="fcur">this project</span>' : "") + '<span class="fpm">' + (busy ? busy + " working" : "idle") + (holder ? '<span class="devonly"> \xB7 baton ' + esc(holder.id) + "</span>" : "") + '</span><span class="spacer"></span>' + (info.id !== view.pid ? '<button class="btn ghost xs" type="button" data-fopen="' + esc(info.id) + '">Open</button>' : "") + "</div>" + agents.map(function(a) {
|
|
9108
9155
|
return fleetAgentRow(info, a);
|
|
9109
9156
|
}).join("");
|
|
9110
9157
|
var o = pr.orchestra;
|
|
@@ -9135,7 +9182,7 @@
|
|
|
9135
9182
|
var lbl = agentLabel(a.kind, a.id), last = a.last;
|
|
9136
9183
|
var sub = [a.id !== lbl ? a.id : "", a.role || ""].filter(Boolean).join(" \xB7 ");
|
|
9137
9184
|
var chatName = a.chatTitle || (a.chat === "main" ? "Main thread" : a.chat);
|
|
9138
|
-
return '<div class="frow' + (a.busy ? " busy" : "") + '" data-fagent="' + esc(a.id) + '"><span class="fg">' + agentGlyph(a.kind, a.id) + '</span><span class="fn"><b>' + esc(lbl) + "</b>" + (sub ? "<small>" + esc(sub) + "</small>" : "") + '</span><span class="fs">' + (a.busy ? '<span class="fspin"></span>working' + (a.since ? " \xB7 " + fleetSince(a.since) : "") : '<span class="fidle"></span>idle') + '</span><span class="fa">' + (a.chat ? '<button class="fthr" type="button" data-fchat="' + esc(a.chat) + '" data-fpid="' + esc(info.id) + '" title="open this thread">' + ICONS.thread + "<span>" + esc(chatName) + "</span></button>" : "") + (last && last.line ? '<span class="fline">' + esc(last.line) + '<span class="ft">' + rel(last.ts) + "</span></span>" : a.chat ? "" : '<span class="fline">no activity yet</span>') + '</span><span class="fb">' + (a.holdsBaton ? '<span class="fbaton" title="holds the baton">baton</span>' : "") + permBadge(a.permissions || "auto", void 0, a.kind) + "</span></div>";
|
|
9185
|
+
return '<div class="frow' + (a.busy ? " busy" : "") + '" data-fagent="' + esc(a.id) + '"><span class="fg">' + agentGlyph(a.kind, a.id) + '</span><span class="fn"><b>' + esc(lbl) + "</b>" + (sub ? "<small>" + esc(sub) + "</small>" : "") + '</span><span class="fs">' + (a.busy ? '<span class="fspin"></span>working' + (a.since ? " \xB7 " + fleetSince(a.since) : "") : '<span class="fidle"></span>idle') + '</span><span class="fa">' + (a.chat ? '<button class="fthr" type="button" data-fchat="' + esc(a.chat) + '" data-fpid="' + esc(info.id) + '" title="open this thread">' + ICONS.thread + "<span>" + esc(chatName) + "</span></button>" : "") + (last && last.line ? '<span class="fline">' + esc(last.line) + '<span class="ft">' + rel(last.ts) + "</span></span>" : a.chat ? "" : '<span class="fline">no activity yet</span>') + '</span><span class="fb devonly">' + (a.holdsBaton ? '<span class="fbaton" title="holds the baton">baton</span>' : "") + permBadge(a.permissions || "auto", void 0, a.kind) + "</span></div>";
|
|
9139
9186
|
}
|
|
9140
9187
|
__name(fleetAgentRow, "fleetAgentRow");
|
|
9141
9188
|
function openFleetThread(toPid, chat) {
|
|
@@ -14842,26 +14889,26 @@
|
|
|
14842
14889
|
}));
|
|
14843
14890
|
var share = p && p.costUsd > 0 && total > 0 ? Math.min(100, Math.round(p.costUsd / total * 100)) : 0;
|
|
14844
14891
|
var gh = state.github, ghSeg = "";
|
|
14845
|
-
if (gh && gh.connected) ghSeg = '<span class="sit ghok" title="GitHub connected as ' + esc(gh.user || "") + '">' + ICONS.github + " " + esc(gh.user || "connected") + "</span>";
|
|
14846
|
-
else if (gh && gh.installed) ghSeg = '<button class="sit ghconnect" id="ghconnect" title="sign in to GitHub in a terminal">' + ICONS.github + " Connect GitHub</button>";
|
|
14892
|
+
if (gh && gh.connected) ghSeg = '<span class="sit ghok devonly" title="GitHub connected as ' + esc(gh.user || "") + '">' + ICONS.github + " " + esc(gh.user || "connected") + "</span>";
|
|
14893
|
+
else if (gh && gh.installed) ghSeg = '<button class="sit ghconnect devonly" id="ghconnect" title="sign in to GitHub in a terminal">' + ICONS.github + " Connect GitHub</button>";
|
|
14847
14894
|
var lp = state.loompad, lpUp = !!(lp && lp.up);
|
|
14848
|
-
var lpSeg = '<button class="sit lppill' + (lpUp ? " on" : "") + '" id="lppill" title="' + (lpUp ? "LoomPad voice backend connected" + (lp && lp.brain ? " \xB7 brain " + esc(String(lp.brain)) : "") + " \u2014 the pad can speak" : "LoomPad voice backend offline \u2014 start it so the pad can speak") + '"><span class="sdot' + (lpUp ? "" : " off") + '"></span>LoomPad' + (lpUp ? "" : " offline") + "</button>";
|
|
14895
|
+
var lpSeg = '<button class="sit lppill devonly' + (lpUp ? " on" : "") + '" id="lppill" title="' + (lpUp ? "LoomPad voice backend connected" + (lp && lp.brain ? " \xB7 brain " + esc(String(lp.brain)) : "") + " \u2014 the pad can speak" : "LoomPad voice backend offline \u2014 start it so the pad can speak") + '"><span class="sdot' + (lpUp ? "" : " off") + '"></span>LoomPad' + (lpUp ? "" : " offline") + "</button>";
|
|
14849
14896
|
var gd = state.gitDel, gdSeg = "";
|
|
14850
14897
|
if (p && gd && gd.pid === p.id) {
|
|
14851
14898
|
var gi = gitDeliveryInfo(gd.mode);
|
|
14852
|
-
gdSeg = '<button class="sit gitdel ' + esc(gi.mode) + '" id="gitdel" type="button" aria-haspopup="menu" title="git delivery for ' + esc(p.name || p.id) + ": " + esc(gi.name) + ' \u2014 click to change">' + gi.icon + esc(gi.short) + "</button>";
|
|
14899
|
+
gdSeg = '<button class="sit gitdel devonly ' + esc(gi.mode) + '" id="gitdel" type="button" aria-haspopup="menu" title="git delivery for ' + esc(p.name || p.id) + ": " + esc(gi.name) + ' \u2014 click to change">' + gi.icon + esc(gi.short) + "</button>";
|
|
14853
14900
|
}
|
|
14854
14901
|
el.innerHTML = // a project's live socket when one is open; otherwise whether the daemon itself answers
|
|
14855
14902
|
(function() {
|
|
14856
14903
|
var up = p ? state.wsLive : state.daemonUp !== false;
|
|
14857
14904
|
return '<span class="sit"><span class="sdot' + (up ? "" : " off") + '"></span>' + (up ? "live" : "offline") + "</span>";
|
|
14858
|
-
})() + '<span class="sit">' + esc(location.host) + "</span>" + (p ? '<span class="sit">baton ' + esc(p.holder || "\u2014") + "</span>" : "") + (p && p.costUsd > 0 ? (function() {
|
|
14905
|
+
})() + '<span class="sit devonly">' + esc(location.host) + "</span>" + (p ? '<span class="sit devonly">baton ' + esc(p.holder || "\u2014") + "</span>" : "") + (p && p.costUsd > 0 ? (function() {
|
|
14859
14906
|
var b = budgetFor(p.id);
|
|
14860
14907
|
var cls = b ? p.costUsd >= b ? " over" : p.costUsd >= b * 0.8 ? " warn" : "" : "";
|
|
14861
14908
|
var w = b ? Math.min(100, Math.round(p.costUsd / b * 100)) : share;
|
|
14862
14909
|
var label = b ? money(p.costUsd) + " / $" + b.toFixed(2) : money(p.costUsd) + " \xB7 " + share + "% of \u03A3";
|
|
14863
14910
|
var tip = b ? "spend vs budget \u2014 click to adjust" : "usage breakdown \u2014 click to set a budget";
|
|
14864
|
-
return '<button class="sit usagepill' + cls + '" id="usagepill" title="' + tip + '"><span class="meter"><i style="width:' + w + '%"></i></span>' + label + "</button>";
|
|
14911
|
+
return '<button class="sit usagepill devonly' + cls + '" id="usagepill" title="' + tip + '"><span class="meter"><i style="width:' + w + '%"></i></span>' + label + "</button>";
|
|
14865
14912
|
})() : "") + '<span class="spacer"></span>' + // A newer Loom is worth one quiet pill, not a banner: it opens the
|
|
14866
14913
|
// Updates section, where the button says exactly what it will run.
|
|
14867
14914
|
(state.update && state.update.behindRelease ? '<button class="sit updready" id="updready" title="Loom ' + esc(state.update.latest) + ' is out \u2014 open Updates">' + ICONS.up + " " + esc(state.update.latest) + "</button>" : "") + lpSeg + branchSeg() + gdSeg + ghSeg + (busy ? '<span class="sit" style="color:var(--live)">' + busy + " working</span>" : "") + '<span class="sit">' + (state.projects || []).length + " project" + ((state.projects || []).length === 1 ? "" : "s") + "</span>" + (total > 0 ? '<span class="sit">\u03A3 ' + money(total) + "</span>" : "");
|
|
@@ -16710,11 +16757,11 @@
|
|
|
16710
16757
|
// business one pixel from Interrupt) and Interrupt went into the
|
|
16711
16758
|
// composer. What's left beside the panel toggle is the panel toggle:
|
|
16712
16759
|
// this strip is about the window, not about the turn.
|
|
16713
|
-
desktop ? "" : '<button id="brainbtn" class="iconbtn" title="unified memory">' + ICONS.memory + '</button><button id="treebtn" class="iconbtn" title="working tree">' + ICONS.tree + '</button><button id="routebtn" class="iconbtn" title="routes">' + ICONS.route + '</button><button id="orchbtn" class="iconbtn" title="orchestra">' + ICONS.orchestra + '</button><button id="crewbtn" class="iconbtn" title="crew \xB7 agents with roles on one goal">' + ICONS.team + '</button><button id="fleetbtn" class="iconbtn" title="fleet \xB7 what every agent is doing">' + ICONS.fleet + '</button><button class="apbadge" id="apbadge" type="button" style="display:none"></button>'
|
|
16760
|
+
desktop ? "" : '<button id="brainbtn" class="iconbtn" title="unified memory">' + ICONS.memory + '</button><button id="treebtn" class="iconbtn devonly" title="working tree">' + ICONS.tree + '</button><button id="routebtn" class="iconbtn devonly" title="routes">' + ICONS.route + '</button><button id="orchbtn" class="iconbtn devonly" title="orchestra">' + ICONS.orchestra + '</button><button id="crewbtn" class="iconbtn devonly" title="crew \xB7 agents with roles on one goal">' + ICONS.team + '</button><button id="fleetbtn" class="iconbtn" title="fleet \xB7 what every agent is doing">' + ICONS.fleet + '</button><button class="apbadge" id="apbadge" type="button" style="display:none"></button>'
|
|
16714
16761
|
);
|
|
16715
|
-
var composerHtml = '<div class="composer" id="composerwrap"><form class="cbox" id="cform"><div class="cmenu" id="cmenu" style="display:none"></div><div class="cchips" id="cchips" style="display:none"></div><div class="cqueue" id="cqueue" style="display:none"></div><textarea id="box" class="cinput" rows="2" aria-label="message" placeholder="Message… @ for files, / for actions" autocomplete="off"></textarea><div class="cskillsug" id="cskillsug" style="display:none"></div><div class="cpanel" id="cpanel" style="display:none"></div><div class="corch" id="corch" style="display:none"></div><div class="crow"><div class="cmode" id="cmode" role="tablist" aria-label="composer mode"><button type="button" role="tab" data-cmode="chat" title="talk to one agent">' + ICONS.chat + 'Chat</button><button type="button" role="tab" data-cmode="orch" title="one agent plans, many work in parallel">' + ICONS.orchestra + 'Orchestrate</button></div><button class="ctool iconly" id="attach" type="button" title="attach an image or file" aria-label="attach a file">' + ICONS.plus + '</button><span class="cpick" id="cpick"><button class="cagent" id="cagent" type="button" title="who runs this turn \u2014 AUTO routes it, or pick an agent" aria-label="who runs this turn"><span class="cadot" id="cadot"></span><span class="can">agent</span><span class="cchev">' + ICONS.chevron + '</span></button><button class="ctool" id="modelpick" type="button" title="pick a model" aria-label="pick a model"><span class="cmodel" id="cmodellabel">model</span><span class="cchev">' + ICONS.updown + '</span></button></span><button class="cperm" id="cperm" type="button" aria-haspopup="menu" style="display:none"></button><span class="cctx" id="cctx" style="display:none"></span><button class="cslot" id="morebtn" type="button" aria-haspopup="menu" aria-expanded="false" title="MCPs, skills and more"><span class="cslotico">' + ICONS.dots + '</span><span class="cslotlbl">More</span><span class="skcount" id="skcount" style="display:none">0</span></button><button class="cslot" id="micbtn" type="button" aria-label="hold to talk" title="hold to talk \u2014 transcribed by LOOM_STT_CMD on the daemon, or by this browser when that isn\u2019t set"><span class="cslotico">' + ICONS.mic + '</span></button><button class="cprompt" id="promptbtn" type="button" aria-haspopup="dialog" title="prompts \u2014 saved and recent (' + KMOD + '\u21E7V)">' + ICONS.clipboard + '<span class="cslotlbl">Prompts</span><kbd>' + KMOD + '\u21E7V</kbd></button><span style="flex:1"></span><span class="ctok" id="ctok" aria-live="off"></span><span class="ckhint" aria-hidden="true"><kbd>\u23CE</kbd> send \xB7 <kbd>\u21E7\u23CE</kbd> new line</span><span class="csend"><button class="cplan" id="planbtn" type="button" role="switch" aria-checked="false" title="plan mode \u2014 write a plan, change no code"><span class="ptrack"><i></i></span><span class="cplanlbl">Plan</span></button><button class="sendbtn" id="send" type="submit" title="send" aria-label="send">' + ICONS.up + '</button><button class="sendbtn orchsend" id="orchsend" type="button" title="plan this goal and run it in parallel" style="display:none">' + ICONS.orchestra + 'Orchestrate</button><button class="sendbtn stopbtn" id="stop" type="button" title="interrupt" aria-label="interrupt" style="display:none">' + ICONS.stop + '</button></span></div><input type="file" id="cfile" multiple style="display:none"></form><div class="hint" id="hint"></div></div>';
|
|
16762
|
+
var composerHtml = '<div class="composer" id="composerwrap"><form class="cbox" id="cform"><div class="cmenu" id="cmenu" style="display:none"></div><div class="cchips" id="cchips" style="display:none"></div><div class="cqueue" id="cqueue" style="display:none"></div><textarea id="box" class="cinput" rows="2" aria-label="message" placeholder="Message… @ for files, / for actions" autocomplete="off"></textarea><div class="cskillsug" id="cskillsug" style="display:none"></div><div class="cpanel" id="cpanel" style="display:none"></div><div class="corch" id="corch" style="display:none"></div><div class="crow"><div class="cmode devonly" id="cmode" role="tablist" aria-label="composer mode"><button type="button" role="tab" data-cmode="chat" title="talk to one agent">' + ICONS.chat + 'Chat</button><button type="button" role="tab" data-cmode="orch" title="one agent plans, many work in parallel">' + ICONS.orchestra + 'Orchestrate</button></div><button class="ctool iconly" id="attach" type="button" title="attach an image or file" aria-label="attach a file">' + ICONS.plus + '</button><span class="cpick" id="cpick"><button class="cagent" id="cagent" type="button" title="who runs this turn \u2014 AUTO routes it, or pick an agent" aria-label="who runs this turn"><span class="cadot" id="cadot"></span><span class="can">agent</span><span class="cchev">' + ICONS.chevron + '</span></button><button class="ctool devonly" id="modelpick" type="button" title="pick a model" aria-label="pick a model"><span class="cmodel" id="cmodellabel">model</span><span class="cchev">' + ICONS.updown + '</span></button></span><button class="cperm devonly" id="cperm" type="button" aria-haspopup="menu" style="display:none"></button><span class="cctx devonly" id="cctx" style="display:none"></span><button class="cslot devonly" id="morebtn" type="button" aria-haspopup="menu" aria-expanded="false" title="MCPs, skills and more"><span class="cslotico">' + ICONS.dots + '</span><span class="cslotlbl">More</span><span class="skcount" id="skcount" style="display:none">0</span></button><button class="cslot" id="micbtn" type="button" aria-label="hold to talk" title="hold to talk \u2014 transcribed by LOOM_STT_CMD on the daemon, or by this browser when that isn\u2019t set"><span class="cslotico">' + ICONS.mic + '</span></button><button class="cprompt devonly" id="promptbtn" type="button" aria-haspopup="dialog" title="prompts \u2014 saved and recent (' + KMOD + '\u21E7V)">' + ICONS.clipboard + '<span class="cslotlbl">Prompts</span><kbd>' + KMOD + '\u21E7V</kbd></button><span style="flex:1"></span><span class="ctok" id="ctok" aria-live="off"></span><span class="ckhint" aria-hidden="true"><kbd>\u23CE</kbd> send \xB7 <kbd>\u21E7\u23CE</kbd> new line</span><span class="csend"><button class="cplan" id="planbtn" type="button" role="switch" aria-checked="false" title="plan mode \u2014 write a plan, change no code"><span class="ptrack"><i></i></span><span class="cplanlbl">Plan</span></button><button class="sendbtn" id="send" type="submit" title="send" aria-label="send">' + ICONS.up + '</button><button class="sendbtn orchsend" id="orchsend" type="button" title="plan this goal and run it in parallel" style="display:none">' + ICONS.orchestra + 'Orchestrate</button><button class="sendbtn stopbtn" id="stop" type="button" title="interrupt" aria-label="interrupt" style="display:none">' + ICONS.stop + '</button></span></div><input type="file" id="cfile" multiple style="display:none"></form><div class="hint" id="hint"></div></div>';
|
|
16716
16763
|
if (desktop) {
|
|
16717
|
-
mount.innerHTML = '<div class="panel"><div class="tabstrip" id="tabstrip"><button id="sbbtn" class="iconbtn sbbtn" type="button" title="projects and threads" aria-label="show projects and threads">' + ICONS.panelRight + '</button><span id="tabsbox" style="display:contents"></span><span class="spacer"></span><button class="apbadge" id="apbadge" type="button" style="display:none"></button><button id="invitebtn" class="btn outline sm invitebtn" type="button" title="invite a teammate \u2014 one link sets up the team, this repo and their agents">' + ICONS.team + '<span>Invite</span></button><button id="termbtn" class="iconbtn" title="toggle terminal (\u2303`)">' + ICONS.terminal + '</button><button id="phonebtn" class="iconbtn" title="connect a phone" aria-label="connect a phone">' + ICONS.phone + '</button><button id="consolebtn" class="iconbtn" title="console \xB7 errors and logs">' + ICONS.console + '<span class="errdot" id="errdot"></span></button><button id="browserbtn" class="iconbtn" title="browser \xB7 live page and Playwright specs">' + ICONS.globe + '</button><button id="subagentsbtn" class="iconbtn" title="subagents \xB7 every agent an orchestrator or crew put to work">' + ICONS.agents + '</button><button id="railbtn" class="iconbtn" title="toggle right panel">' + ICONS.panelRight + "</button>" + headerActions + '</div><div class="paneswrap"><div class="mainpane" id="mainpane"><div class="pane scroll" id="pane-thread"><div id="agenthead" class="agenthead" style="display:none"></div><div id="routebar"></div><div id="feed">' + LOADER + '</div><div id="feedlive" aria-live="polite"></div><button type="button" class="jumpnew" id="jumpnew">' + ICONS.arrowDown + 'Latest</button></div><div class="pane scroll" id="pane-brain" style="display:none">' + LOADER + '</div><div class="pane scroll" id="pane-observatory" style="display:none">' + LOADER + '</div><div class="pane scroll" id="pane-board" style="display:none"></div><div class="pane scroll" id="pane-orchestra" style="display:none"></div><div class="pane scroll" id="pane-crew" style="display:none"></div><div class="pane scroll" id="pane-fleet" style="display:none"></div><div class="pane scroll" id="pane-team" style="display:none"><div class="teampane" id="fteam"></div></div>' + composerHtml + '</div><div class="dockpane" id="dockpane"><div class="rz rz-dock" id="rz-dock" title="drag to resize"></div><div class="dockhead" id="dockhead"><div class="docktabs" id="docktabs" role="tablist"></div><button id="dockclose" class="iconbtn" title="close every tab">' + ICONS.x + '</button></div><div class="pane scroll" id="pane-changes">' + LOADER + '</div></div></div><div class="termdock" id="termdock"><div class="termresize" id="termresize"></div><div class="termtabs"><span id="termtabs" style="display:contents"></span><button id="termadd" class="iconbtn" title="new terminal">' + ICONS.plus + '</button><span class="spacer"></span><span class="termfind" id="termfind" hidden><input id="termq" placeholder="Find in terminal" spellcheck="false" autocomplete="off" aria-label="find in terminal"><span id="termqn" class="termqn"></span></span><button id="termsearch" class="iconbtn" title="Find in this terminal">' + ICONS.search + '</button><button id="termclear" class="iconbtn" title="Clear this terminal">' + ICONS.trash + '</button><button id="termhide" class="iconbtn" title="hide terminal">' + ICONS.x + '</button></div><div class="termpanes" id="termpanes"><div class="conwrap" id="conwrap"><div class="conbar"><span class="lvl on" data-lvl="all">all</span><span class="lvl" data-lvl="error">errors</span><span class="lvl" data-lvl="warn">warnings</span><select id="conscope" class="consel" title="filter by scope"><option value="">all scopes</option></select><input id="consearch" class="consearch" placeholder="search\u2026" autocomplete="off" spellcheck="false"><span class="spacer" style="flex:1"></span><span id="concount"></span><button id="conclear" class="iconbtn" title="clear">' + ICONS.x + '</button></div><div class="conlist" id="conlist"></div></div><div class="browwrap" id="browwrap"><div class="browrail" id="browrail"><div class="browbar"><span class="lbl">Dev servers</span><span class="spacer" style="flex:1"></span><button id="srvreload" class="iconbtn xs" title="refresh">' + ICONS.refresh + '</button><button id="browrailclose" class="iconbtn xs browrailclose" title="hide">' + ICONS.x + '</button></div><div class="srvlist" id="srvlist">' + LOADER + '</div><div class="browbar"><span class="lbl">Playwright specs</span><span class="spacer" style="flex:1"></span><button id="specstop" class="iconbtn xs" title="stop the running spec" style="display:none">' + ICONS.stop + '</button><button id="specreload" class="iconbtn xs" title="rescan">' + ICONS.refresh + '</button></div><div class="speclist" id="speclist">' + LOADER + '</div><div class="specout" id="specout" style="display:none"></div></div><div class="browmain"><div class="browurl"><button id="browrailbtn" class="iconbtn browrailbtn" title="servers and specs">' + ICONS.tasks + '</button><button id="browback" class="iconbtn" title="back">' + ICONS.back + '</button><button id="browfwd" class="iconbtn" title="forward">' + ICONS.arrowRight + '</button><button id="browreload" class="iconbtn" title="reload">' + ICONS.refresh + '</button><input id="browurl" placeholder="http://localhost:3000 \u2014 preview a dev server" autocomplete="off" spellcheck="false"><button id="browgo" class="iconbtn" title="open">' + ICONS.play + '</button><button id="browmore" class="iconbtn browmore" title="more">' + ICONS.dots + '</button><span class="browtools" id="browtools"><span class="browsizes" id="browsizes"><button data-w="0" class="on" title="fit the pane">Fit</button><button data-w="375" title="phone width">375</button><button data-w="768" title="tablet width">768</button><button data-w="1280" title="desktop width">1280</button></span><span class="browsizes" id="browscheme"><button data-s="" class="on" title="whatever your OS is set to">Auto</button><button data-s="light" title="preview the page in light mode">\u2600</button><button data-s="dark" title="preview the page in dark mode">\u263D</button></span><button id="browshot" class="iconbtn" title="screenshot into the composer">' + ICONS.camera + '</button><button id="browext" class="iconbtn" title="open in your browser">' + ICONS.external + '</button><label class="browauto" title="reload when an agent changes a file this server serves"><input type="checkbox" id="browautorel" checked><span>auto</span></label></span></div><div class="browframe" id="browframe"><div class="browhint">Point this at a running dev server to see the page beside its tests.<br>Sites that forbid embedding (X-Frame-Options) won\u2019t render here \u2014 local ones do.</div></div><div class="srvlog" id="srvlog" style="display:none"><div class="srvlogbar"><span class="lbl" id="srvlogname"></span><span class="spacer" style="flex:1"></span><button id="srvlogclose" class="iconbtn xs" title="hide">' + ICONS.x + '</button></div><div class="srvloglines" id="srvloglines"></div></div><div class="pglog" id="pglog" style="display:none"><div class="srvlogbar"><span class="lbl">Page</span><span class="pgtabs" id="pgtabs"><button data-pg="console" class="on">Console</button><button data-pg="network">Network</button></span><span class="spacer" style="flex:1"></span><span class="pgcount" id="pgcount"></span><button id="pgpick" class="iconbtn xs" title="pick an element on the page">' + ICONS.target + '</button><button id="pgclear" class="iconbtn xs" title="clear">' + ICONS.x + '</button></div><div class="srvloglines" id="pglines"></div></div></div></div></div><form class="terminput" id="termform" style="display:none"><span class="pr">❯</span><input id="terminput" placeholder="run a command\u2026" autocomplete="off" autocapitalize="off" spellcheck="false"><span class="st"></span></form></div></div>';
|
|
16764
|
+
mount.innerHTML = '<div class="panel"><div class="tabstrip" id="tabstrip"><button id="sbbtn" class="iconbtn sbbtn" type="button" title="projects and threads" aria-label="show projects and threads">' + ICONS.panelRight + '</button><span id="tabsbox" style="display:contents"></span><span class="spacer"></span><button class="apbadge" id="apbadge" type="button" style="display:none"></button><button id="invitebtn" class="btn outline sm invitebtn" type="button" title="invite a teammate \u2014 one link sets up the team, this repo and their agents">' + ICONS.team + '<span>Invite</span></button><button id="termbtn" class="iconbtn devonly" title="toggle terminal (\u2303`)">' + ICONS.terminal + '</button><button id="phonebtn" class="iconbtn" title="connect a phone" aria-label="connect a phone">' + ICONS.phone + '</button><button id="consolebtn" class="iconbtn devonly" title="console \xB7 errors and logs">' + ICONS.console + '<span class="errdot" id="errdot"></span></button><button id="browserbtn" class="iconbtn devonly" title="browser \xB7 live page and Playwright specs">' + ICONS.globe + '</button><button id="subagentsbtn" class="iconbtn devonly" title="subagents \xB7 every agent an orchestrator or crew put to work">' + ICONS.agents + '</button><button id="railbtn" class="iconbtn devonly" title="toggle right panel">' + ICONS.panelRight + "</button>" + headerActions + '</div><div class="paneswrap"><div class="mainpane" id="mainpane"><div class="pane scroll" id="pane-thread"><div id="agenthead" class="agenthead" style="display:none"></div><div id="routebar"></div><div id="feed">' + LOADER + '</div><div id="feedlive" aria-live="polite"></div><button type="button" class="jumpnew" id="jumpnew">' + ICONS.arrowDown + 'Latest</button></div><div class="pane scroll" id="pane-brain" style="display:none">' + LOADER + '</div><div class="pane scroll" id="pane-observatory" style="display:none">' + LOADER + '</div><div class="pane scroll" id="pane-board" style="display:none"></div><div class="pane scroll" id="pane-orchestra" style="display:none"></div><div class="pane scroll" id="pane-crew" style="display:none"></div><div class="pane scroll" id="pane-fleet" style="display:none"></div><div class="pane scroll" id="pane-team" style="display:none"><div class="teampane" id="fteam"></div></div>' + composerHtml + '</div><div class="dockpane" id="dockpane"><div class="rz rz-dock" id="rz-dock" title="drag to resize"></div><div class="dockhead" id="dockhead"><div class="docktabs" id="docktabs" role="tablist"></div><button id="dockclose" class="iconbtn" title="close every tab">' + ICONS.x + '</button></div><div class="pane scroll" id="pane-changes">' + LOADER + '</div></div></div><div class="termdock" id="termdock"><div class="termresize" id="termresize"></div><div class="termtabs"><span id="termtabs" style="display:contents"></span><button id="termadd" class="iconbtn" title="new terminal">' + ICONS.plus + '</button><span class="spacer"></span><span class="termfind" id="termfind" hidden><input id="termq" placeholder="Find in terminal" spellcheck="false" autocomplete="off" aria-label="find in terminal"><span id="termqn" class="termqn"></span></span><button id="termsearch" class="iconbtn" title="Find in this terminal">' + ICONS.search + '</button><button id="termclear" class="iconbtn" title="Clear this terminal">' + ICONS.trash + '</button><button id="termhide" class="iconbtn" title="hide terminal">' + ICONS.x + '</button></div><div class="termpanes" id="termpanes"><div class="conwrap" id="conwrap"><div class="conbar"><span class="lvl on" data-lvl="all">all</span><span class="lvl" data-lvl="error">errors</span><span class="lvl" data-lvl="warn">warnings</span><select id="conscope" class="consel" title="filter by scope"><option value="">all scopes</option></select><input id="consearch" class="consearch" placeholder="search\u2026" autocomplete="off" spellcheck="false"><span class="spacer" style="flex:1"></span><span id="concount"></span><button id="conclear" class="iconbtn" title="clear">' + ICONS.x + '</button></div><div class="conlist" id="conlist"></div></div><div class="browwrap" id="browwrap"><div class="browrail" id="browrail"><div class="browbar"><span class="lbl">Dev servers</span><span class="spacer" style="flex:1"></span><button id="srvreload" class="iconbtn xs" title="refresh">' + ICONS.refresh + '</button><button id="browrailclose" class="iconbtn xs browrailclose" title="hide">' + ICONS.x + '</button></div><div class="srvlist" id="srvlist">' + LOADER + '</div><div class="browbar"><span class="lbl">Playwright specs</span><span class="spacer" style="flex:1"></span><button id="specstop" class="iconbtn xs" title="stop the running spec" style="display:none">' + ICONS.stop + '</button><button id="specreload" class="iconbtn xs" title="rescan">' + ICONS.refresh + '</button></div><div class="speclist" id="speclist">' + LOADER + '</div><div class="specout" id="specout" style="display:none"></div></div><div class="browmain"><div class="browurl"><button id="browrailbtn" class="iconbtn browrailbtn" title="servers and specs">' + ICONS.tasks + '</button><button id="browback" class="iconbtn" title="back">' + ICONS.back + '</button><button id="browfwd" class="iconbtn" title="forward">' + ICONS.arrowRight + '</button><button id="browreload" class="iconbtn" title="reload">' + ICONS.refresh + '</button><input id="browurl" placeholder="http://localhost:3000 \u2014 preview a dev server" autocomplete="off" spellcheck="false"><button id="browgo" class="iconbtn" title="open">' + ICONS.play + '</button><button id="browmore" class="iconbtn browmore" title="more">' + ICONS.dots + '</button><span class="browtools" id="browtools"><span class="browsizes" id="browsizes"><button data-w="0" class="on" title="fit the pane">Fit</button><button data-w="375" title="phone width">375</button><button data-w="768" title="tablet width">768</button><button data-w="1280" title="desktop width">1280</button></span><span class="browsizes" id="browscheme"><button data-s="" class="on" title="whatever your OS is set to">Auto</button><button data-s="light" title="preview the page in light mode">\u2600</button><button data-s="dark" title="preview the page in dark mode">\u263D</button></span><button id="browshot" class="iconbtn" title="screenshot into the composer">' + ICONS.camera + '</button><button id="browext" class="iconbtn" title="open in your browser">' + ICONS.external + '</button><label class="browauto" title="reload when an agent changes a file this server serves"><input type="checkbox" id="browautorel" checked><span>auto</span></label></span></div><div class="browframe" id="browframe"><div class="browhint">Point this at a running dev server to see the page beside its tests.<br>Sites that forbid embedding (X-Frame-Options) won\u2019t render here \u2014 local ones do.</div></div><div class="srvlog" id="srvlog" style="display:none"><div class="srvlogbar"><span class="lbl" id="srvlogname"></span><span class="spacer" style="flex:1"></span><button id="srvlogclose" class="iconbtn xs" title="hide">' + ICONS.x + '</button></div><div class="srvloglines" id="srvloglines"></div></div><div class="pglog" id="pglog" style="display:none"><div class="srvlogbar"><span class="lbl">Page</span><span class="pgtabs" id="pgtabs"><button data-pg="console" class="on">Console</button><button data-pg="network">Network</button></span><span class="spacer" style="flex:1"></span><span class="pgcount" id="pgcount"></span><button id="pgpick" class="iconbtn xs" title="pick an element on the page">' + ICONS.target + '</button><button id="pgclear" class="iconbtn xs" title="clear">' + ICONS.x + '</button></div><div class="srvloglines" id="pglines"></div></div></div></div></div><form class="terminput" id="termform" style="display:none"><span class="pr">❯</span><input id="terminput" placeholder="run a command\u2026" autocomplete="off" autocapitalize="off" spellcheck="false"><span class="st"></span></form></div></div>';
|
|
16718
16765
|
} else {
|
|
16719
16766
|
mount.innerHTML = '<div class="panel"><header><button id="back" class="iconbtn" title="back">' + ICONS.back + '</button><div class="ptitle"><span class="nm" id="pname">…</span><span class="st" id="pstat"></span></div><span class="spacer"></span>' + headerActions + '</header><div class="chips" id="chips"></div><div class="scroll" id="pane-thread"><div id="routesheet"></div><div id="routebar"></div><div id="feed">' + LOADER + '</div><div id="feedlive" aria-live="polite"></div><button type="button" class="jumpnew" id="jumpnew">' + ICONS.arrowDown + "Latest</button></div>" + composerHtml + "</div>";
|
|
16720
16767
|
}
|
|
@@ -16742,6 +16789,9 @@
|
|
|
16742
16789
|
tabs.splice(2, 0, "orchestra");
|
|
16743
16790
|
tabs.splice(3, 0, "crew");
|
|
16744
16791
|
tabs.splice(4, 0, "fleet");
|
|
16792
|
+
if (!devMode()) tabs = SIMPLE_TABS.filter(function(t) {
|
|
16793
|
+
return tabs.indexOf(t) >= 0;
|
|
16794
|
+
});
|
|
16745
16795
|
if (tabs.indexOf(state.tab) < 0) state.tab = "thread";
|
|
16746
16796
|
var LBL = {
|
|
16747
16797
|
thread: [ICONS.thread, "Chat", "talk to an agent in this thread"],
|
|
@@ -16764,13 +16814,27 @@
|
|
|
16764
16814
|
}
|
|
16765
16815
|
__name(drawTabs, "drawTabs");
|
|
16766
16816
|
function showTab(name) {
|
|
16817
|
+
if (!devMode() && SIMPLE_TABS.indexOf(name) < 0) {
|
|
16818
|
+
toast("That\u2019s in Developer mode \u2014 turn it on in Settings \u2192 Preferences");
|
|
16819
|
+
return;
|
|
16820
|
+
}
|
|
16767
16821
|
var still = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
16768
16822
|
if (document.startViewTransition && state.tab && state.tab !== name && !still && !showTab.inTransition) {
|
|
16769
16823
|
showTab.inTransition = true;
|
|
16770
16824
|
try {
|
|
16825
|
+
var swapped = false;
|
|
16771
16826
|
var vt = document.startViewTransition(function() {
|
|
16827
|
+
if (swapped) return;
|
|
16828
|
+
swapped = true;
|
|
16772
16829
|
showTabNow(name);
|
|
16773
16830
|
});
|
|
16831
|
+
setTimeout(function() {
|
|
16832
|
+
if (!swapped) {
|
|
16833
|
+
swapped = true;
|
|
16834
|
+
showTab.inTransition = false;
|
|
16835
|
+
showTabNow(name);
|
|
16836
|
+
}
|
|
16837
|
+
}, 400);
|
|
16774
16838
|
var quiet = /* @__PURE__ */ __name(function() {
|
|
16775
16839
|
}, "quiet");
|
|
16776
16840
|
if (vt.ready) vt.ready.catch(quiet);
|
|
@@ -17929,7 +17993,7 @@
|
|
|
17929
17993
|
el.id = "recap";
|
|
17930
17994
|
el.className = "recap";
|
|
17931
17995
|
el.setAttribute("role", "status");
|
|
17932
|
-
el.innerHTML = '<span class="recapi">' + ICONS.clock + '</span><span class="recapt"><b>Since you were here</b> <span class="dim">' + esc(newDay ? relDay(last) : rel(last)) + "</span> \xB7 " + turns + " turn" + (turns === 1 ? "" : "s") + " (" + who + ")" + (errs ? ' \xB7 <span class="recaperr">' + errs + " failed</span>" : "") + (cost > 0 ? " \xB7 " + money(cost) : "") + '</span><button type="button" class="btn xs ghost" id="recapgo">Insights</button><button type="button" class="iconbtn xs" id="recapx" aria-label="dismiss" title="dismiss">' + ICONS.x + "</button>";
|
|
17996
|
+
el.innerHTML = '<span class="recapi">' + ICONS.clock + '</span><span class="recapt"><b>Since you were here</b> <span class="dim">' + esc(newDay ? relDay(last) : rel(last)) + "</span> \xB7 " + turns + " turn" + (turns === 1 ? "" : "s") + " (" + who + ")" + (errs ? ' \xB7 <span class="recaperr">' + errs + " failed</span>" : "") + (cost > 0 && devMode() ? " \xB7 " + money(cost) : "") + '</span><button type="button" class="btn xs ghost devonly" id="recapgo">Insights</button><button type="button" class="iconbtn xs" id="recapx" aria-label="dismiss" title="dismiss">' + ICONS.x + "</button>";
|
|
17933
17997
|
host.insertBefore(el, feed);
|
|
17934
17998
|
el.querySelector("#recapx").onclick = function() {
|
|
17935
17999
|
el.remove();
|
|
@@ -18967,7 +19031,9 @@
|
|
|
18967
19031
|
var gh = hue(p.id + p.name);
|
|
18968
19032
|
var rows = '<div class="srow' + (sel ? " sel" : "") + '" data-id="' + esc(p.id) + '"><div class="n"><button class="scaret' + (open ? " open" : "") + '" data-caret="' + esc(p.id) + '" aria-label="' + (open ? "collapse " : "expand ") + esc(p.name) + '" aria-expanded="' + (open ? "true" : "false") + '">' + ICONS.chevron + '</button><span class="pglyph' + (p.needsInput ? " hot" : "") + '" style="background:color-mix(in srgb, hsl(' + gh + ",60%,50%) 20%, transparent);color:hsl(" + gh + ',60%,var(--agent-l))">' + esc((p.name || "?").slice(0, 1).toUpperCase()) + '</span><span class="nm">' + esc(p.name) + "</span>" + // The gear takes the trailing slot, so the count needs its own
|
|
18969
19033
|
// margin-left:auto — .cnt's rule loses to the badge's inline style.
|
|
18970
|
-
(act ? '<span class="badge live" style="margin-left:auto">' + (r.current + 1) + "/" + r.steps.length + "</span>" : '<span class="cnt" style="margin-left:auto">' + adapters.length + "</span>") + '<button class="psetbtn" data-pset="' + esc(p.id) + '" title="project settings" aria-label="settings for ' + esc(p.name) + '">' + ICONS.gear + "</button></div>" + (p.error ? '<div class="m merr">' + ICONS.alert + (p.missing ? "folder missing" : "needs loom init") + "</div></div>" : '<div class="m">baton ' + esc(p.holder || "\u2014") + (p.costUsd > 0 ? " \xB7 " + money(p.costUsd) : "") + "</div></div>")
|
|
19034
|
+
(act ? '<span class="badge live" style="margin-left:auto">' + (r.current + 1) + "/" + r.steps.length + "</span>" : '<span class="cnt" style="margin-left:auto">' + adapters.length + "</span>") + '<button class="psetbtn" data-pset="' + esc(p.id) + '" title="project settings" aria-label="settings for ' + esc(p.name) + '">' + ICONS.gear + "</button></div>" + (p.error ? '<div class="m merr">' + ICONS.alert + (p.missing ? "folder missing" : "needs loom init") + "</div></div>" : devMode() ? '<div class="m">baton ' + esc(p.holder || "\u2014") + (p.costUsd > 0 ? " \xB7 " + money(p.costUsd) : "") + "</div></div>" : '<div class="m">' + ((p.agents || []).some(function(a) {
|
|
19035
|
+
return a.busy;
|
|
19036
|
+
}) || (p.activity || []).length ? '<span class="mwork">working</span>' : "idle") + "</div></div>");
|
|
18971
19037
|
if (open && !p.error) {
|
|
18972
19038
|
var chats = (p.chats || [{ id: "main", title: "Main", createdAt: 0 }]).slice();
|
|
18973
19039
|
var here = currentChat(), SHOW = 8;
|
|
@@ -20791,7 +20857,7 @@
|
|
|
20791
20857
|
}
|
|
20792
20858
|
__name(runnerAct, "runnerAct");
|
|
20793
20859
|
var JOB_ST = { queued: ["queued", "off"], claimed: ["running", "live"], done: ["done", "ok"], failed: ["failed", "err"], cancelled: ["cancelled", "off"] };
|
|
20794
|
-
var JOB_KIND = { start: "Start", "continue": "Continue", fix: "CI fix", "return": "Bring back", land: "Land" };
|
|
20860
|
+
var JOB_KIND = { start: "Start", "continue": "Continue", fix: "CI fix", "return": "Bring back", land: "Land", task: "Task" };
|
|
20795
20861
|
function jobProgressText(p) {
|
|
20796
20862
|
if (!p) return "";
|
|
20797
20863
|
var ts = p.tasks || [], done = ts.filter(function(t) {
|
|
@@ -20813,7 +20879,8 @@
|
|
|
20813
20879
|
return r.online;
|
|
20814
20880
|
}).length + "/" + rs.length + " online</span></div>";
|
|
20815
20881
|
h += rs.map(function(r) {
|
|
20816
|
-
return '<div class="trn" data-trunner="' + esc(r.deviceId) + '"><span class="tnt"><span class="odot ' + (r.online ? "ok" : "off") + '" title="' + (r.online ? "online" : "offline") + '"></span><b>' + esc(runnerName(r)) + "</b>" + (r.shared ? '<span class="tbdg">shared</span>' : "") +
|
|
20882
|
+
return '<div class="trn" data-trunner="' + esc(r.deviceId) + '"><span class="tnt"><span class="odot ' + (r.online ? "ok" : "off") + '" title="' + (r.online ? "online" : "offline") + '"></span><b>' + esc(runnerName(r)) + "</b>" + (r.shared ? '<span class="tbdg">shared</span>' : "") + // a teammate's shared runner is where your goals' team:<agent> tasks run
|
|
20883
|
+
(r.shared && !r.mine && r.online ? '<span class="tbdg" title="your goals can send tasks here: team:' + esc((r.kinds || []).join(", team:")) + '">takes your tasks</span>' : "") + "<small>" + (r.mine ? "yours" : esc(r.github || "a teammate") + "\u2019s") + " \xB7 " + (esc((r.kinds || []).join(", ")) || "no agents yet") + (r.capacity ? " \xB7 " + Number(r.capacity) + " at a time" : "") + (r.online ? "" : " \xB7 seen " + rel(r.lastSeen)) + "</small></span></div>";
|
|
20817
20884
|
}).join("");
|
|
20818
20885
|
if (jobs.length) h += '<div class="trsub">Jobs</div>' + jobs.map(function(j) {
|
|
20819
20886
|
var s = JOB_ST[j.state] || [j.state || "\u2014", "off"], on = byId[j.runnerId];
|
|
@@ -21384,7 +21451,7 @@
|
|
|
21384
21451
|
var who = /* @__PURE__ */ __name(function(id, c) {
|
|
21385
21452
|
return '<span class="' + c + '">' + (id ? agentGlyph(kindOf(id), id, "brand") : "") + esc(id ? labelOf(id) : "\u2014") + "</span>";
|
|
21386
21453
|
}, "who");
|
|
21387
|
-
return '<div class="handoff" title="the baton passed ' + esc(new Date(Number(e.ts) || Date.now()).toLocaleString()) + '"><span class="hochip"><span class="hok">baton</span>' + who(p.from, "a") + '<span class="shuttle">' + ICONS.arrowRight + "</span>" + who(p.to, "b") + "</span></div>";
|
|
21454
|
+
return '<div class="handoff' + (p.from ? "" : " devonly") + '" title="the baton passed ' + esc(new Date(Number(e.ts) || Date.now()).toLocaleString()) + '"><span class="hochip"><span class="hok devonly">baton</span>' + who(p.from, "a") + '<span class="shuttle">' + ICONS.arrowRight + "</span>" + who(p.to, "b") + "</span></div>";
|
|
21388
21455
|
}
|
|
21389
21456
|
if (e.kind === "subtask_started") return '<div class="sys" style="padding-left:22px">\u21B3 ' + esc(e.agentId) + " picks up a subtask for " + esc(p.parent) + ": " + esc(String(p.task || "").slice(0, 90)) + "</div>";
|
|
21390
21457
|
if (e.kind === "subtask_done") return '<div class="sys" style="padding-left:22px;color:var(--live)">\u21B3 ' + esc(e.agentId) + " finished its subtask</div>";
|
|
@@ -21666,7 +21733,7 @@
|
|
|
21666
21733
|
var r = p.rerun || null;
|
|
21667
21734
|
var meta = r ? esc(String(r.command || "")) + " \xB7 " + durfmt(Number(r.ms) || 0) + (r.clean === false ? " \xB7 in place" : " \xB7 clean checkout") : "";
|
|
21668
21735
|
var claims = (p.claims || []).map(function(c) {
|
|
21669
|
-
return '<li class="pf-' + esc(c.status || "unchecked") + '"><span class="pfq">\u201C' + esc(String(c.text || "").slice(0, 140)) + '\u201D</span><span class="pfw">' + esc(String(c.why || "")) + "</span></li>";
|
|
21736
|
+
return '<li class="pf-' + esc(c.status || "unchecked") + '"><span class="pfq">\u201C' + esc(String(c.text || "").replace(/\*\*|__|`/g, "").slice(0, 140)) + '\u201D</span><span class="pfw">' + esc(String(c.why || "")) + "</span></li>";
|
|
21670
21737
|
}).join("");
|
|
21671
21738
|
var counts = r && r.counts ? '<span class="pfn">' + Number(r.counts.passed || 0) + " passed" + (r.counts.failed ? " \xB7 " + Number(r.counts.failed) + " failed" : "") + "</span>" : "";
|
|
21672
21739
|
return '<div class="proofcard v-' + esc(p.verdict || "unverified") + '" data-agent="' + esc(p.about || "") + '"><div class="pfh"><span class="pfi">' + ICONS[v.icon] + "</span><b>" + v.label + '</b><span class="pfhl">' + esc(String(p.headline || "")) + "</span>" + counts + (p.auto ? '<span class="pfauto" title="checked automatically: the reply claimed it">auto</span>' : "") + "</div>" + (claims ? '<ul class="pfc">' + claims + "</ul>" : "") + (r ? '<details class="pfr"><summary>' + meta + (r.timedOut ? " \xB7 timed out" : "") + "</summary><pre>" + esc(String(r.tail || "")) + "</pre></details>" : "") + "</div>";
|
|
@@ -22318,7 +22385,9 @@
|
|
|
22318
22385
|
|
|
22319
22386
|
// src/web/navigation.js
|
|
22320
22387
|
function route() {
|
|
22388
|
+
state.rerender = route;
|
|
22321
22389
|
applyTheme();
|
|
22390
|
+
applyMode();
|
|
22322
22391
|
state.composer = null;
|
|
22323
22392
|
state.toggleTerm = null;
|
|
22324
22393
|
state.selectProject = null;
|