@paradow/ledge 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{action-HUKZUHQ7.js → action-K42H5BDA.js} +5 -5
- package/dist/cli/{attach-ILMHKRUI.js → attach-KEE4A5YP.js} +28 -15
- package/dist/cli/{bridge-LFKUCKQP.js → bridge-X327AZY4.js} +2 -2
- package/dist/cli/{chunk-VGAPV4DC.js → chunk-25RVT5MR.js} +3 -103
- package/dist/cli/{chunk-Q6RMLRPI.js → chunk-3OJCWJAA.js} +2 -2
- package/dist/cli/chunk-4OYVM4MT.js +49 -0
- package/dist/cli/{chunk-IE52REEI.js → chunk-4TCSADFR.js} +5 -23
- package/dist/cli/{chunk-HOOHS3MX.js → chunk-53ISXX2R.js} +1 -1
- package/dist/cli/{chunk-6IYPRUQG.js → chunk-54KF5RBY.js} +1 -1
- package/dist/cli/{chunk-CXZETRPA.js → chunk-7NHQGP6J.js} +1 -1
- package/dist/cli/{chunk-U7J2AN3F.js → chunk-G7XPEVCG.js} +5 -5
- package/dist/cli/{chunk-2BLPGRLO.js → chunk-IWY7DSSO.js} +835 -1030
- package/dist/cli/{chunk-SUBKKCGA.js → chunk-KPDTYX7F.js} +3 -3
- package/dist/cli/chunk-RPH773TY.js +6 -0
- package/dist/cli/{chunk-YHZIHIGI.js → chunk-RX5CJ7YH.js} +3 -5
- package/dist/cli/{chunk-NLL2EQJ2.js → chunk-T547FLQN.js} +38 -4
- package/dist/cli/{chunk-K7UEKSB2.js → chunk-UJ2WBGLW.js} +2 -2
- package/dist/cli/{chunk-OPUIV6PR.js → chunk-ULOMKEB6.js} +4 -4
- package/dist/cli/{chunk-5JNJFBKZ.js → chunk-V4XKKL6K.js} +13 -40
- package/dist/cli/{chunk-EGXOBQZI.js → daemon-RO43S3S5.js} +4655 -2964
- package/dist/cli/{decide-3B6LGVNN.js → decide-KZFYL3HY.js} +5 -5
- package/dist/cli/{handover-IX7EFDIP.js → handover-BWNMI2RA.js} +5 -5
- package/dist/cli/{hook-G7UA6MB6.js → hook-ZLWXI5EQ.js} +21 -71
- package/dist/cli/index.js +18 -25
- package/dist/cli/launch-GCX7TXOH.js +28 -0
- package/dist/cli/{send-55RWY4LZ.js → send-SXZAPVRH.js} +5 -5
- package/dist/cli/{setup-K42IVMHS.js → setup-TJ32FMVJ.js} +4 -4
- package/dist/cli/{status-NT5ZUYM6.js → status-YDVRES4E.js} +3 -3
- package/dist/cli/{task-GABQ4SKY.js → task-TUSOVJK7.js} +5 -5
- package/dist/cli/{tui-AMW2XAH5.js → tui-TCVIRZCQ.js} +1411 -1277
- package/dist/cli/{uninstall-4IMMR55T.js → uninstall-QO7YMSLA.js} +4 -4
- package/dist/cli/{version-35XLTEMX.js → version-BAYSYWFP.js} +1 -1
- package/dist/cli/who-6AZYSP7T.js +12 -0
- package/dist/ledge-guide.md +26 -49
- package/package.json +2 -1
- package/dist/cli/chunk-5FKHISVK.js +0 -160
- package/dist/cli/chunk-M7364G3S.js +0 -6
- package/dist/cli/chunk-QQVWFOPU.js +0 -290
- package/dist/cli/daemon-UJTMG3D4.js +0 -2322
- package/dist/cli/launch-2GZIRF3A.js +0 -36
- package/dist/cli/team-IK2RYXW2.js +0 -205
- package/dist/cli/who-4FRIGYVT.js +0 -12
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
attachEnv
|
|
3
|
-
} from "./chunk-5JNJFBKZ.js";
|
|
4
1
|
import {
|
|
5
2
|
imageInfo
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4OYVM4MT.js";
|
|
4
|
+
import {
|
|
5
|
+
attachEnv
|
|
6
|
+
} from "./chunk-V4XKKL6K.js";
|
|
7
7
|
import {
|
|
8
8
|
MAX_FRAME
|
|
9
9
|
} from "./chunk-OLLQBK6N.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-5FKHISVK.js";
|
|
13
|
-
import "./chunk-IE52REEI.js";
|
|
14
|
-
import "./chunk-CXZETRPA.js";
|
|
10
|
+
import "./chunk-4TCSADFR.js";
|
|
11
|
+
import "./chunk-7NHQGP6J.js";
|
|
15
12
|
import {
|
|
16
13
|
ACTION_ERROR_CODES,
|
|
17
14
|
ATTACHMENTS_MAX,
|
|
@@ -22,6 +19,7 @@ import {
|
|
|
22
19
|
ChatTurnSchema,
|
|
23
20
|
ContextPrefsSchema,
|
|
24
21
|
IslandPrefsSchema,
|
|
22
|
+
KERNEL_RIG,
|
|
25
23
|
LEDGE_GIVER,
|
|
26
24
|
MachinesSchema,
|
|
27
25
|
NOTE_MAX,
|
|
@@ -30,7 +28,7 @@ import {
|
|
|
30
28
|
PROJECT_COLORS,
|
|
31
29
|
PROTOCOL_PORT,
|
|
32
30
|
ProjectsSchema,
|
|
33
|
-
|
|
31
|
+
RIG_POLICIES,
|
|
34
32
|
backendOf,
|
|
35
33
|
contextNear,
|
|
36
34
|
isArchived,
|
|
@@ -42,15 +40,18 @@ import {
|
|
|
42
40
|
projectOf,
|
|
43
41
|
proposalRows,
|
|
44
42
|
readDaemonToken,
|
|
43
|
+
rigCommands,
|
|
44
|
+
seatPlan,
|
|
45
|
+
seatsByRole,
|
|
46
|
+
showRigCommand,
|
|
45
47
|
taskClosed,
|
|
46
48
|
transmissions
|
|
47
|
-
} from "./chunk-
|
|
48
|
-
import "./chunk-
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-6IYPRUQG.js";
|
|
49
|
+
} from "./chunk-IWY7DSSO.js";
|
|
50
|
+
import "./chunk-T547FLQN.js";
|
|
51
|
+
import "./chunk-54KF5RBY.js";
|
|
51
52
|
import {
|
|
52
53
|
ledgeDir
|
|
53
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-53ISXX2R.js";
|
|
54
55
|
import {
|
|
55
56
|
__commonJS,
|
|
56
57
|
__export,
|
|
@@ -346,7 +347,7 @@ var daemonStore = {
|
|
|
346
347
|
return;
|
|
347
348
|
}
|
|
348
349
|
if (m.type === "chat.step" || m.type === "chat.delta" || m.type === "chat.done" || m.type === "chat.error") {
|
|
349
|
-
const chat = state.chat.map((t) => t.qid !== m.qid ? t : m.type === "chat.step" ? { ...t, steps: [...t.steps, m.step] } : m.type === "chat.done" ? { ...t, answer: m.text, answeredAt: m.at, ...m.proposal ? { proposal: m.proposal } : {}, ...m.proposals ? { proposals: m.proposals } : {}, ...m.relay ? { relay: m.relay } : {}, ...m.closes ? { closes: m.closes } : {}, ...m.projectProposal ? { projectProposal: m.projectProposal } : {}, ...m.
|
|
350
|
+
const chat = state.chat.map((t) => t.qid !== m.qid ? t : m.type === "chat.step" ? { ...t, steps: [...t.steps, m.step] } : m.type === "chat.done" ? { ...t, answer: m.text, answeredAt: m.at, ...m.proposal ? { proposal: m.proposal } : {}, ...m.proposals ? { proposals: m.proposals } : {}, ...m.relay ? { relay: m.relay } : {}, ...m.closes ? { closes: m.closes } : {}, ...m.projectProposal ? { projectProposal: m.projectProposal } : {}, ...m.tasks ? { tasks: m.tasks } : {}, ...m.actions ? { actions: m.actions } : {} } : m.type === "chat.error" ? { ...t, error: m.message } : t);
|
|
350
351
|
const chatLive = m.type === "chat.delta" ? { qid: m.qid, text: (state.chatLive?.qid === m.qid ? state.chatLive.text : "") + m.text } : m.type === "chat.step" ? state.chatLive : null;
|
|
351
352
|
state = { ...state, chat, chatLive };
|
|
352
353
|
emit();
|
|
@@ -542,9 +543,6 @@ function useMachines(client) {
|
|
|
542
543
|
var nullSnapshot = () => null;
|
|
543
544
|
var noTasks = [];
|
|
544
545
|
var emptyTasks = () => noTasks;
|
|
545
|
-
function useTeams(client) {
|
|
546
|
-
return useSyncExternalStore3(client.fleet?.subscribe ?? noopSubscribe, client.fleet?.teams ?? nullSnapshot, nullSnapshot);
|
|
547
|
-
}
|
|
548
546
|
var defaultNear = () => CONTEXT_NEAR;
|
|
549
547
|
function useContextNear(client) {
|
|
550
548
|
return useSyncExternalStore3(client.fleet?.subscribe ?? noopSubscribe, () => client.fleet?.contextNear() ?? CONTEXT_NEAR, defaultNear);
|
|
@@ -574,13 +572,14 @@ function changeOf(was, now2) {
|
|
|
574
572
|
}
|
|
575
573
|
|
|
576
574
|
// ../fleet/src/fleet.ts
|
|
577
|
-
var toWire = (list3) => list3.map(({ id, label, ssh }) => ({ id, label, ...ssh ? { ssh } : {} }));
|
|
575
|
+
var toWire = (list3) => list3.map(({ id, label, ssh, disabled }) => ({ id, label, ...ssh ? { ssh } : {}, ...disabled ? { disabled: true } : {} }));
|
|
578
576
|
var OPERATIONS = /* @__PURE__ */ new Set(["session.launch", "session.relay", "session.relay.cancel", "session.close"]);
|
|
579
577
|
function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
580
578
|
const prefix = opts.prefix ?? "ledge";
|
|
581
579
|
const HISTORY_KEY = `${prefix}.fleet.history`, MACHINES_KEY = `${prefix}.machines`;
|
|
582
580
|
let configs = parseMachines(config), selected = configs[0].id, connected = false, configuring = false, state2 = [];
|
|
583
581
|
const peers = /* @__PURE__ */ new Map();
|
|
582
|
+
const active = () => configs.filter((c) => !c.disabled);
|
|
584
583
|
const machineMessages = /* @__PURE__ */ new Set();
|
|
585
584
|
const messages = /* @__PURE__ */ new Set(), statuses = /* @__PURE__ */ new Set(), listeners2 = /* @__PURE__ */ new Set();
|
|
586
585
|
const turns2 = /* @__PURE__ */ new Map(), bindings = /* @__PURE__ */ new Map();
|
|
@@ -590,7 +589,14 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
590
589
|
const scans = /* @__PURE__ */ new Map();
|
|
591
590
|
const attachmentAsks = /* @__PURE__ */ new Map();
|
|
592
591
|
const modelLists = /* @__PURE__ */ new Map();
|
|
593
|
-
const
|
|
592
|
+
const rigFailure = (kind, requestId, machineId, error) => kind === "act" ? { type: "openrig.done", requestId, machineId, ok: false, commands: [], error } : kind === "specs" ? { type: "openrig.specList", requestId, machineId, specs: [], error } : kind === "launch" ? { type: "openrig.launched", requestId, machineId, ok: false, plan: false, commands: [], error } : kind === "seats" ? { type: "openrig.reseated", requestId, machineId, ok: false, commands: [], added: [], removed: [], error } : { type: "openrig.state", requestId, machineId, error };
|
|
593
|
+
const rigAsks = /* @__PURE__ */ new Map();
|
|
594
|
+
const answerFailedRigs = (machine, error) => {
|
|
595
|
+
for (const [requestId, a] of rigAsks) if (a.machine === machine) {
|
|
596
|
+
rigAsks.delete(requestId);
|
|
597
|
+
emit2(rigFailure(a.kind, requestId, machine, error));
|
|
598
|
+
}
|
|
599
|
+
};
|
|
594
600
|
const operations = /* @__PURE__ */ new Map();
|
|
595
601
|
const closeRows = /* @__PURE__ */ new Map();
|
|
596
602
|
const endOperation = (machine) => {
|
|
@@ -624,25 +630,17 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
624
630
|
emit2({ type: "models.listing", requestId, tool: l.tool, models: [], error });
|
|
625
631
|
}
|
|
626
632
|
};
|
|
627
|
-
const answerFailedRoles = (machine, error) => {
|
|
628
|
-
for (const [requestId, owner] of roleLists) if (owner === machine) {
|
|
629
|
-
roleLists.delete(requestId);
|
|
630
|
-
emit2({ type: "roles.listing", requestId, roles: [], templates: [], problems: [], error });
|
|
631
|
-
}
|
|
632
|
-
};
|
|
633
633
|
let source2 = "local";
|
|
634
634
|
let projects = null;
|
|
635
635
|
let island;
|
|
636
636
|
let contextNear2;
|
|
637
637
|
let mobile;
|
|
638
638
|
let mobileError;
|
|
639
|
-
let teams = null;
|
|
640
639
|
let tasks = /* @__PURE__ */ new Map();
|
|
641
640
|
let taskList = [];
|
|
642
641
|
const taskLists = /* @__PURE__ */ new Set();
|
|
643
642
|
let listSeq = 0;
|
|
644
643
|
const local = (id) => id === LEDGE_GIVER ? id : qualify("local", id);
|
|
645
|
-
const teamOut = (t) => ({ ...t, seats: t.seats.map((s) => ({ ...s, sessionId: s.sessionId === null ? null : qualify("local", s.sessionId) })) });
|
|
646
644
|
const taskOut = (t) => ({
|
|
647
645
|
...t,
|
|
648
646
|
giver: local(t.giver),
|
|
@@ -654,14 +652,15 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
654
652
|
taskList = [...tasks.values()].sort((a, b2) => a.at.localeCompare(b2.at));
|
|
655
653
|
listeners2.forEach((fn) => fn());
|
|
656
654
|
};
|
|
655
|
+
const knowsTasks = (version) => {
|
|
656
|
+
const [major = 0, minor = 0] = (version ?? "").split(".").map(Number);
|
|
657
|
+
return major > 0 || minor >= 17;
|
|
658
|
+
};
|
|
657
659
|
const askTasks = (p) => {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
};
|
|
663
|
-
ask2({});
|
|
664
|
-
for (const t of teams ?? []) if (t.state !== "dissolved") ask2({ team: t.id });
|
|
660
|
+
if (!knowsTasks(p.snapshot?.daemon?.version)) return;
|
|
661
|
+
const rid = `fleet-tasks-${++listSeq}`;
|
|
662
|
+
taskLists.add(rid);
|
|
663
|
+
p.client.send({ type: "task.cmd", rid, by: LEDGE_GIVER, op: "list", all: true });
|
|
665
664
|
};
|
|
666
665
|
let routing = null, resetAt = "", lastStatus = "connecting";
|
|
667
666
|
const emit2 = (m) => messages.forEach((fn) => fn(m));
|
|
@@ -710,30 +709,30 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
710
709
|
const stateSessions = (p) => (stale(p) ? p.snapshot.sessions.map((s) => ({ ...s, offline: true })) : p.snapshot?.sessions ?? []).filter((s) => !isArchived(s));
|
|
711
710
|
function refresh() {
|
|
712
711
|
if (configuring) return;
|
|
713
|
-
state2 =
|
|
712
|
+
state2 = active().map((c) => {
|
|
714
713
|
const p = peers.get(c.id);
|
|
715
714
|
return { ...c, status: p.status, ready: available(p), recents: p.snapshot?.recents ?? [], sessions: stateSessions(p), launcher: p.snapshot?.launcher ?? null, version: p.snapshot?.daemon?.version, daemon: p.snapshot?.daemon, error: p.error };
|
|
716
715
|
});
|
|
717
|
-
const
|
|
718
|
-
if (
|
|
719
|
-
lastStatus =
|
|
720
|
-
statuses.forEach((fn) => fn(
|
|
716
|
+
const next3 = status();
|
|
717
|
+
if (next3 !== lastStatus) {
|
|
718
|
+
lastStatus = next3;
|
|
719
|
+
statuses.forEach((fn) => fn(next3));
|
|
721
720
|
}
|
|
722
721
|
listeners2.forEach((fn) => fn());
|
|
723
722
|
}
|
|
724
723
|
function publish() {
|
|
725
724
|
if (configuring) return;
|
|
726
|
-
state2 =
|
|
725
|
+
state2 = active().map((c) => {
|
|
727
726
|
const p = peers.get(c.id);
|
|
728
727
|
return { ...c, status: p.status, ready: available(p), recents: p.snapshot?.recents ?? [], sessions: stateSessions(p), launcher: p.snapshot?.launcher ?? null, version: p.snapshot?.daemon?.version, daemon: p.snapshot?.daemon, error: p.error };
|
|
729
728
|
});
|
|
730
729
|
const primary = peers.get("local")?.snapshot;
|
|
731
730
|
emit2({ type: "snapshot", sessions: [...peers.values()].filter((p) => available(p) || stale(p)).flatMap((p) => p.snapshot.sessions.map((s) => session(p, s))), recents: available(peers.get(selected)) ? peers.get(selected).snapshot.recents : [], launcher: primary?.launcher, daemon: primary?.daemon });
|
|
732
731
|
for (const p of peers.values()) if (available(p) || stale(p)) for (const [id, lines] of p.previews) emit2({ type: "session.preview", id: qualify(p.config.id, id), lines });
|
|
733
|
-
const
|
|
734
|
-
if (
|
|
735
|
-
lastStatus =
|
|
736
|
-
statuses.forEach((fn) => fn(
|
|
732
|
+
const next3 = status();
|
|
733
|
+
if (next3 !== lastStatus) {
|
|
734
|
+
lastStatus = next3;
|
|
735
|
+
statuses.forEach((fn) => fn(next3));
|
|
737
736
|
}
|
|
738
737
|
listeners2.forEach((fn) => fn());
|
|
739
738
|
}
|
|
@@ -764,15 +763,15 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
764
763
|
...raw.actions ? { actions: raw.actions.map((a) => ({ ...a, ...a.session ? { session: qualify(p.config.id, a.session) } : {} })) } : {}
|
|
765
764
|
};
|
|
766
765
|
}
|
|
767
|
-
function apply(
|
|
766
|
+
function apply(next3) {
|
|
768
767
|
configuring = true;
|
|
769
|
-
for (const [id, p] of peers) if (!
|
|
768
|
+
for (const [id, p] of peers) if (!next3.some((c) => !c.disabled && c.id === id && c.url === p.config.url && c.ssh === p.config.ssh)) {
|
|
770
769
|
p.client.close();
|
|
771
770
|
p.off.forEach((off) => off());
|
|
772
771
|
peers.delete(id);
|
|
773
772
|
}
|
|
774
|
-
configs =
|
|
775
|
-
for (const c of
|
|
773
|
+
configs = next3;
|
|
774
|
+
for (const c of active()) {
|
|
776
775
|
const p = peers.get(c.id);
|
|
777
776
|
if (p) p.config = c;
|
|
778
777
|
else add(c);
|
|
@@ -788,15 +787,15 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
788
787
|
const machine = p.config.id;
|
|
789
788
|
if (m.type === "machines") {
|
|
790
789
|
if (machine !== "local" || !opts.machinesFromDaemon) return;
|
|
791
|
-
let
|
|
790
|
+
let next3;
|
|
792
791
|
try {
|
|
793
|
-
|
|
792
|
+
next3 = parseMachines(m.machines);
|
|
794
793
|
} catch {
|
|
795
794
|
return;
|
|
796
795
|
}
|
|
797
|
-
const mine =
|
|
796
|
+
const mine = next3.length === 1 ? loadMachines(prefix) : [];
|
|
798
797
|
source2 = "daemon";
|
|
799
|
-
if (
|
|
798
|
+
if (next3.length === 1 && mine.length > 1) {
|
|
800
799
|
p.client.send({ type: "machines.set", machines: toWire(mine) });
|
|
801
800
|
return;
|
|
802
801
|
}
|
|
@@ -804,7 +803,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
804
803
|
localStorage.removeItem(MACHINES_KEY);
|
|
805
804
|
} catch {
|
|
806
805
|
}
|
|
807
|
-
apply(
|
|
806
|
+
apply(next3);
|
|
808
807
|
return;
|
|
809
808
|
}
|
|
810
809
|
if (m.type === "projects") {
|
|
@@ -825,19 +824,6 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
825
824
|
listeners2.forEach((fn) => fn());
|
|
826
825
|
return;
|
|
827
826
|
}
|
|
828
|
-
if (m.type === "teams" || m.type === "team.updated") {
|
|
829
|
-
if (machine !== "local") return;
|
|
830
|
-
const known2 = new Set((teams ?? []).map((t) => t.id));
|
|
831
|
-
teams = m.type === "teams" ? m.teams.map(teamOut) : [...(teams ?? []).filter((t) => t.id !== m.team.id), teamOut(m.team)].sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
832
|
-
listeners2.forEach((fn) => fn());
|
|
833
|
-
if (m.type === "team.updated" && !known2.has(m.team.id) && m.team.state !== "dissolved") {
|
|
834
|
-
const rid = `fleet-tasks-${++listSeq}`;
|
|
835
|
-
taskLists.add(rid);
|
|
836
|
-
p.client.send({ type: "task.cmd", rid, by: LEDGE_GIVER, op: "list", all: true, team: m.team.id });
|
|
837
|
-
}
|
|
838
|
-
if (m.type === "teams" && p.snapshot?.daemon?.teams) askTasks(p);
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
827
|
if (m.type === "task.updated") {
|
|
842
828
|
if (machine === "local") putTasks([m.task]);
|
|
843
829
|
return;
|
|
@@ -870,6 +856,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
870
856
|
p.restarting = false;
|
|
871
857
|
p.previews.clear();
|
|
872
858
|
publish();
|
|
859
|
+
if (machine === "local") askTasks(p);
|
|
873
860
|
return;
|
|
874
861
|
}
|
|
875
862
|
if (m.type === "session.updated") {
|
|
@@ -959,16 +946,17 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
959
946
|
}
|
|
960
947
|
return;
|
|
961
948
|
}
|
|
962
|
-
if (m.type === "
|
|
963
|
-
if (
|
|
964
|
-
|
|
965
|
-
|
|
949
|
+
if (m.type === "openrig.state" || m.type === "openrig.done" || m.type === "openrig.specList" || m.type === "openrig.launched" || m.type === "openrig.reseated") {
|
|
950
|
+
if (m.requestId !== void 0) {
|
|
951
|
+
if (rigAsks.get(m.requestId)?.machine !== machine) return;
|
|
952
|
+
rigAsks.delete(m.requestId);
|
|
966
953
|
}
|
|
954
|
+
emit2({ ...m, machineId: machine });
|
|
967
955
|
return;
|
|
968
956
|
}
|
|
969
|
-
if (m.type === "
|
|
970
|
-
if (
|
|
971
|
-
|
|
957
|
+
if (m.type === "models.listing") {
|
|
958
|
+
if (modelLists.get(m.requestId)?.machine === machine) {
|
|
959
|
+
modelLists.delete(m.requestId);
|
|
972
960
|
emit2(m);
|
|
973
961
|
}
|
|
974
962
|
return;
|
|
@@ -1015,15 +1003,15 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1015
1003
|
const qid = globalQid(machine, m.qid), old = turns2.get(qid);
|
|
1016
1004
|
if (!old) return;
|
|
1017
1005
|
if (m.type === "chat.done") {
|
|
1018
|
-
const raw = { ...old, qid: m.qid, answer: m.text, answeredAt: m.at, proposal: m.proposal, proposals: m.proposals, relay: m.relay, closes: m.closes, projectProposal: m.projectProposal,
|
|
1006
|
+
const raw = { ...old, qid: m.qid, answer: m.text, answeredAt: m.at, proposal: m.proposal, proposals: m.proposals, relay: m.relay, closes: m.closes, projectProposal: m.projectProposal, tasks: m.tasks, actions: m.actions };
|
|
1019
1007
|
const t = mappedTurn(p, { ...raw, steps: [] });
|
|
1020
1008
|
turns2.set(qid, { ...t, steps: old.steps });
|
|
1021
1009
|
history();
|
|
1022
1010
|
} else if (m.type === "chat.error") fail(qid, m.message);
|
|
1023
1011
|
else if (m.type === "chat.step") {
|
|
1024
|
-
const
|
|
1025
|
-
turns2.set(qid, { ...old, steps: [...old.steps,
|
|
1026
|
-
emit2({ ...m, qid, step:
|
|
1012
|
+
const step3 = { ...m.step, ...m.step.id ? { id: qualify(machine, m.step.id) } : {} };
|
|
1013
|
+
turns2.set(qid, { ...old, steps: [...old.steps, step3] });
|
|
1014
|
+
emit2({ ...m, qid, step: step3 });
|
|
1027
1015
|
} else emit2({ ...m, qid });
|
|
1028
1016
|
return;
|
|
1029
1017
|
}
|
|
@@ -1053,8 +1041,8 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1053
1041
|
answerFailedModels(machine, "outdated");
|
|
1054
1042
|
return;
|
|
1055
1043
|
}
|
|
1056
|
-
if (m.request
|
|
1057
|
-
|
|
1044
|
+
if (m.request?.startsWith("openrig.")) {
|
|
1045
|
+
answerFailedRigs(machine, "outdated");
|
|
1058
1046
|
return;
|
|
1059
1047
|
}
|
|
1060
1048
|
if ((m.request === "folder.list" || m.request === "folder.create") && [...listings.values()].some((l) => l.machine === machine)) {
|
|
@@ -1062,7 +1050,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1062
1050
|
return;
|
|
1063
1051
|
}
|
|
1064
1052
|
if (m.request !== void 0 && OPERATIONS.has(m.request)) endOperation(machine);
|
|
1065
|
-
emit2({ ...m, ...m.id ? { id: qualify(machine, m.id) } : {}, message:
|
|
1053
|
+
emit2({ ...m, ...m.id ? { id: qualify(machine, m.id) } : {}, message: active().length > 1 ? `${p.config.label}: ${m.message}` : m.message });
|
|
1066
1054
|
return;
|
|
1067
1055
|
}
|
|
1068
1056
|
if (m.type === "session.handover.result") {
|
|
@@ -1090,7 +1078,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1090
1078
|
answerUnfoundListings(c.id, "offline");
|
|
1091
1079
|
answerFailedScans(c.id, "offline");
|
|
1092
1080
|
answerFailedModels(c.id, "offline");
|
|
1093
|
-
|
|
1081
|
+
answerFailedRigs(c.id, "offline");
|
|
1094
1082
|
for (const [requestId, owner] of documents) if (owner === c.id) {
|
|
1095
1083
|
documents.delete(requestId);
|
|
1096
1084
|
emit2({ type: "document.error", requestId, path: "", code: "read_failed" });
|
|
@@ -1110,7 +1098,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1110
1098
|
}));
|
|
1111
1099
|
if (connected) client.connect();
|
|
1112
1100
|
}
|
|
1113
|
-
for (const c of
|
|
1101
|
+
for (const c of active()) add(c);
|
|
1114
1102
|
function inventory() {
|
|
1115
1103
|
return { machines: state2.map((m) => ({ id: m.id, label: m.label, online: m.ready, local: m.id === "local", sessions: m.sessions.slice(0, 500).map((s) => ({ id: s.id, name: s.name, project: s.repo ?? s.project, cwd: s.cwd, topic: s.topic, state: s.state, readOnly: s.source === "hook_only" })), folders: m.recents.slice(0, 100).map((r) => ({ project: r.project, cwd: r.cwd })) })), history: [...turns2.values()].slice(-30).map((t) => ({ question: t.question.slice(0, 2e4), answer: t.answer?.slice(0, 2e4), machineId: t.machineId })) };
|
|
1116
1104
|
}
|
|
@@ -1163,7 +1151,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1163
1151
|
const context = inventory();
|
|
1164
1152
|
turns2.set(msg.qid, { qid: msg.qid, question: msg.text, askedAt: (/* @__PURE__ */ new Date()).toISOString(), steps: [] });
|
|
1165
1153
|
history();
|
|
1166
|
-
if (
|
|
1154
|
+
if (active().length === 1) {
|
|
1167
1155
|
const p = peers.get("local");
|
|
1168
1156
|
if (!available(p)) return fail(msg.qid, "Local is offline");
|
|
1169
1157
|
bindings.set(msg.qid, { machine: "local", raw: msg.qid });
|
|
@@ -1216,7 +1204,7 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1216
1204
|
attachmentAsks.set(msg.requestId, machine);
|
|
1217
1205
|
}
|
|
1218
1206
|
if (msg.type === "document.read") {
|
|
1219
|
-
if (
|
|
1207
|
+
if (active().length > 1 && !msg.machineId && !msg.sessionId) {
|
|
1220
1208
|
emit2({ type: "document.error", requestId: msg.requestId, path: msg.path, code: "read_failed" });
|
|
1221
1209
|
return;
|
|
1222
1210
|
}
|
|
@@ -1265,6 +1253,17 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1265
1253
|
}
|
|
1266
1254
|
modelLists.set(msg.requestId, { machine, tool: msg.tool });
|
|
1267
1255
|
}
|
|
1256
|
+
if (msg.type === "openrig.status" || msg.type === "openrig.act" || msg.type === "openrig.specs" || msg.type === "openrig.launch" || msg.type === "openrig.seats") {
|
|
1257
|
+
machine = msg.machineId ?? "local";
|
|
1258
|
+
const { machineId: _m, ...rest } = msg;
|
|
1259
|
+
outgoing = rest;
|
|
1260
|
+
const kind = msg.type === "openrig.status" ? "status" : msg.type === "openrig.act" ? "act" : msg.type === "openrig.specs" ? "specs" : msg.type === "openrig.seats" ? "seats" : "launch";
|
|
1261
|
+
if (!available(peers.get(machine))) {
|
|
1262
|
+
emit2(rigFailure(kind, msg.requestId, machine, "offline"));
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
rigAsks.set(msg.requestId, { machine, kind });
|
|
1266
|
+
}
|
|
1268
1267
|
if (msg.type === "folder.list") {
|
|
1269
1268
|
if (msg.machineId) machine = msg.machineId;
|
|
1270
1269
|
else if (msg.requestId !== void 0) machine = "local";
|
|
@@ -1292,30 +1291,10 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1292
1291
|
}
|
|
1293
1292
|
}
|
|
1294
1293
|
if (msg.type === "update.daemon") machine = "local";
|
|
1295
|
-
if (msg.type === "
|
|
1296
|
-
machine = msg.machineId ?? "local";
|
|
1297
|
-
if (!available(peers.get(machine))) {
|
|
1298
|
-
emit2({ type: "roles.listing", requestId: msg.requestId, roles: [], templates: [], problems: [], error: "offline" });
|
|
1299
|
-
return;
|
|
1300
|
-
}
|
|
1301
|
-
roleLists.set(msg.requestId, machine);
|
|
1302
|
-
}
|
|
1303
|
-
if (msg.type === "roles.list" || msg.type === "team.launch") {
|
|
1304
|
-
if (!("qid" in msg && msg.qid)) machine = msg.machineId ?? "local";
|
|
1305
|
-
const { machineId: _m, ...rest } = outgoing;
|
|
1306
|
-
outgoing = rest;
|
|
1307
|
-
}
|
|
1308
|
-
if (msg.type === "team.join" || msg.type === "team.leave" || msg.type === "team.resume" || msg.type === "team.dissolve" || msg.type === "team.save" || msg.type === "task.cmd" && !msg.qid || msg.type === "action.run") machine = "local";
|
|
1309
|
-
if (outgoing.type === "team.join" || outgoing.type === "team.leave") {
|
|
1310
|
-
const o = splitId(outgoing.session);
|
|
1311
|
-
if (o) {
|
|
1312
|
-
machine = o.machine;
|
|
1313
|
-
outgoing = { ...outgoing, session: o.id };
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1294
|
+
if (msg.type === "task.cmd" && !msg.qid || msg.type === "action.run") machine = "local";
|
|
1316
1295
|
if (outgoing.type === "task.cmd") {
|
|
1317
1296
|
const o = outgoing.to ? splitId(outgoing.to) : null;
|
|
1318
|
-
if (o
|
|
1297
|
+
if (o) outgoing = { ...outgoing, to: o.id };
|
|
1319
1298
|
const b2 = splitId(outgoing.by);
|
|
1320
1299
|
if (b2 && outgoing.by !== LEDGE_GIVER) outgoing = { ...outgoing, by: b2.id };
|
|
1321
1300
|
}
|
|
@@ -1361,16 +1340,17 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1361
1340
|
publish();
|
|
1362
1341
|
},
|
|
1363
1342
|
configure(raw) {
|
|
1364
|
-
const
|
|
1343
|
+
const next3 = parseMachines(raw);
|
|
1365
1344
|
if (source2 === "daemon") {
|
|
1366
1345
|
const local2 = peers.get("local").client;
|
|
1367
1346
|
if (local2.status() !== "open") throw Object.assign(new Error("The local daemon is not connected"), { name: "DaemonOffline" });
|
|
1368
|
-
local2.send({ type: "machines.set", machines: toWire(
|
|
1347
|
+
local2.send({ type: "machines.set", machines: toWire(next3) });
|
|
1369
1348
|
return;
|
|
1370
1349
|
}
|
|
1371
|
-
localStorage.setItem(MACHINES_KEY, JSON.stringify(
|
|
1372
|
-
apply(
|
|
1350
|
+
localStorage.setItem(MACHINES_KEY, JSON.stringify(next3));
|
|
1351
|
+
apply(next3);
|
|
1373
1352
|
},
|
|
1353
|
+
configured: () => configs,
|
|
1374
1354
|
machinesSource: () => source2,
|
|
1375
1355
|
probe: (ssh) => probeMachine(configs[0].url, ssh, { token: opts.token }),
|
|
1376
1356
|
// The last try's error is forgotten: the machine is « connecting » until its next answer (a snapshot, or an error again).
|
|
@@ -1412,16 +1392,16 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1412
1392
|
};
|
|
1413
1393
|
},
|
|
1414
1394
|
projects: () => projects,
|
|
1415
|
-
setProjects(
|
|
1416
|
-
const valid = ProjectsSchema.parse(
|
|
1395
|
+
setProjects(next3) {
|
|
1396
|
+
const valid = ProjectsSchema.parse(next3);
|
|
1417
1397
|
const local2 = peers.get("local").client;
|
|
1418
1398
|
if (local2.status() !== "open") throw Object.assign(new Error("The local daemon is not connected"), { name: "DaemonOffline" });
|
|
1419
1399
|
if (projects === null) throw Object.assign(new Error("Update the local Ledge daemon: it does not know projects"), { name: "DaemonOutdated" });
|
|
1420
1400
|
local2.send({ type: "projects.set", projects: valid });
|
|
1421
1401
|
},
|
|
1422
1402
|
island: () => island,
|
|
1423
|
-
setIsland(
|
|
1424
|
-
const valid = IslandPrefsSchema.parse(
|
|
1403
|
+
setIsland(next3) {
|
|
1404
|
+
const valid = IslandPrefsSchema.parse(next3);
|
|
1425
1405
|
const local2 = peers.get("local").client;
|
|
1426
1406
|
if (local2.status() !== "open") throw Object.assign(new Error("The local daemon is not connected"), { name: "DaemonOffline" });
|
|
1427
1407
|
if (island === void 0) throw Object.assign(new Error("Update the local Ledge daemon: it does not know the island settings"), { name: "DaemonOutdated" });
|
|
@@ -1429,7 +1409,6 @@ function createFleetClient(config, makeClient = createDaemonClient, opts = {}) {
|
|
|
1429
1409
|
},
|
|
1430
1410
|
mobile: () => mobile,
|
|
1431
1411
|
mobileError: () => mobileError,
|
|
1432
|
-
teams: () => teams,
|
|
1433
1412
|
tasks: () => taskList,
|
|
1434
1413
|
contextNear: () => contextNear2,
|
|
1435
1414
|
setContextNear(near) {
|
|
@@ -1512,8 +1491,8 @@ function getImage(client, attachment, route = {}, preview = false, timeoutMs = T
|
|
|
1512
1491
|
}
|
|
1513
1492
|
|
|
1514
1493
|
// src/tui/App.tsx
|
|
1515
|
-
import { useCallback, useEffect as
|
|
1516
|
-
import { useApp, useInput as
|
|
1494
|
+
import { useCallback as useCallback2, useEffect as useEffect15, useMemo as useMemo7, useRef as useRef14, useState as useState16 } from "react";
|
|
1495
|
+
import { useApp, useInput as useInput8, useStdout, useWindowSize as useWindowSize2 } from "ink";
|
|
1517
1496
|
|
|
1518
1497
|
// src/tui/actions.ts
|
|
1519
1498
|
import { useEffect as useEffect3, useMemo, useRef as useRef2 } from "react";
|
|
@@ -1874,7 +1853,7 @@ async function openImage(file, env = process.env, spawnImpl = spawn2, platform =
|
|
|
1874
1853
|
// src/tui/context.tsx
|
|
1875
1854
|
import { createContext, useContext, useEffect as useEffect4, useRef as useRef3 } from "react";
|
|
1876
1855
|
import { useWindowSize } from "ink";
|
|
1877
|
-
var SCREENS = ["overview", "session", "ask", "launch", "settings", "
|
|
1856
|
+
var SCREENS = ["overview", "session", "ask", "launch", "settings", "openrig"];
|
|
1878
1857
|
var TuiContext = createContext(null);
|
|
1879
1858
|
var useTui = () => {
|
|
1880
1859
|
const tui = useContext(TuiContext);
|
|
@@ -1921,7 +1900,7 @@ function formatBytes(n, lang) {
|
|
|
1921
1900
|
var b = (name) => `**${name}**`;
|
|
1922
1901
|
var short = (text5) => text5.length <= 100 ? text5 : `${text5.slice(0, 99)}\u2026`;
|
|
1923
1902
|
var need = (v, keys, say) => keys.every((k) => v[k]) ? say(v) : void 0;
|
|
1924
|
-
var about = (action, v) => action?.startsWith("
|
|
1903
|
+
var about = (action, v) => action?.startsWith("task.") && v.task ? "task" : v.session ? "session" : v.task ? "task" : null;
|
|
1925
1904
|
var fr = {
|
|
1926
1905
|
line: {
|
|
1927
1906
|
"session.model": (v) => need(v, ["session"], (w) => `Passer ${b(w.session)} sur ${v.model ? `${v.model}${v.effort ? `, effort ${v.effort}` : ""}` : v.effort ? `son mod\xE8le par d\xE9faut, effort ${v.effort}` : "son mod\xE8le et son effort par d\xE9faut"}`),
|
|
@@ -1931,26 +1910,21 @@ var fr = {
|
|
|
1931
1910
|
"session.resume": (v) => need(v, ["session"], (w) => `Reprendre ${b(w.session)} sur sa conversation`),
|
|
1932
1911
|
"session.close": (v) => need(v, ["session"], (w) => `Fermer ${b(w.session)}`),
|
|
1933
1912
|
"session.decide": (v) => need(v, ["session", "decision", "kind"], (w) => `${w.decision === "deny" ? "Refuser" : "Accepter"} la demande de ${w.kind} de ${b(w.session)}${v.note ? ", avec une note" : ""}`),
|
|
1934
|
-
"team.join": (v) => need(v, ["session", "team", "role"], (w) => `Faire entrer ${b(w.session)} dans ${b(w.team)} comme @${w.role}`),
|
|
1935
|
-
"team.leave": (v) => need(v, ["session", "team"], (w) => `Retirer ${b(w.session)} de ${b(w.team)}`),
|
|
1936
|
-
"team.resume": (v) => need(v, ["team"], (w) => `Reprendre l\u2019\xE9quipe ${b(w.team)}`),
|
|
1937
|
-
"team.dissolve": (v) => need(v, ["team"], (w) => `Dissoudre l\u2019\xE9quipe ${b(w.team)}`),
|
|
1938
|
-
"team.save": (v) => need(v, ["team", "name"], (w) => v.replaces ? `Remplacer le mod\xE8le \xAB ${w.name} \xBB par ${b(w.team)}` : `Enregistrer ${b(w.team)} comme mod\xE8le \xAB ${w.name} \xBB`),
|
|
1939
1913
|
"task.cancel": (v) => need(v, ["task", "owner"], (w) => `Annuler la t\xE2che \xAB ${short(w.task)} \xBB de ${b(w.owner)}`),
|
|
1940
1914
|
"task.pass": (v) => need(v, ["task", "owner", "session"], (w) => `Passer la t\xE2che \xAB ${short(w.task)} \xBB de ${b(w.owner)} \xE0 ${b(w.session)}`),
|
|
1941
1915
|
"task.answer": (v) => need(v, ["task", "session"], (w) => `R\xE9pondre \xE0 la d\xE9cision \xAB ${short(w.task)} \xBB de ${b(w.session)}`)
|
|
1942
1916
|
},
|
|
1943
1917
|
why: (code3, action, v) => {
|
|
1944
|
-
const s = v.session ? b(v.session) : void 0,
|
|
1918
|
+
const s = v.session ? b(v.session) : void 0, k = v.task ? `\xAB ${short(v.task)} \xBB` : void 0;
|
|
1945
1919
|
const gone = "cette action n\u2019est plus possible.";
|
|
1946
1920
|
switch (code3) {
|
|
1947
1921
|
case "unknown": {
|
|
1948
1922
|
const on = about(action, v);
|
|
1949
|
-
return on === "
|
|
1923
|
+
return on === "task" ? `Ledge ne trouve plus la t\xE2che ${k}.` : on === "session" ? `Ledge ne trouve plus ${s}.` : gone;
|
|
1950
1924
|
}
|
|
1951
1925
|
case "ambiguous": {
|
|
1952
1926
|
const on = about(action, v);
|
|
1953
|
-
return on === "
|
|
1927
|
+
return on === "session" ? `plusieurs sessions s\u2019appellent ${s} : redemande \xE0 Ledge en pr\xE9cisant laquelle.` : gone;
|
|
1954
1928
|
}
|
|
1955
1929
|
case "read_only":
|
|
1956
1930
|
return s ? `${s} est en lecture seule : Ledge ne peut pas lui \xE9crire.` : gone;
|
|
@@ -1972,18 +1946,6 @@ var fr = {
|
|
|
1972
1946
|
return s ? `les demandes de ${s} se r\xE8glent dans sa session.` : gone;
|
|
1973
1947
|
case "no_note":
|
|
1974
1948
|
return s ? `${s} ne peut pas recevoir de note avec cette r\xE9ponse.` : gone;
|
|
1975
|
-
case "member":
|
|
1976
|
-
return s && t ? `${s} est d\xE9j\xE0 dans l\u2019\xE9quipe ${t}.` : gone;
|
|
1977
|
-
case "not_member":
|
|
1978
|
-
return s && t ? `${s} n\u2019est pas dans l\u2019\xE9quipe ${t}.` : gone;
|
|
1979
|
-
case "unknown_role":
|
|
1980
|
-
return v.role ? `le r\xF4le @${v.role} n\u2019existe pas pour ce projet.` : gone;
|
|
1981
|
-
case "not_resting":
|
|
1982
|
-
return t ? `l\u2019\xE9quipe ${t} n\u2019est pas au repos : rien \xE0 reprendre.` : gone;
|
|
1983
|
-
case "dissolved":
|
|
1984
|
-
return t ? `l\u2019\xE9quipe ${t} a \xE9t\xE9 dissoute entre-temps.` : gone;
|
|
1985
|
-
case "no_seat":
|
|
1986
|
-
return t ? `l\u2019\xE9quipe ${t} n\u2019a aucun poste : rien \xE0 enregistrer comme mod\xE8le.` : gone;
|
|
1987
1949
|
case "closed":
|
|
1988
1950
|
return k ? `la t\xE2che ${k} est d\xE9j\xE0 close.` : gone;
|
|
1989
1951
|
case "holder":
|
|
@@ -2010,26 +1972,21 @@ var en = {
|
|
|
2010
1972
|
"session.resume": (v) => need(v, ["session"], (w) => `Resume ${b(w.session)} on its conversation`),
|
|
2011
1973
|
"session.close": (v) => need(v, ["session"], (w) => `Close ${b(w.session)}`),
|
|
2012
1974
|
"session.decide": (v) => need(v, ["session", "decision", "kind"], (w) => `${w.decision === "deny" ? "Deny" : "Accept"} ${b(w.session)}\u2019s ${w.kind} request${v.note ? ", with a note" : ""}`),
|
|
2013
|
-
"team.join": (v) => need(v, ["session", "team", "role"], (w) => `Add ${b(w.session)} to ${b(w.team)} as @${w.role}`),
|
|
2014
|
-
"team.leave": (v) => need(v, ["session", "team"], (w) => `Remove ${b(w.session)} from ${b(w.team)}`),
|
|
2015
|
-
"team.resume": (v) => need(v, ["team"], (w) => `Resume the team ${b(w.team)}`),
|
|
2016
|
-
"team.dissolve": (v) => need(v, ["team"], (w) => `Dissolve the team ${b(w.team)}`),
|
|
2017
|
-
"team.save": (v) => need(v, ["team", "name"], (w) => v.replaces ? `Replace the template \u201C${w.name}\u201D with ${b(w.team)}` : `Save ${b(w.team)} as the template \u201C${w.name}\u201D`),
|
|
2018
1975
|
"task.cancel": (v) => need(v, ["task", "owner"], (w) => `Cancel ${b(w.owner)}\u2019s task \u201C${short(w.task)}\u201D`),
|
|
2019
1976
|
"task.pass": (v) => need(v, ["task", "owner", "session"], (w) => `Pass ${b(w.owner)}\u2019s task \u201C${short(w.task)}\u201D to ${b(w.session)}`),
|
|
2020
1977
|
"task.answer": (v) => need(v, ["task", "session"], (w) => `Answer ${b(w.session)}\u2019s decision \u201C${short(w.task)}\u201D`)
|
|
2021
1978
|
},
|
|
2022
1979
|
why: (code3, action, v) => {
|
|
2023
|
-
const s = v.session ? b(v.session) : void 0,
|
|
1980
|
+
const s = v.session ? b(v.session) : void 0, k = v.task ? `\u201C${short(v.task)}\u201D` : void 0;
|
|
2024
1981
|
const gone = "this action is no longer possible.";
|
|
2025
1982
|
switch (code3) {
|
|
2026
1983
|
case "unknown": {
|
|
2027
1984
|
const on = about(action, v);
|
|
2028
|
-
return on === "
|
|
1985
|
+
return on === "task" ? `Ledge can no longer find the task ${k}.` : on === "session" ? `Ledge can no longer find ${s}.` : gone;
|
|
2029
1986
|
}
|
|
2030
1987
|
case "ambiguous": {
|
|
2031
1988
|
const on = about(action, v);
|
|
2032
|
-
return on === "
|
|
1989
|
+
return on === "session" ? `several sessions are called ${s}: ask Ledge again and say which one.` : gone;
|
|
2033
1990
|
}
|
|
2034
1991
|
case "read_only":
|
|
2035
1992
|
return s ? `${s} is read-only: Ledge cannot write to it.` : gone;
|
|
@@ -2051,18 +2008,6 @@ var en = {
|
|
|
2051
2008
|
return s ? `${s}\u2019s requests are answered in its session.` : gone;
|
|
2052
2009
|
case "no_note":
|
|
2053
2010
|
return s ? `${s} cannot take a note with this answer.` : gone;
|
|
2054
|
-
case "member":
|
|
2055
|
-
return s && t ? `${s} is already in the team ${t}.` : gone;
|
|
2056
|
-
case "not_member":
|
|
2057
|
-
return s && t ? `${s} is not in the team ${t}.` : gone;
|
|
2058
|
-
case "unknown_role":
|
|
2059
|
-
return v.role ? `there is no @${v.role} role for this project.` : gone;
|
|
2060
|
-
case "not_resting":
|
|
2061
|
-
return t ? `the team ${t} is not resting: nothing to resume.` : gone;
|
|
2062
|
-
case "dissolved":
|
|
2063
|
-
return t ? `the team ${t} was dissolved in the meantime.` : gone;
|
|
2064
|
-
case "no_seat":
|
|
2065
|
-
return t ? `the team ${t} has no seat: nothing to save as a template.` : gone;
|
|
2066
2011
|
case "closed":
|
|
2067
2012
|
return k ? `the task ${k} is already closed.` : gone;
|
|
2068
2013
|
case "holder":
|
|
@@ -2097,11 +2042,6 @@ var fr2 = {
|
|
|
2097
2042
|
"session.restore": "Restaurer",
|
|
2098
2043
|
"session.resume": "Reprendre",
|
|
2099
2044
|
"session.decide": "Accepter",
|
|
2100
|
-
"team.join": "Ajouter",
|
|
2101
|
-
"team.leave": "Retirer",
|
|
2102
|
-
"team.resume": "Reprendre",
|
|
2103
|
-
"team.dissolve": "Dissoudre",
|
|
2104
|
-
"team.save": "Enregistrer",
|
|
2105
2045
|
"task.cancel": "Abandonner",
|
|
2106
2046
|
"task.pass": "Passer le relais",
|
|
2107
2047
|
"task.answer": "R\xE9pondre"
|
|
@@ -2164,11 +2104,6 @@ var en2 = {
|
|
|
2164
2104
|
"session.restore": "Restore",
|
|
2165
2105
|
"session.resume": "Resume",
|
|
2166
2106
|
"session.decide": "Accept",
|
|
2167
|
-
"team.join": "Add",
|
|
2168
|
-
"team.leave": "Remove",
|
|
2169
|
-
"team.resume": "Resume",
|
|
2170
|
-
"team.dissolve": "Dissolve",
|
|
2171
|
-
"team.save": "Save",
|
|
2172
2107
|
"task.cancel": "Drop",
|
|
2173
2108
|
"task.pass": "Hand over",
|
|
2174
2109
|
"task.answer": "Answer"
|
|
@@ -2232,7 +2167,7 @@ var fr3 = {
|
|
|
2232
2167
|
h: (n) => `${n} h`,
|
|
2233
2168
|
d: (n) => `${n} j`
|
|
2234
2169
|
},
|
|
2235
|
-
tabs: { overview: "Vue d\u2019ensemble", session: "Session", ask: "Demander \xE0 Ledge", launch: "Nouvelle session", settings: "R\xE9glages",
|
|
2170
|
+
tabs: { overview: "Vue d\u2019ensemble", session: "Session", ask: "Demander \xE0 Ledge", launch: "Nouvelle session", settings: "R\xE9glages", openrig: "OpenRig" },
|
|
2236
2171
|
bar: {
|
|
2237
2172
|
sessions: (n) => `${n} ${plural(n, "session", "sessions")}`,
|
|
2238
2173
|
machines: (n) => `${n} ${plural(n, "machine", "machines")}`,
|
|
@@ -2274,11 +2209,6 @@ var fr3 = {
|
|
|
2274
2209
|
scroll: "d\xE9filer",
|
|
2275
2210
|
space: "espace",
|
|
2276
2211
|
redraw: "autre nom",
|
|
2277
|
-
save: "enregistrer l\u2019\xE9quipe",
|
|
2278
|
-
tasks: "t\xE2ches de l\u2019\xE9quipe",
|
|
2279
|
-
join: "rejoindre une \xE9quipe",
|
|
2280
|
-
resume: "reprendre l\u2019\xE9quipe",
|
|
2281
|
-
teamMode: "session ou \xE9quipe",
|
|
2282
2212
|
handover: "passer le relais",
|
|
2283
2213
|
decide: "r\xE9pondre \xE0 la d\xE9cision",
|
|
2284
2214
|
sendAnswer: "envoyer la r\xE9ponse",
|
|
@@ -2306,16 +2236,12 @@ var fr3 = {
|
|
|
2306
2236
|
deny: "refuser",
|
|
2307
2237
|
ignore: "ignorer",
|
|
2308
2238
|
review: "revoir",
|
|
2309
|
-
openSession: (name) => `ouvrir ${name}
|
|
2310
|
-
rolesTemplates: "r\xF4les / mod\xE8les",
|
|
2311
|
-
folder: "dossier",
|
|
2312
|
-
launchRole: "lancer avec ce r\xF4le",
|
|
2313
|
-
launchTeam: "lancer cette \xE9quipe",
|
|
2314
|
-
openFile: "ouvrir le fichier",
|
|
2315
|
-
ignored: "ignor\xE9s",
|
|
2316
|
-
reread: "relire"
|
|
2239
|
+
openSession: (name) => `ouvrir ${name}`
|
|
2317
2240
|
},
|
|
2318
2241
|
overview: {
|
|
2242
|
+
rigsGroup: "RIGS",
|
|
2243
|
+
kernelGroup: "KERNEL",
|
|
2244
|
+
rigSeat: (rig, role) => `rig ${rig} \xB7 ${role}`,
|
|
2319
2245
|
yours: (n) => `\xC0 toi \xB7 ${n}`,
|
|
2320
2246
|
projects: "Projets",
|
|
2321
2247
|
exchanges: "\xC9changes",
|
|
@@ -2336,11 +2262,6 @@ var fr3 = {
|
|
|
2336
2262
|
deny: "Refuser",
|
|
2337
2263
|
always: "Toujours",
|
|
2338
2264
|
denyWithNote: "Refuser en expliquant",
|
|
2339
|
-
common: "table commune",
|
|
2340
|
-
teamLine: (done, given) => `\xE9quipe \xB7 ${done}/${given}`,
|
|
2341
|
-
resting: "au repos \xB7 R pour reprendre",
|
|
2342
|
-
tasks: (team) => `T\xE2ches \xB7 ${team}`,
|
|
2343
|
-
noTask: "Aucune t\xE2che.",
|
|
2344
2265
|
ledge: "Ledge",
|
|
2345
2266
|
near: (name, pct) => `${name} \xB7 ctx ${pct} % \xB7 H rel\xE8ve`,
|
|
2346
2267
|
reliefFailed: (name, why) => `La rel\xE8ve de ${name} a \xE9chou\xE9 : ${why}`,
|
|
@@ -2352,10 +2273,7 @@ var fr3 = {
|
|
|
2352
2273
|
decision: (giver, title2) => `${giver} te demande : ${title2}`,
|
|
2353
2274
|
decisionTitle: (giver, title2) => `R\xE9pondre \xE0 ${giver} \xB7 ${title2}`,
|
|
2354
2275
|
decisionHint: "Ta r\xE9ponse, telle que la session la lira\u2026",
|
|
2355
|
-
confirmAnswer: (giver) => `Envoyer \xE0 ${giver} ? Une r\xE9ponse ne se reprend pas
|
|
2356
|
-
joinWhich: (name) => `${name} rejoint quelle \xE9quipe ? (\u2191\u2193 \u21B5, esc)`,
|
|
2357
|
-
noTeamHere: "Aucune \xE9quipe dans ce projet.",
|
|
2358
|
-
notInTeam: "Cette session n\u2019est dans aucune \xE9quipe."
|
|
2276
|
+
confirmAnswer: (giver) => `Envoyer \xE0 ${giver} ? Une r\xE9ponse ne se reprend pas`
|
|
2359
2277
|
},
|
|
2360
2278
|
session: {
|
|
2361
2279
|
you: "Vous",
|
|
@@ -2413,19 +2331,8 @@ var fr3 = {
|
|
|
2413
2331
|
offline: "Le daemon local est hors ligne : la question attendra.",
|
|
2414
2332
|
steps: { sessions: "les sessions", pane: (n) => `le terminal de ${n}`, reply: (n) => `la r\xE9ponse de ${n}`, git: (n) => `l\u2019\xE9tat git de ${n}`, repo: (p) => p },
|
|
2415
2333
|
operator: (s, m) => `Ledge \xB7 Op\xE9rateur \xB7 voit ${s} ${plural(s, "session", "sessions")}, ${m} ${plural(m, "machine", "machines")}`,
|
|
2416
|
-
teamCard: (name) => `\xC9quipe \xB7 ${name}`,
|
|
2417
2334
|
taskCard: "T\xE2ches \xE0 confier",
|
|
2418
|
-
launchTeam: "Lancer l\u2019\xE9quipe",
|
|
2419
|
-
save: "Enregistrer",
|
|
2420
|
-
saved: "enregistr\xE9e",
|
|
2421
|
-
seats: "Si\xE8ges",
|
|
2422
|
-
table: "Table",
|
|
2423
|
-
newTable: (project) => `nouvelle table dans la pi\xE8ce ${project}`,
|
|
2424
|
-
autonomy: { ask: "demande", edits: "modifie sans demander", auto: "autonome" },
|
|
2425
|
-
autoWarning: (roles) => `${roles} travaillera sans demander.`,
|
|
2426
|
-
teamLaunched: (at) => `\u2713 \xC9quipe lanc\xE9e \xE0 ${at}`,
|
|
2427
2335
|
give: "Confier",
|
|
2428
|
-
waitTeam: "active une fois l\u2019\xE9quipe lanc\xE9e",
|
|
2429
2336
|
given: (owner, id, state2) => `\u2713 Confi\xE9e \xE0 ${owner} \xB7 ${id} \xB7 ${state2}`,
|
|
2430
2337
|
taskState: { open: "\xE0 prendre", taken: "prise", done: "finie", refused: "refus\xE9e", dropped: "abandonn\xE9e" },
|
|
2431
2338
|
placeholder: "Une question pour Ledge\u2026",
|
|
@@ -2476,66 +2383,7 @@ var fr3 = {
|
|
|
2476
2383
|
thenAttach: "puis a pour s\u2019attacher \xE0 son terminal",
|
|
2477
2384
|
missing: { prompt: "\xC9crivez une instruction.", machine: "Aucune machine en ligne.", repos: "Choisissez un d\xE9p\xF4t ou un dossier." },
|
|
2478
2385
|
launching: "Lancement\u2026",
|
|
2479
|
-
launched: (name) => `\u2713 ${name} est lanc\xE9e
|
|
2480
|
-
teamTitle: "Nouvelle \xE9quipe",
|
|
2481
|
-
mode: "Mode",
|
|
2482
|
-
session: "session",
|
|
2483
|
-
team: "\xE9quipe",
|
|
2484
|
-
template: "Mod\xE8le",
|
|
2485
|
-
custom: "si\xE8ges choisis un par un",
|
|
2486
|
-
seats: "Si\xE8ges",
|
|
2487
|
-
teamName: "Nom",
|
|
2488
|
-
noRole: "aucun r\xF4le : \xE9cris ~/.ledge/roles/<id>.md",
|
|
2489
|
-
loadingRoles: "lecture des r\xF4les\u2026",
|
|
2490
|
-
teamPreview: (team, project) => `L\u2019\xE9quipe ${team} s\u2019installera \xE0 une nouvelle table de la pi\xE8ce ${project}.`,
|
|
2491
|
-
teamLaunched: (name) => `\u2713 \xC9quipe ${name} lanc\xE9e`,
|
|
2492
|
-
teamFailed: (why) => `\xC9quipe non lanc\xE9e : ${why}`,
|
|
2493
|
-
noSeat: "Choisissez au moins un si\xE8ge."
|
|
2494
|
-
},
|
|
2495
|
-
catalog: {
|
|
2496
|
-
roles: "r\xF4les",
|
|
2497
|
-
templates: "mod\xE8les",
|
|
2498
|
-
homeOnly: "Perso seulement",
|
|
2499
|
-
repoRoles: "d\xE9p\xF4t \xB7 .ledge/roles",
|
|
2500
|
-
homeRoles: "perso \xB7 ~/.ledge/roles",
|
|
2501
|
-
repoTeams: "d\xE9p\xF4t \xB7 .ledge/teams",
|
|
2502
|
-
homeTeams: "perso \xB7 ~/.ledge/teams",
|
|
2503
|
-
repo: "d\xE9p\xF4t",
|
|
2504
|
-
home: "perso",
|
|
2505
|
-
tool: "outil",
|
|
2506
|
-
model: "mod\xE8le",
|
|
2507
|
-
effort: "effort",
|
|
2508
|
-
autonomy: "autonomie",
|
|
2509
|
-
file: "fichier",
|
|
2510
|
-
usedIn: "dans",
|
|
2511
|
-
heldBy: "tenu par",
|
|
2512
|
-
teams: "\xE9quipes",
|
|
2513
|
-
replaces: (path2) => `remplace ${path2}`,
|
|
2514
|
-
toolDefault: "d\xE9faut de l\u2019outil",
|
|
2515
|
-
noTemplate: "aucun mod\xE8le",
|
|
2516
|
-
nobody: "personne",
|
|
2517
|
-
noTeam: "aucune",
|
|
2518
|
-
active: "active",
|
|
2519
|
-
resting: "au repos",
|
|
2520
|
-
instruction: (n, max) => `Consigne \xB7 ${n}/${max}`,
|
|
2521
|
-
noInstruction: "Pas de consigne.",
|
|
2522
|
-
seats: (n) => `${n} ${plural(n, "poste", "postes")}`,
|
|
2523
|
-
autonomyShort: { ask: "demande", edits: "\xE9ditions", auto: "auto" },
|
|
2524
|
-
ignored: (n) => `\u26A0 ${n} ${plural(n, "fichier ignor\xE9", "fichiers ignor\xE9s")}`,
|
|
2525
|
-
see: "voir",
|
|
2526
|
-
problems: "Fichiers ignor\xE9s",
|
|
2527
|
-
noProblem: "Aucun fichier ignor\xE9.",
|
|
2528
|
-
loading: "lecture des r\xF4les\u2026",
|
|
2529
|
-
noAnswer: "Le daemon n\u2019a pas r\xE9pondu.",
|
|
2530
|
-
offline: (m) => `${m} est hors ligne.`,
|
|
2531
|
-
outdated: (m) => `Le daemon de ${m} est trop ancien pour le catalogue.`,
|
|
2532
|
-
onMachine: (m) => `sur ${m}`,
|
|
2533
|
-
roleChecking: (id) => `@${id} : lecture du r\xF4le dans ce dossier\u2026`,
|
|
2534
|
-
roleReadIn: (cwd) => `celui de ${cwd}`,
|
|
2535
|
-
roleElsewhere: (id, cwd) => `@${id} n\u2019est lu que dans ${cwd} : lanc\xE9 sans r\xF4le`,
|
|
2536
|
-
noRole: "Aucun r\xF4le ici : \xE9cris .ledge/roles/<id>.md",
|
|
2537
|
-
noTemplateHere: "Aucun mod\xE8le ici : \xE9cris .ledge/teams/<id>.yaml",
|
|
2538
|
-
role: "R\xF4le"
|
|
2386
|
+
launched: (name) => `\u2713 ${name} est lanc\xE9e`
|
|
2539
2387
|
},
|
|
2540
2388
|
settings: { title: "R\xE9glages", language: "Langue", theme: "Th\xE8me", themes: { auto: "Auto", dark: "Sombre", light: "Clair" }, themeAuto: (tone2) => `Auto (fond ${tone2 === "light" ? "clair" : "sombre"})`, context: "Contexte max", contextHint: "au-del\xE0 : passer le relais", contextUnknown: "mettez \xE0 jour le daemon", contextSaved: (pct) => `Contexte max : ${pct} %`, saved: "R\xE9glage enregistr\xE9.", saveFailed: (m) => `R\xE9glage appliqu\xE9, mais non enregistr\xE9 : ${m}` },
|
|
2541
2389
|
help: {
|
|
@@ -2546,8 +2394,9 @@ var fr3 = {
|
|
|
2546
2394
|
ask: "Demander \xE0 Ledge",
|
|
2547
2395
|
launch: "Nouvelle session",
|
|
2548
2396
|
settings: "R\xE9glages",
|
|
2397
|
+
openrig: "OpenRig",
|
|
2398
|
+
rigLaunch: "Lancer un rig",
|
|
2549
2399
|
screens: "changer d\u2019\xE9cran",
|
|
2550
|
-
teams: "\xC9quipes",
|
|
2551
2400
|
field: "Saisie",
|
|
2552
2401
|
wordBefore: "effacer le mot avant",
|
|
2553
2402
|
more: (above, below) => [above ? `\u2191 ${above} plus haut` : "", below ? `\u2193 ${below} plus bas` : ""].filter(Boolean).join(" \xB7 ")
|
|
@@ -2593,9 +2442,6 @@ var fr3 = {
|
|
|
2593
2442
|
noTerminal: (n) => `Pas de terminal pour ${n}.`,
|
|
2594
2443
|
attachFailed: (code3) => `tmux s\u2019est arr\xEAt\xE9 avec le code ${code3}.`,
|
|
2595
2444
|
modelSwitch: "Ce daemon ne change pas le mod\xE8le d\u2019une session en cours.",
|
|
2596
|
-
joined: (n, team) => `${n} rejoint ${team}.`,
|
|
2597
|
-
resumed: (team) => `Reprise de l\u2019\xE9quipe ${team} demand\xE9e.`,
|
|
2598
|
-
saved: (path2) => `\xC9quipe enregistr\xE9e : ${path2}`,
|
|
2599
2445
|
draftKept: "Brouillon gard\xE9 : r pour reprendre.",
|
|
2600
2446
|
draftQuit: "Brouillon en cours : ctrl+c encore pour quitter quand m\xEAme (il sera perdu).",
|
|
2601
2447
|
exited: (cmd, code3) => `${cmd} s\u2019est arr\xEAt\xE9 avec le code ${code3}.`
|
|
@@ -2612,10 +2458,154 @@ var fr3 = {
|
|
|
2612
2458
|
question: (n, text5) => `${n} a une question : ${text5}`,
|
|
2613
2459
|
title: (n) => n > 0 ? `ledge \xB7 ${n} t\u2019${plural(n, "attend", "attendent")}` : "ledge"
|
|
2614
2460
|
},
|
|
2461
|
+
openrig: {
|
|
2462
|
+
operatorKey: "op\xE9rateur",
|
|
2463
|
+
operatorHint: "O : lui parler",
|
|
2464
|
+
operatorNotYet: "Ledge ne suit pas encore la session de l\u2019op\xE9rateur : r\xE9essayez dans quelques secondes.",
|
|
2465
|
+
activity: (a) => ({ running: "au travail", idle: "disponible", unknown: "\u2014" })[a] ?? a,
|
|
2466
|
+
title: "OpenRig",
|
|
2467
|
+
daemon: "Daemon",
|
|
2468
|
+
kernel: "Kernel",
|
|
2469
|
+
rigs: "Rigs",
|
|
2470
|
+
machine: "machine",
|
|
2471
|
+
toggle: "d\xE9marrer/arr\xEAter",
|
|
2472
|
+
restart: "red\xE9marrer",
|
|
2473
|
+
unfold: "d\xE9plier",
|
|
2474
|
+
daemonKey: "daemon",
|
|
2475
|
+
kernelKey: "kernel",
|
|
2476
|
+
daemonState: { running: "actif", stopped: "arr\xEAt\xE9", stale: "arr\xEAt\xE9 sans arr\xEAt propre", unknown: "inconnu" },
|
|
2477
|
+
kernelState: { ready: "pr\xEAt", starting: "d\xE9marrage", stopped: "arr\xEAt\xE9", skipped: "sans kernel", absent: "absent", unknown: "inconnu" },
|
|
2478
|
+
look: { running: "en marche", starting: "d\xE9marrage", attention: "\xE0 surveiller", stopped: "arr\xEAt\xE9" },
|
|
2479
|
+
daemonMeta: (port, pid) => [port ? `127.0.0.1:${port}` : "", pid ? `pid ${pid}` : ""].filter(Boolean).join(" \xB7 "),
|
|
2480
|
+
restoreHint: "\u21BB au d\xE9marrage : rigs relanc\xE9s",
|
|
2481
|
+
kernelHint: "l\u2019op\xE9rateur qui aide \xE0 lancer un rig",
|
|
2482
|
+
seats: (running, total) => `${running}/${total}`,
|
|
2483
|
+
attention: (n) => `${n} ${plural(n, "si\xE8ge demande", "si\xE8ges demandent")} attention`,
|
|
2484
|
+
since: (uptime) => `depuis ${uptime}`,
|
|
2485
|
+
snapshot: (s) => `snapshot ${s}`,
|
|
2486
|
+
work: (n) => n ? `${n} ${plural(n, "t\xE2che", "t\xE2ches")}` : "",
|
|
2487
|
+
stoppedOnPurpose: "arr\xEAt\xE9 volontairement",
|
|
2488
|
+
noRigs: "Aucun rig sur cette machine.",
|
|
2489
|
+
notInstalled: "OpenRig n\u2019est pas install\xE9 sur cette machine (la commande rig est introuvable).",
|
|
2490
|
+
stoppedDaemon: "Le daemon OpenRig est arr\xEAt\xE9 : D le d\xE9marre.",
|
|
2491
|
+
offline: "Machine hors ligne.",
|
|
2492
|
+
outdated: "Le daemon Ledge de cette machine ne conna\xEEt pas OpenRig : mettez-le \xE0 jour.",
|
|
2493
|
+
loading: "Lecture d\u2019OpenRig\u2026",
|
|
2494
|
+
version: (v) => `OpenRig ${v}`,
|
|
2495
|
+
confirmTitle: "Confirmer",
|
|
2496
|
+
confirm: (what) => `${what} ?`,
|
|
2497
|
+
what: {
|
|
2498
|
+
"daemon.stop": "Arr\xEAter le daemon OpenRig",
|
|
2499
|
+
"daemon.restart": "Red\xE9marrer le daemon OpenRig",
|
|
2500
|
+
"kernel.stop": "Arr\xEAter le kernel",
|
|
2501
|
+
"kernel.restart": "Red\xE9marrer le kernel",
|
|
2502
|
+
"rig.stop": (rig) => `Arr\xEAter le rig \xAB ${rig} \xBB`,
|
|
2503
|
+
"rig.restart": (rig) => `Red\xE9marrer le rig \xAB ${rig} \xBB`
|
|
2504
|
+
},
|
|
2505
|
+
busy: (names, n) => n ? `${n} ${plural(n, "agent au travail s\u2019arr\xEAte", "agents au travail s\u2019arr\xEAtent")} : ${names}.` : "Aucun agent au travail.",
|
|
2506
|
+
yes: "confirmer",
|
|
2507
|
+
no: "annuler",
|
|
2508
|
+
running: (cmd) => `en cours : ${cmd}`,
|
|
2509
|
+
done: (cmd) => `fait : ${cmd}`,
|
|
2510
|
+
failed: (why) => `\xE9chec : ${why}`,
|
|
2511
|
+
why: { busy: "une autre action OpenRig est en cours sur cette machine", not_installed: "OpenRig n\u2019est pas install\xE9", offline: "machine hors ligne", outdated: "daemon Ledge trop ancien" }
|
|
2512
|
+
},
|
|
2513
|
+
rigLaunch: {
|
|
2514
|
+
title: "Lancer un rig",
|
|
2515
|
+
launchKey: "lancer un rig",
|
|
2516
|
+
count: "nombre de si\xE8ges",
|
|
2517
|
+
permissions: "4 \xB7 Permissions",
|
|
2518
|
+
policyKey: "permissions",
|
|
2519
|
+
policyOf: { auto: "Auto", standard: "Standard", open: "Ouvert", yolo: "YOLO", locked: "Verrouill\xE9" },
|
|
2520
|
+
specPolicy: (p) => `celle de la spec (${p})`,
|
|
2521
|
+
noSpecPolicy: "aucune",
|
|
2522
|
+
asRig: "comme le rig",
|
|
2523
|
+
policyHint: {
|
|
2524
|
+
none: "sans politique : Claude en acceptEdits, Codex en workspace-write",
|
|
2525
|
+
auto: "Claude d\xE9cide seul (mode auto) ; Codex garde la posture par d\xE9faut",
|
|
2526
|
+
standard: "tout passe sauf PR, publication, fusion, force push et destructif (demande une personne) ; r\xE8gles appliqu\xE9es une fois traduites dans les r\xE9glages du harnais",
|
|
2527
|
+
open: "tout passe sauf le destructif ; r\xE8gles appliqu\xE9es une fois traduites dans les r\xE9glages du harnais",
|
|
2528
|
+
yolo: "aucune demande : Claude --dangerously-skip-permissions, Codex danger-full-access",
|
|
2529
|
+
locked: "seuls la cha\xEEne d\u2019outils et rig up/down passent ; r\xE8gles appliqu\xE9es une fois traduites dans les r\xE9glages du harnais"
|
|
2530
|
+
},
|
|
2531
|
+
nonInterruptive: "accepter les avertissements de premier lancement (--non-interruptive)",
|
|
2532
|
+
spec: "1 \xB7 Spec de d\xE9part",
|
|
2533
|
+
where: "2 \xB7 O\xF9",
|
|
2534
|
+
roles: "3 \xB7 Si\xE8ges par r\xF4le",
|
|
2535
|
+
delegation: "5 \xB7 Qui d\xE9l\xE8gue \xE0 qui",
|
|
2536
|
+
preview: "Aper\xE7u \xB7 rig.yaml",
|
|
2537
|
+
specHint: "Le mod\xE8le de rig : ses pods, ses r\xF4les, les liens entre eux.",
|
|
2538
|
+
source: { user: "mes specs", builtin: "OpenRig" },
|
|
2539
|
+
seatsOf: (n) => `${n} ${plural(n, "si\xE8ge", "si\xE8ges")}`,
|
|
2540
|
+
folder: "Dossier",
|
|
2541
|
+
name: "Nom",
|
|
2542
|
+
folderHint: "un dossier de cette machine, ~ accept\xE9",
|
|
2543
|
+
projectFolder: (p) => `projet ${p}`,
|
|
2544
|
+
model: "mod\xE8le",
|
|
2545
|
+
defaultModel: "par d\xE9faut",
|
|
2546
|
+
modelKey: "mod\xE8le",
|
|
2547
|
+
rolesHint: "Un compteur \xE0 3 donne build, build-2, build-3, identiques au premier.",
|
|
2548
|
+
pairs: "par paires",
|
|
2549
|
+
all: "chaque si\xE8ge \u2192 tous",
|
|
2550
|
+
pairsHint: "build-2 \u2192 review-2",
|
|
2551
|
+
allHint: "chaque build \u2192 tous les review",
|
|
2552
|
+
save: "enregistrer dans mes specs",
|
|
2553
|
+
notScaled: "un si\xE8ge par r\xF4le : rien \xE0 d\xE9l\xE9guer de plus",
|
|
2554
|
+
loading: "Lecture des specs\u2026",
|
|
2555
|
+
noSpecs: "Aucune spec sur cette machine.",
|
|
2556
|
+
daemonStopped: "D\xE9marrez le daemon OpenRig d\u2019abord (D sur l\u2019\xE9cran OpenRig).",
|
|
2557
|
+
noCheck: "p v\xE9rifie le lancement (rig up --plan), sans rien d\xE9marrer.",
|
|
2558
|
+
checking: "V\xE9rification\u2026",
|
|
2559
|
+
launching: "Lancement\u2026",
|
|
2560
|
+
passes: (seats) => `\u2713 le plan passe \xB7 ${seats} ${plural(seats, "si\xE8ge", "si\xE8ges")}`,
|
|
2561
|
+
planStatus: (s) => `plan : ${s}`,
|
|
2562
|
+
warning: (text5, seats) => seats ? `${text5} (${seats})` : text5,
|
|
2563
|
+
launched: (name, n) => `Rig \xAB ${name} \xBB lanc\xE9 \xB7 ${n} ${plural(n, "si\xE8ge", "si\xE8ges")}.`,
|
|
2564
|
+
check: "v\xE9rifier (--plan)",
|
|
2565
|
+
launch: (n) => `lancer ${n} ${plural(n, "si\xE8ge", "si\xE8ges")}`,
|
|
2566
|
+
missing: { spec: "Choisissez une spec.", cwd: "Indiquez le dossier de travail.", name: "Le nom du rig : lettres, chiffres, . _ - (pas de - au d\xE9but).", seats: "Au moins un si\xE8ge." },
|
|
2567
|
+
why: {
|
|
2568
|
+
busy: "Une autre action OpenRig est en cours sur cette machine.",
|
|
2569
|
+
cwd_missing: "Ce dossier n\u2019existe pas sur la machine.",
|
|
2570
|
+
spec_not_found: "Cette spec n\u2019est plus dans la biblioth\xE8que.",
|
|
2571
|
+
daemon_stopped: "D\xE9marrez le daemon OpenRig d\u2019abord (D sur l\u2019\xE9cran OpenRig).",
|
|
2572
|
+
not_installed: "OpenRig n\u2019est pas install\xE9 sur cette machine.",
|
|
2573
|
+
offline: "Machine hors ligne.",
|
|
2574
|
+
outdated: "Le daemon Ledge de cette machine ne sait pas lancer de rig : mettez-le \xE0 jour."
|
|
2575
|
+
}
|
|
2576
|
+
},
|
|
2577
|
+
rigSeats: {
|
|
2578
|
+
title: (rig, machine) => `Si\xE8ges \xB7 ${rig} \xB7 ${machine}`,
|
|
2579
|
+
key: "si\xE8ges",
|
|
2580
|
+
stays: (now2) => `Le rig reste en marche. Aujourd\u2019hui : ${now2}.`,
|
|
2581
|
+
role: "r\xF4le",
|
|
2582
|
+
count: "nombre",
|
|
2583
|
+
delegationKey: "d\xE9l\xE9gation",
|
|
2584
|
+
apply: "appliquer",
|
|
2585
|
+
cancel: "annuler",
|
|
2586
|
+
pairs: "d\xE9l\xE9gation par paires",
|
|
2587
|
+
all: "chaque ajout \u2192 tous",
|
|
2588
|
+
linksPairs: "liens ajout\xE9s par paires",
|
|
2589
|
+
linksAll: "liens ajout\xE9s \xE0 tous",
|
|
2590
|
+
nothing: "Changez un nombre : - +",
|
|
2591
|
+
notRunning: "Seul un rig en marche change de si\xE8ges.",
|
|
2592
|
+
busy: (seat) => `${seat} travaille : son travail en cours s\u2019arr\xEAte.`,
|
|
2593
|
+
applying: "en cours\u2026",
|
|
2594
|
+
done: (added, removed, links) => `+${added} \u2212${removed} si\xE8ges${links !== void 0 ? `, ${links} ${plural(links, "lien", "liens")}` : ""}`,
|
|
2595
|
+
linksUnsupported: "cet OpenRig ne sait pas lier des si\xE8ges ajout\xE9s \xE0 un rig en marche (avant 0.7)",
|
|
2596
|
+
why: {
|
|
2597
|
+
rig_not_running: "Le rig n\u2019est plus en marche.",
|
|
2598
|
+
rig_root_unknown: "Impossible de copier un si\xE8ge : les agents du rig sont introuvables.",
|
|
2599
|
+
busy: "Une autre action OpenRig est en cours sur cette machine.",
|
|
2600
|
+
not_installed: "OpenRig n\u2019est pas install\xE9 sur cette machine.",
|
|
2601
|
+
offline: "Machine hors ligne.",
|
|
2602
|
+
outdated: "Le daemon Ledge de cette machine ne sait pas changer les si\xE8ges d\u2019un rig : mettez-le \xE0 jour."
|
|
2603
|
+
}
|
|
2604
|
+
},
|
|
2615
2605
|
small: {
|
|
2616
2606
|
tooSmall: (w, h) => `Fen\xEAtre trop petite : ${w}\xD7${h}`,
|
|
2617
2607
|
atLeast: (w, h) => `il faut au moins ${w}\xD7${h}`,
|
|
2618
|
-
waits: (name,
|
|
2608
|
+
waits: (name, question2) => question2 ? `${name} a une question` : `${name} attend ton accord`,
|
|
2619
2609
|
kept: "brouillon gard\xE9"
|
|
2620
2610
|
},
|
|
2621
2611
|
cli: { notTty: "ledge tui: needs a terminal (stdin and stdout must be a TTY)", movedToTab: "ledge tui s\u2019ouvre dans l\u2019onglet Ledge.", loadingProfile: "Windows Terminal charge le profil Ledge\u2026" }
|
|
@@ -2627,7 +2617,7 @@ var en3 = {
|
|
|
2627
2617
|
lang: { fr: "Fran\xE7ais", en: "English" },
|
|
2628
2618
|
state: { approval: "Needs you", question: "A question", starting: "Starting", idle: "Available", working: "Working", done: "Finished", error: "Error", readonly: "Read-only" },
|
|
2629
2619
|
time: { now: "just now", decimal: ".", s: (n) => `${n}s`, min: (n) => `${n} min`, h: (n) => `${n} h`, d: (n) => `${n} d` },
|
|
2630
|
-
tabs: { overview: "Overview", session: "Session", ask: "Ask Ledge", launch: "New session", settings: "Settings",
|
|
2620
|
+
tabs: { overview: "Overview", session: "Session", ask: "Ask Ledge", launch: "New session", settings: "Settings", openrig: "OpenRig" },
|
|
2631
2621
|
bar: {
|
|
2632
2622
|
sessions: (n) => `${n} ${plural2(n, "session", "sessions")}`,
|
|
2633
2623
|
machines: (n) => `${n} ${plural2(n, "machine", "machines")}`,
|
|
@@ -2669,11 +2659,6 @@ var en3 = {
|
|
|
2669
2659
|
scroll: "scroll",
|
|
2670
2660
|
space: "space",
|
|
2671
2661
|
redraw: "another name",
|
|
2672
|
-
save: "save the team",
|
|
2673
|
-
tasks: "team tasks",
|
|
2674
|
-
join: "join a team",
|
|
2675
|
-
resume: "resume the team",
|
|
2676
|
-
teamMode: "session or team",
|
|
2677
2662
|
handover: "hand over",
|
|
2678
2663
|
decide: "answer the decision",
|
|
2679
2664
|
sendAnswer: "send the answer",
|
|
@@ -2701,16 +2686,12 @@ var en3 = {
|
|
|
2701
2686
|
deny: "deny",
|
|
2702
2687
|
ignore: "ignore",
|
|
2703
2688
|
review: "review",
|
|
2704
|
-
openSession: (name) => `open ${name}
|
|
2705
|
-
rolesTemplates: "roles / templates",
|
|
2706
|
-
folder: "folder",
|
|
2707
|
-
launchRole: "launch with this role",
|
|
2708
|
-
launchTeam: "launch this team",
|
|
2709
|
-
openFile: "open the file",
|
|
2710
|
-
ignored: "ignored",
|
|
2711
|
-
reread: "read again"
|
|
2689
|
+
openSession: (name) => `open ${name}`
|
|
2712
2690
|
},
|
|
2713
2691
|
overview: {
|
|
2692
|
+
rigsGroup: "RIGS",
|
|
2693
|
+
kernelGroup: "KERNEL",
|
|
2694
|
+
rigSeat: (rig, role) => `rig ${rig} \xB7 ${role}`,
|
|
2714
2695
|
yours: (n) => `Yours \xB7 ${n}`,
|
|
2715
2696
|
projects: "Projects",
|
|
2716
2697
|
exchanges: "Messages",
|
|
@@ -2731,11 +2712,6 @@ var en3 = {
|
|
|
2731
2712
|
deny: "Deny",
|
|
2732
2713
|
always: "Always",
|
|
2733
2714
|
denyWithNote: "Deny with a note",
|
|
2734
|
-
common: "common table",
|
|
2735
|
-
teamLine: (done, given) => `team \xB7 ${done}/${given}`,
|
|
2736
|
-
resting: "resting \xB7 R to resume",
|
|
2737
|
-
tasks: (team) => `Tasks \xB7 ${team}`,
|
|
2738
|
-
noTask: "No task.",
|
|
2739
2715
|
ledge: "Ledge",
|
|
2740
2716
|
near: (name, pct) => `${name} \xB7 ctx ${pct} % \xB7 H hand over`,
|
|
2741
2717
|
reliefFailed: (name, why) => `The relief of ${name} failed: ${why}`,
|
|
@@ -2747,10 +2723,7 @@ var en3 = {
|
|
|
2747
2723
|
decision: (giver, title2) => `${giver} asks you: ${title2}`,
|
|
2748
2724
|
decisionTitle: (giver, title2) => `Answer ${giver} \xB7 ${title2}`,
|
|
2749
2725
|
decisionHint: "Your answer, as the session will read it\u2026",
|
|
2750
|
-
confirmAnswer: (giver) => `Send to ${giver}? An answer cannot be taken back
|
|
2751
|
-
joinWhich: (name) => `${name} joins which team? (\u2191\u2193 \u21B5, esc)`,
|
|
2752
|
-
noTeamHere: "No team in this project.",
|
|
2753
|
-
notInTeam: "This session is in no team."
|
|
2726
|
+
confirmAnswer: (giver) => `Send to ${giver}? An answer cannot be taken back`
|
|
2754
2727
|
},
|
|
2755
2728
|
session: {
|
|
2756
2729
|
you: "You",
|
|
@@ -2808,19 +2781,8 @@ var en3 = {
|
|
|
2808
2781
|
offline: "The local daemon is offline: the question will wait.",
|
|
2809
2782
|
steps: { sessions: "the sessions", pane: (n) => `${n}'s terminal`, reply: (n) => `${n}'s reply`, git: (n) => `${n}'s git state`, repo: (p) => p },
|
|
2810
2783
|
operator: (s, m) => `Ledge \xB7 Operator \xB7 sees ${s} ${plural2(s, "session", "sessions")}, ${m} ${plural2(m, "machine", "machines")}`,
|
|
2811
|
-
teamCard: (name) => `Team \xB7 ${name}`,
|
|
2812
2784
|
taskCard: "Tasks to give",
|
|
2813
|
-
launchTeam: "Launch the team",
|
|
2814
|
-
save: "Save",
|
|
2815
|
-
saved: "saved",
|
|
2816
|
-
seats: "Seats",
|
|
2817
|
-
table: "Table",
|
|
2818
|
-
newTable: (project) => `new table in the ${project} room`,
|
|
2819
|
-
autonomy: { ask: "asks", edits: "edits without asking", auto: "autonomous" },
|
|
2820
|
-
autoWarning: (roles) => `${roles} will work without asking.`,
|
|
2821
|
-
teamLaunched: (at) => `\u2713 Team launched at ${at}`,
|
|
2822
2785
|
give: "Give",
|
|
2823
|
-
waitTeam: "active once the team is launched",
|
|
2824
2786
|
given: (owner, id, state2) => `\u2713 Given to ${owner} \xB7 ${id} \xB7 ${state2}`,
|
|
2825
2787
|
taskState: { open: "to take", taken: "taken", done: "done", refused: "refused", dropped: "dropped" },
|
|
2826
2788
|
placeholder: "A question for Ledge\u2026",
|
|
@@ -2876,66 +2838,7 @@ var en3 = {
|
|
|
2876
2838
|
thenAttach: "then a to attach to its terminal",
|
|
2877
2839
|
missing: { prompt: "Write an instruction.", machine: "No machine online.", repos: "Pick a repository or a folder." },
|
|
2878
2840
|
launching: "Launching\u2026",
|
|
2879
|
-
launched: (name) => `\u2713 ${name} is started
|
|
2880
|
-
teamTitle: "New team",
|
|
2881
|
-
mode: "Mode",
|
|
2882
|
-
session: "session",
|
|
2883
|
-
team: "team",
|
|
2884
|
-
template: "Template",
|
|
2885
|
-
custom: "seats chosen one by one",
|
|
2886
|
-
seats: "Seats",
|
|
2887
|
-
teamName: "Name",
|
|
2888
|
-
noRole: "no role: write ~/.ledge/roles/<id>.md",
|
|
2889
|
-
loadingRoles: "reading the roles\u2026",
|
|
2890
|
-
teamPreview: (team, project) => `Team ${team} will sit at a new table in the ${project} room.`,
|
|
2891
|
-
teamLaunched: (name) => `\u2713 Team ${name} launched`,
|
|
2892
|
-
teamFailed: (why) => `Team not launched: ${why}`,
|
|
2893
|
-
noSeat: "Choose at least one seat."
|
|
2894
|
-
},
|
|
2895
|
-
catalog: {
|
|
2896
|
-
roles: "roles",
|
|
2897
|
-
templates: "templates",
|
|
2898
|
-
homeOnly: "Personal only",
|
|
2899
|
-
repoRoles: "repository \xB7 .ledge/roles",
|
|
2900
|
-
homeRoles: "personal \xB7 ~/.ledge/roles",
|
|
2901
|
-
repoTeams: "repository \xB7 .ledge/teams",
|
|
2902
|
-
homeTeams: "personal \xB7 ~/.ledge/teams",
|
|
2903
|
-
repo: "repository",
|
|
2904
|
-
home: "personal",
|
|
2905
|
-
tool: "agent",
|
|
2906
|
-
model: "model",
|
|
2907
|
-
effort: "effort",
|
|
2908
|
-
autonomy: "autonomy",
|
|
2909
|
-
file: "file",
|
|
2910
|
-
usedIn: "in",
|
|
2911
|
-
heldBy: "held by",
|
|
2912
|
-
teams: "teams",
|
|
2913
|
-
replaces: (path2) => `replaces ${path2}`,
|
|
2914
|
-
toolDefault: "the agent\u2019s default",
|
|
2915
|
-
noTemplate: "no template",
|
|
2916
|
-
nobody: "nobody",
|
|
2917
|
-
noTeam: "none",
|
|
2918
|
-
active: "active",
|
|
2919
|
-
resting: "resting",
|
|
2920
|
-
instruction: (n, max) => `Instruction \xB7 ${n}/${max}`,
|
|
2921
|
-
noInstruction: "No instruction.",
|
|
2922
|
-
seats: (n) => `${n} ${plural2(n, "seat", "seats")}`,
|
|
2923
|
-
autonomyShort: { ask: "asks", edits: "edits", auto: "auto" },
|
|
2924
|
-
ignored: (n) => `\u26A0 ${n} ${plural2(n, "file", "files")} ignored`,
|
|
2925
|
-
see: "see",
|
|
2926
|
-
problems: "Ignored files",
|
|
2927
|
-
noProblem: "No ignored file.",
|
|
2928
|
-
loading: "reading the roles\u2026",
|
|
2929
|
-
noAnswer: "The daemon did not answer.",
|
|
2930
|
-
offline: (m) => `${m} is offline.`,
|
|
2931
|
-
outdated: (m) => `${m}\u2019s daemon is too old for the catalog.`,
|
|
2932
|
-
onMachine: (m) => `on ${m}`,
|
|
2933
|
-
roleChecking: (id) => `@${id}: reading the role in this folder\u2026`,
|
|
2934
|
-
roleReadIn: (cwd) => `the one in ${cwd}`,
|
|
2935
|
-
roleElsewhere: (id, cwd) => `@${id} is only read in ${cwd}: launched without a role`,
|
|
2936
|
-
noRole: "No role here: write .ledge/roles/<id>.md",
|
|
2937
|
-
noTemplateHere: "No template here: write .ledge/teams/<id>.yaml",
|
|
2938
|
-
role: "Role"
|
|
2841
|
+
launched: (name) => `\u2713 ${name} is started`
|
|
2939
2842
|
},
|
|
2940
2843
|
settings: { title: "Settings", language: "Language", theme: "Theme", themes: { auto: "Auto", dark: "Dark", light: "Light" }, themeAuto: (tone2) => `Auto (${tone2} background)`, context: "Max context", contextHint: "past it: hand over", contextUnknown: "update the daemon", contextSaved: (pct) => `Max context: ${pct} %`, saved: "Setting saved.", saveFailed: (m) => `Setting applied, but not saved: ${m}` },
|
|
2941
2844
|
help: {
|
|
@@ -2946,8 +2849,9 @@ var en3 = {
|
|
|
2946
2849
|
ask: "Ask Ledge",
|
|
2947
2850
|
launch: "New session",
|
|
2948
2851
|
settings: "Settings",
|
|
2852
|
+
openrig: "OpenRig",
|
|
2853
|
+
rigLaunch: "Launch a rig",
|
|
2949
2854
|
screens: "switch screen",
|
|
2950
|
-
teams: "Teams",
|
|
2951
2855
|
field: "Typing",
|
|
2952
2856
|
wordBefore: "delete the word before",
|
|
2953
2857
|
more: (above, below) => [above ? `\u2191 ${above} above` : "", below ? `\u2193 ${below} below` : ""].filter(Boolean).join(" \xB7 ")
|
|
@@ -2986,9 +2890,6 @@ var en3 = {
|
|
|
2986
2890
|
noTerminal: (n) => `No terminal for ${n}.`,
|
|
2987
2891
|
attachFailed: (code3) => `tmux stopped with code ${code3}.`,
|
|
2988
2892
|
modelSwitch: "This daemon cannot change a running session\u2019s model.",
|
|
2989
|
-
joined: (n, team) => `${n} joins ${team}.`,
|
|
2990
|
-
resumed: (team) => `Asked to resume team ${team}.`,
|
|
2991
|
-
saved: (path2) => `Team saved: ${path2}`,
|
|
2992
2893
|
draftKept: "Draft kept: r to pick it up.",
|
|
2993
2894
|
draftQuit: "Draft in progress: ctrl+c again to quit anyway (it will be lost).",
|
|
2994
2895
|
exited: (cmd, code3) => `${cmd} exited with code ${code3}.`
|
|
@@ -3005,10 +2906,154 @@ var en3 = {
|
|
|
3005
2906
|
question: (n, text5) => `${n} has a question: ${text5}`,
|
|
3006
2907
|
title: (n) => n > 0 ? `ledge \xB7 ${n} waiting` : "ledge"
|
|
3007
2908
|
},
|
|
2909
|
+
openrig: {
|
|
2910
|
+
operatorKey: "operator",
|
|
2911
|
+
operatorHint: "O: talk to it",
|
|
2912
|
+
operatorNotYet: "Ledge does not follow the operator\u2019s session yet: try again in a few seconds.",
|
|
2913
|
+
activity: (a) => ({ running: "working", idle: "available", unknown: "\u2014" })[a] ?? a,
|
|
2914
|
+
title: "OpenRig",
|
|
2915
|
+
daemon: "Daemon",
|
|
2916
|
+
kernel: "Kernel",
|
|
2917
|
+
rigs: "Rigs",
|
|
2918
|
+
machine: "machine",
|
|
2919
|
+
toggle: "start/stop",
|
|
2920
|
+
restart: "restart",
|
|
2921
|
+
unfold: "unfold",
|
|
2922
|
+
daemonKey: "daemon",
|
|
2923
|
+
kernelKey: "kernel",
|
|
2924
|
+
daemonState: { running: "running", stopped: "stopped", stale: "stopped uncleanly", unknown: "unknown" },
|
|
2925
|
+
kernelState: { ready: "ready", starting: "starting", stopped: "stopped", skipped: "no kernel", absent: "absent", unknown: "unknown" },
|
|
2926
|
+
look: { running: "running", starting: "starting", attention: "needs a look", stopped: "stopped" },
|
|
2927
|
+
daemonMeta: (port, pid) => [port ? `127.0.0.1:${port}` : "", pid ? `pid ${pid}` : ""].filter(Boolean).join(" \xB7 "),
|
|
2928
|
+
restoreHint: "\u21BB on start: rigs brought back",
|
|
2929
|
+
kernelHint: "the operator that helps start a rig",
|
|
2930
|
+
seats: (running, total) => `${running}/${total}`,
|
|
2931
|
+
attention: (n) => `${n} ${plural2(n, "seat needs", "seats need")} attention`,
|
|
2932
|
+
since: (uptime) => `up ${uptime}`,
|
|
2933
|
+
snapshot: (s) => `snapshot ${s}`,
|
|
2934
|
+
work: (n) => n ? `${n} ${plural2(n, "task", "tasks")}` : "",
|
|
2935
|
+
stoppedOnPurpose: "stopped on purpose",
|
|
2936
|
+
noRigs: "No rig on this machine.",
|
|
2937
|
+
notInstalled: "OpenRig is not installed on this machine (no rig command).",
|
|
2938
|
+
stoppedDaemon: "The OpenRig daemon is stopped: D starts it.",
|
|
2939
|
+
offline: "Machine offline.",
|
|
2940
|
+
outdated: "This machine\u2019s Ledge daemon does not know OpenRig: update it.",
|
|
2941
|
+
loading: "Reading OpenRig\u2026",
|
|
2942
|
+
version: (v) => `OpenRig ${v}`,
|
|
2943
|
+
confirmTitle: "Confirm",
|
|
2944
|
+
confirm: (what) => `${what}?`,
|
|
2945
|
+
what: {
|
|
2946
|
+
"daemon.stop": "Stop the OpenRig daemon",
|
|
2947
|
+
"daemon.restart": "Restart the OpenRig daemon",
|
|
2948
|
+
"kernel.stop": "Stop the kernel",
|
|
2949
|
+
"kernel.restart": "Restart the kernel",
|
|
2950
|
+
"rig.stop": (rig) => `Stop the rig \u201C${rig}\u201D`,
|
|
2951
|
+
"rig.restart": (rig) => `Restart the rig \u201C${rig}\u201D`
|
|
2952
|
+
},
|
|
2953
|
+
busy: (names, n) => n ? `${n} working ${plural2(n, "agent stops", "agents stop")}: ${names}.` : "No agent at work.",
|
|
2954
|
+
yes: "confirm",
|
|
2955
|
+
no: "cancel",
|
|
2956
|
+
running: (cmd) => `running: ${cmd}`,
|
|
2957
|
+
done: (cmd) => `done: ${cmd}`,
|
|
2958
|
+
failed: (why) => `failed: ${why}`,
|
|
2959
|
+
why: { busy: "another OpenRig action runs on this machine", not_installed: "OpenRig is not installed", offline: "machine offline", outdated: "Ledge daemon too old" }
|
|
2960
|
+
},
|
|
2961
|
+
rigLaunch: {
|
|
2962
|
+
title: "Launch a rig",
|
|
2963
|
+
launchKey: "launch a rig",
|
|
2964
|
+
count: "number of seats",
|
|
2965
|
+
permissions: "4 \xB7 Permissions",
|
|
2966
|
+
policyKey: "permissions",
|
|
2967
|
+
policyOf: { auto: "Auto", standard: "Standard", open: "Open", yolo: "YOLO", locked: "Locked" },
|
|
2968
|
+
specPolicy: (p) => `the spec\u2019s (${p})`,
|
|
2969
|
+
noSpecPolicy: "none",
|
|
2970
|
+
asRig: "as the rig",
|
|
2971
|
+
policyHint: {
|
|
2972
|
+
none: "no policy: Claude in acceptEdits, Codex in workspace-write",
|
|
2973
|
+
auto: "Claude decides on its own (auto mode); Codex keeps the default posture",
|
|
2974
|
+
standard: "everything passes but PRs, publishing, merging, force push and destructive (asks a person); rules applied once translated into the harness settings",
|
|
2975
|
+
open: "everything passes but destructive; rules applied once translated into the harness settings",
|
|
2976
|
+
yolo: "no prompt: Claude --dangerously-skip-permissions, Codex danger-full-access",
|
|
2977
|
+
locked: "only the toolchain and rig up/down pass; rules applied once translated into the harness settings"
|
|
2978
|
+
},
|
|
2979
|
+
nonInterruptive: "accept the first-launch warnings (--non-interruptive)",
|
|
2980
|
+
spec: "1 \xB7 Starting spec",
|
|
2981
|
+
where: "2 \xB7 Where",
|
|
2982
|
+
roles: "3 \xB7 Seats per role",
|
|
2983
|
+
delegation: "5 \xB7 Who delegates to whom",
|
|
2984
|
+
preview: "Preview \xB7 rig.yaml",
|
|
2985
|
+
specHint: "The rig\u2019s model: its pods, its roles, the links between them.",
|
|
2986
|
+
source: { user: "my specs", builtin: "OpenRig" },
|
|
2987
|
+
seatsOf: (n) => `${n} ${plural2(n, "seat", "seats")}`,
|
|
2988
|
+
folder: "Folder",
|
|
2989
|
+
name: "Name",
|
|
2990
|
+
folderHint: "a folder of this machine, ~ accepted",
|
|
2991
|
+
projectFolder: (p) => `project ${p}`,
|
|
2992
|
+
model: "model",
|
|
2993
|
+
defaultModel: "default",
|
|
2994
|
+
modelKey: "model",
|
|
2995
|
+
rolesHint: "A counter at 3 gives build, build-2, build-3, the same as the first.",
|
|
2996
|
+
pairs: "in pairs",
|
|
2997
|
+
all: "each seat \u2192 all",
|
|
2998
|
+
pairsHint: "build-2 \u2192 review-2",
|
|
2999
|
+
allHint: "each build \u2192 every review",
|
|
3000
|
+
save: "save in my specs",
|
|
3001
|
+
notScaled: "one seat per role: nothing more to delegate",
|
|
3002
|
+
loading: "Reading the specs\u2026",
|
|
3003
|
+
noSpecs: "No spec on this machine.",
|
|
3004
|
+
daemonStopped: "Start the OpenRig daemon first (D on the OpenRig screen).",
|
|
3005
|
+
noCheck: "p checks the launch (rig up --plan) without starting anything.",
|
|
3006
|
+
checking: "Checking\u2026",
|
|
3007
|
+
launching: "Launching\u2026",
|
|
3008
|
+
passes: (seats) => `\u2713 the plan passes \xB7 ${seats} ${plural2(seats, "seat", "seats")}`,
|
|
3009
|
+
planStatus: (s) => `plan: ${s}`,
|
|
3010
|
+
warning: (text5, seats) => seats ? `${text5} (${seats})` : text5,
|
|
3011
|
+
launched: (name, n) => `Rig \u201C${name}\u201D launched \xB7 ${n} ${plural2(n, "seat", "seats")}.`,
|
|
3012
|
+
check: "check (--plan)",
|
|
3013
|
+
launch: (n) => `launch ${n} ${plural2(n, "seat", "seats")}`,
|
|
3014
|
+
missing: { spec: "Pick a spec.", cwd: "Give the working folder.", name: "The rig\u2019s name: letters, digits, . _ - (no leading -).", seats: "At least one seat." },
|
|
3015
|
+
why: {
|
|
3016
|
+
busy: "Another OpenRig action runs on this machine.",
|
|
3017
|
+
cwd_missing: "This folder does not exist on the machine.",
|
|
3018
|
+
spec_not_found: "This spec is no longer in the library.",
|
|
3019
|
+
daemon_stopped: "Start the OpenRig daemon first (D on the OpenRig screen).",
|
|
3020
|
+
not_installed: "OpenRig is not installed on this machine.",
|
|
3021
|
+
offline: "Machine offline.",
|
|
3022
|
+
outdated: "This machine\u2019s Ledge daemon cannot launch a rig: update it."
|
|
3023
|
+
}
|
|
3024
|
+
},
|
|
3025
|
+
rigSeats: {
|
|
3026
|
+
title: (rig, machine) => `Seats \xB7 ${rig} \xB7 ${machine}`,
|
|
3027
|
+
key: "seats",
|
|
3028
|
+
stays: (now2) => `The rig keeps running. Now: ${now2}.`,
|
|
3029
|
+
role: "role",
|
|
3030
|
+
count: "number",
|
|
3031
|
+
delegationKey: "delegation",
|
|
3032
|
+
apply: "apply",
|
|
3033
|
+
cancel: "cancel",
|
|
3034
|
+
pairs: "delegation in pairs",
|
|
3035
|
+
all: "each added \u2192 all",
|
|
3036
|
+
linksPairs: "links added in pairs",
|
|
3037
|
+
linksAll: "links added to all",
|
|
3038
|
+
nothing: "Change a number: - +",
|
|
3039
|
+
notRunning: "Only a running rig changes seats.",
|
|
3040
|
+
busy: (seat) => `${seat} is working: its work in progress stops.`,
|
|
3041
|
+
applying: "applying\u2026",
|
|
3042
|
+
done: (added, removed, links) => `+${added} \u2212${removed} seats${links !== void 0 ? `, ${links} ${plural2(links, "link", "links")}` : ""}`,
|
|
3043
|
+
linksUnsupported: "this OpenRig cannot link seats added to a running rig (before 0.7)",
|
|
3044
|
+
why: {
|
|
3045
|
+
rig_not_running: "The rig is no longer running.",
|
|
3046
|
+
rig_root_unknown: "Cannot copy a seat: the rig\u2019s agents cannot be found.",
|
|
3047
|
+
busy: "Another OpenRig action runs on this machine.",
|
|
3048
|
+
not_installed: "OpenRig is not installed on this machine.",
|
|
3049
|
+
offline: "Machine offline.",
|
|
3050
|
+
outdated: "This machine\u2019s Ledge daemon cannot change a rig\u2019s seats: update it."
|
|
3051
|
+
}
|
|
3052
|
+
},
|
|
3008
3053
|
small: {
|
|
3009
3054
|
tooSmall: (w, h) => `Window too small: ${w}\xD7${h}`,
|
|
3010
3055
|
atLeast: (w, h) => `needs at least ${w}\xD7${h}`,
|
|
3011
|
-
waits: (name,
|
|
3056
|
+
waits: (name, question2) => question2 ? `${name} has a question` : `${name} waits for your approval`,
|
|
3012
3057
|
kept: "draft kept"
|
|
3013
3058
|
},
|
|
3014
3059
|
cli: { notTty: "ledge tui: needs a terminal (stdin and stdout must be a TTY)", movedToTab: "ledge tui opens in the Ledge tab.", loadingProfile: "Windows Terminal is loading the Ledge profile\u2026" }
|
|
@@ -3027,37 +3072,33 @@ var useI18n = () => useContext2(I18nContext);
|
|
|
3027
3072
|
// src/tui/model/overview.ts
|
|
3028
3073
|
var listed = (sessions) => sessions.filter((s) => s.state !== "exited");
|
|
3029
3074
|
var machineOf = (s) => s.machineId ?? splitId(s.id)?.machine ?? "local";
|
|
3030
|
-
function overview(sessions, projects
|
|
3075
|
+
function overview(sessions, projects) {
|
|
3031
3076
|
const live = listed(sessions);
|
|
3032
3077
|
const yours = live.filter(isPending).sort((a, b2) => a.lastActivityAt.localeCompare(b2.lastActivityAt) || a.id.localeCompare(b2.id));
|
|
3033
3078
|
const nodes = /* @__PURE__ */ new Map();
|
|
3034
3079
|
const known2 = new Map((projects?.projects ?? []).map((p) => [p.id, p]));
|
|
3035
|
-
for (const p of projects?.projects ?? []) nodes.set(`p:${p.id}`, { key: `p:${p.id}`, label: p.name, color: p.color, branches: [], count: 0
|
|
3036
|
-
const
|
|
3037
|
-
for (const team of teams) {
|
|
3038
|
-
if (team.state === "dissolved") continue;
|
|
3039
|
-
const pid = projects ? projectOf({ machineId: team.machine, cwd: team.cwd }, projects) ?? team.project : team.project;
|
|
3040
|
-
const node2 = pid ? nodes.get(`p:${pid}`) : void 0;
|
|
3041
|
-
if (!node2) continue;
|
|
3042
|
-
const mine = tasks.filter((x) => x.team === team.id && x.giver === LEDGE_GIVER);
|
|
3043
|
-
const row2 = { key: `${node2.key}|team:${team.id}`, team, sessions: [], done: mine.filter((x) => x.state === "done").length, given: mine.length };
|
|
3044
|
-
node2.teams.push(row2);
|
|
3045
|
-
rooms.set(team.id, row2);
|
|
3046
|
-
}
|
|
3080
|
+
for (const p of projects?.projects ?? []) nodes.set(`p:${p.id}`, { key: `p:${p.id}`, label: p.name, color: p.color, branches: [], count: 0 });
|
|
3081
|
+
const rigNodes = /* @__PURE__ */ new Map();
|
|
3047
3082
|
for (const s of live) {
|
|
3083
|
+
if (s.rig) {
|
|
3084
|
+
const kind = s.rig.name === "kernel" ? "kernel" : "rig";
|
|
3085
|
+
const key2 = kind === "kernel" ? "g:kernel" : `g:rig:${s.rig.name}`;
|
|
3086
|
+
let node3 = rigNodes.get(key2);
|
|
3087
|
+
if (!node3) {
|
|
3088
|
+
node3 = { key: key2, label: kind === "kernel" ? "Kernel" : s.rig.name, kind, branches: [{ branch: "", sessions: [] }], count: 0 };
|
|
3089
|
+
rigNodes.set(key2, node3);
|
|
3090
|
+
}
|
|
3091
|
+
node3.branches[0].sessions.push(s);
|
|
3092
|
+
node3.count += 1;
|
|
3093
|
+
continue;
|
|
3094
|
+
}
|
|
3048
3095
|
const pid = projects ? projectOf({ machineId: machineOf(s), cwd: s.cwd }, projects) : null;
|
|
3049
3096
|
const key = pid && known2.has(pid) ? `p:${pid}` : `r:${machineOf(s)}:${s.repoPath ?? s.cwd}`;
|
|
3050
3097
|
let node2 = nodes.get(key);
|
|
3051
3098
|
if (!node2) {
|
|
3052
|
-
node2 = { key, label: s.repo ?? s.project, branches: [], count: 0
|
|
3099
|
+
node2 = { key, label: s.repo ?? s.project, branches: [], count: 0 };
|
|
3053
3100
|
nodes.set(key, node2);
|
|
3054
3101
|
}
|
|
3055
|
-
const seat = s.team ? rooms.get(s.team) : void 0;
|
|
3056
|
-
if (seat && node2.teams.includes(seat)) {
|
|
3057
|
-
seat.sessions.push(s);
|
|
3058
|
-
node2.count += 1;
|
|
3059
|
-
continue;
|
|
3060
|
-
}
|
|
3061
3102
|
const branch = s.branch ?? "-";
|
|
3062
3103
|
let row2 = node2.branches.find((b2) => b2.branch === branch);
|
|
3063
3104
|
if (!row2) {
|
|
@@ -3067,8 +3108,9 @@ function overview(sessions, projects, teams = [], tasks = []) {
|
|
|
3067
3108
|
row2.sessions.push(s);
|
|
3068
3109
|
node2.count += 1;
|
|
3069
3110
|
}
|
|
3070
|
-
const
|
|
3071
|
-
const
|
|
3111
|
+
const groups = [...rigNodes.values()].sort((a, b2) => a.kind === b2.kind ? a.label.localeCompare(b2.label) : a.kind === "kernel" ? 1 : -1);
|
|
3112
|
+
const tree2 = [...[...nodes.values()].filter((n) => n.count > 0), ...groups];
|
|
3113
|
+
const order2 = tree2.flatMap((n) => n.branches.flatMap((b2) => b2.sessions.map((s) => s.id)));
|
|
3072
3114
|
return { yours, tree: tree2, order: order2, machines: new Set(live.map(machineOf)).size };
|
|
3073
3115
|
}
|
|
3074
3116
|
var helperCount = (s) => liveHelpers(s).length;
|
|
@@ -3094,13 +3136,13 @@ function exchanges(sessions, max, tasks = [], ledge = "Ledge") {
|
|
|
3094
3136
|
const byId = new Map(sessions.map((s) => [s.id, s]));
|
|
3095
3137
|
const bare = (id) => splitId(id)?.id ?? id;
|
|
3096
3138
|
const find2 = (id) => byId.get(id) ?? sessions.find((x) => bare(x.id) === bare(id));
|
|
3097
|
-
const
|
|
3139
|
+
const nameOf2 = (id, then) => id === LEDGE_GIVER ? ledge : find2(id)?.name ?? then;
|
|
3098
3140
|
return [...sessions.flatMap((s) => {
|
|
3099
3141
|
const m = s.lastMessage;
|
|
3100
3142
|
if (!m) return [];
|
|
3101
3143
|
const peer = m.peer ? find2(m.peer) : void 0;
|
|
3102
3144
|
return [{ at: m.at, from: s.name, to: peer?.name ?? m.to, summary: m.summary, kind: "message" }];
|
|
3103
|
-
}), ...tasks.flatMap((x) => transmissions(x).map((tr) => ({ at: tr.at, from:
|
|
3145
|
+
}), ...tasks.flatMap((x) => transmissions(x).map((tr) => ({ at: tr.at, from: nameOf2(tr.from, tr.fromName), to: nameOf2(tr.to, tr.toName), summary: x.title, kind: "task" })))].sort((a, b2) => b2.at.localeCompare(a.at)).slice(0, max);
|
|
3104
3146
|
}
|
|
3105
3147
|
var nearContext = (sessions, near) => sessions.filter((s) => s.state !== "exited" && !s.archivedAt && (s.handover ? s.handover.state === "failed" : contextNear(s.context, near)));
|
|
3106
3148
|
var closedLedgeTasks = (tasks) => tasks.filter((x) => x.giver === LEDGE_GIVER && taskClosed(x) && !x.seen);
|
|
@@ -3272,9 +3314,9 @@ var stateColors = (p) => ({
|
|
|
3272
3314
|
var STATE_COLOR = stateColors(C);
|
|
3273
3315
|
var current = "dark";
|
|
3274
3316
|
var tone = () => current;
|
|
3275
|
-
function setTone(
|
|
3276
|
-
current =
|
|
3277
|
-
Object.assign(C, PALETTES[
|
|
3317
|
+
function setTone(next3) {
|
|
3318
|
+
current = next3;
|
|
3319
|
+
Object.assign(C, PALETTES[next3]);
|
|
3278
3320
|
Object.assign(STATE_COLOR, stateColors(C));
|
|
3279
3321
|
}
|
|
3280
3322
|
var projectColor = (color2) => color2 ? PROJECT_COLORS[color2] : C.dim;
|
|
@@ -3532,7 +3574,7 @@ function visitParents(tree2, test, visitor, reverse) {
|
|
|
3532
3574
|
check = test;
|
|
3533
3575
|
}
|
|
3534
3576
|
const is2 = convert(check);
|
|
3535
|
-
const
|
|
3577
|
+
const step3 = reverse ? -1 : 1;
|
|
3536
3578
|
factory(tree2, void 0, [])();
|
|
3537
3579
|
function factory(node2, index2, parents) {
|
|
3538
3580
|
const value = (
|
|
@@ -3569,7 +3611,7 @@ function visitParents(tree2, test, visitor, reverse) {
|
|
|
3569
3611
|
node2
|
|
3570
3612
|
);
|
|
3571
3613
|
if (nodeAsParent.children && result[0] !== SKIP) {
|
|
3572
|
-
offset = (reverse ? nodeAsParent.children.length : -1) +
|
|
3614
|
+
offset = (reverse ? nodeAsParent.children.length : -1) + step3;
|
|
3573
3615
|
grandparents = parents.concat(nodeAsParent);
|
|
3574
3616
|
while (offset > -1 && offset < nodeAsParent.children.length) {
|
|
3575
3617
|
const child = nodeAsParent.children[offset];
|
|
@@ -3577,7 +3619,7 @@ function visitParents(tree2, test, visitor, reverse) {
|
|
|
3577
3619
|
if (subresult[0] === EXIT) {
|
|
3578
3620
|
return subresult;
|
|
3579
3621
|
}
|
|
3580
|
-
offset = typeof subresult[1] === "number" ? subresult[1] : offset +
|
|
3622
|
+
offset = typeof subresult[1] === "number" ? subresult[1] : offset + step3;
|
|
3581
3623
|
}
|
|
3582
3624
|
}
|
|
3583
3625
|
}
|
|
@@ -8220,9 +8262,9 @@ function tokenizeAutolink(effects, ok3, nok) {
|
|
|
8220
8262
|
}
|
|
8221
8263
|
function emailValue(code3) {
|
|
8222
8264
|
if ((code3 === 45 || asciiAlphanumeric(code3)) && size++ < 63) {
|
|
8223
|
-
const
|
|
8265
|
+
const next3 = code3 === 45 ? emailValue : emailLabel;
|
|
8224
8266
|
effects.consume(code3);
|
|
8225
|
-
return
|
|
8267
|
+
return next3;
|
|
8226
8268
|
}
|
|
8227
8269
|
return nok(code3);
|
|
8228
8270
|
}
|
|
@@ -11488,11 +11530,11 @@ function tokenizeTable(effects, ok3, nok) {
|
|
|
11488
11530
|
}
|
|
11489
11531
|
}
|
|
11490
11532
|
const tail = index2 > -1 ? self.events[index2][1].type : null;
|
|
11491
|
-
const
|
|
11492
|
-
if (
|
|
11533
|
+
const next3 = tail === "tableHead" || tail === "tableRow" ? bodyRowStart : headRowBefore;
|
|
11534
|
+
if (next3 === bodyRowStart && self.parser.lazy[self.now().line]) {
|
|
11493
11535
|
return nok(code3);
|
|
11494
11536
|
}
|
|
11495
|
-
return
|
|
11537
|
+
return next3(code3);
|
|
11496
11538
|
}
|
|
11497
11539
|
function headRowBefore(code3) {
|
|
11498
11540
|
effects.enter("tableHead");
|
|
@@ -12854,9 +12896,9 @@ function preprocess() {
|
|
|
12854
12896
|
break;
|
|
12855
12897
|
}
|
|
12856
12898
|
case 9: {
|
|
12857
|
-
const
|
|
12899
|
+
const next3 = Math.ceil(column / 4) * 4;
|
|
12858
12900
|
chunks.push(-2);
|
|
12859
|
-
while (column++ <
|
|
12901
|
+
while (column++ < next3) {
|
|
12860
12902
|
chunks.push(-1);
|
|
12861
12903
|
}
|
|
12862
12904
|
break;
|
|
@@ -13730,8 +13772,8 @@ function trough() {
|
|
|
13730
13772
|
if (typeof callback !== "function") {
|
|
13731
13773
|
throw new TypeError("Expected function as last argument, not " + callback);
|
|
13732
13774
|
}
|
|
13733
|
-
|
|
13734
|
-
function
|
|
13775
|
+
next3(null, ...values);
|
|
13776
|
+
function next3(error, ...output) {
|
|
13735
13777
|
const fn = fns[++middlewareIndex];
|
|
13736
13778
|
let index2 = -1;
|
|
13737
13779
|
if (error) {
|
|
@@ -13745,7 +13787,7 @@ function trough() {
|
|
|
13745
13787
|
}
|
|
13746
13788
|
values = output;
|
|
13747
13789
|
if (fn) {
|
|
13748
|
-
wrap(fn,
|
|
13790
|
+
wrap(fn, next3)(...output);
|
|
13749
13791
|
} else {
|
|
13750
13792
|
callback(null, ...output);
|
|
13751
13793
|
}
|
|
@@ -15399,6 +15441,11 @@ function fit(s, n) {
|
|
|
15399
15441
|
return cps.length > n ? `${cps.slice(0, Math.max(0, n - 1)).join("")}\u2026` : s + " ".repeat(n - cps.length);
|
|
15400
15442
|
}
|
|
15401
15443
|
|
|
15444
|
+
// src/tui/model/rigSeat.ts
|
|
15445
|
+
var rigTag = (s) => s.rig ? `[${s.rig.name}] ` : "";
|
|
15446
|
+
var rigRole = (s) => s.rig ? s.rig.role ?? s.rig.seat : "";
|
|
15447
|
+
var seatSecond = (s, rest) => s.rig ? [rigRole(s), rest].filter(Boolean).join(" \xB7 ") : rest;
|
|
15448
|
+
|
|
15402
15449
|
// src/tui/ui/now.ts
|
|
15403
15450
|
import { useSyncExternalStore as useSyncExternalStore4 } from "react";
|
|
15404
15451
|
var listeners = /* @__PURE__ */ new Set();
|
|
@@ -15532,10 +15579,10 @@ function fieldLines(text5, cursor, width, o) {
|
|
|
15532
15579
|
const at = cursor !== null && cursor >= r.a && cursor < r.b ? cursor : -1;
|
|
15533
15580
|
if (at < 0) line.push({ text: text5.slice(r.a, r.b), color: o.color });
|
|
15534
15581
|
else {
|
|
15535
|
-
const
|
|
15582
|
+
const next3 = after({ text: text5, cursor: at });
|
|
15536
15583
|
if (at > r.a) line.push({ text: text5.slice(r.a, at), color: o.color });
|
|
15537
|
-
line.push(inv(text5.slice(at, Math.min(
|
|
15538
|
-
if (
|
|
15584
|
+
line.push(inv(text5.slice(at, Math.min(next3, r.b))));
|
|
15585
|
+
if (next3 < r.b) line.push({ text: text5.slice(next3, r.b), color: o.color });
|
|
15539
15586
|
}
|
|
15540
15587
|
if (cursor === r.b && r.last) line.push(inv(" "));
|
|
15541
15588
|
return line.filter((s) => s.text !== "" || s === line[0]);
|
|
@@ -15653,11 +15700,11 @@ function Field({ value, onChange, onSubmit, onEscape, onBrowse, history = [], ac
|
|
|
15653
15700
|
}
|
|
15654
15701
|
};
|
|
15655
15702
|
const show = (b2, i) => {
|
|
15656
|
-
const
|
|
15657
|
-
const text5 =
|
|
15658
|
-
st.current = { f: { text: text5, cursor: text5.length }, browse:
|
|
15703
|
+
const next3 = b2 && i !== void 0 ? { ...b2, i } : b2;
|
|
15704
|
+
const text5 = next3 ? next3.items[next3.i] : st.current.f.text;
|
|
15705
|
+
st.current = { f: { text: text5, cursor: text5.length }, browse: next3, pasted: 0 };
|
|
15659
15706
|
render2();
|
|
15660
|
-
onBrowse?.(inHistory(
|
|
15707
|
+
onBrowse?.(inHistory(next3));
|
|
15661
15708
|
};
|
|
15662
15709
|
useInput((input, key) => {
|
|
15663
15710
|
const { f: f2, browse: browse2 } = st.current;
|
|
@@ -15875,6 +15922,10 @@ function SessionCard({ s, note }) {
|
|
|
15875
15922
|
" ",
|
|
15876
15923
|
t.state[state2]
|
|
15877
15924
|
] }),
|
|
15925
|
+
s.rig ? /* @__PURE__ */ jsxs5(Text5, { color: C.blue, children: [
|
|
15926
|
+
" ",
|
|
15927
|
+
t.overview.rigSeat(s.rig.name, s.rig.role ?? s.rig.seat)
|
|
15928
|
+
] }) : null,
|
|
15878
15929
|
/* @__PURE__ */ jsxs5(Text5, { color: C.dim, children: [
|
|
15879
15930
|
" ",
|
|
15880
15931
|
TOOL_NAME[s.tool],
|
|
@@ -15952,6 +16003,7 @@ function Tail({ lines, color: color2, empty: empty3, emptyColor }) {
|
|
|
15952
16003
|
// src/tui/screens/Overview.tsx
|
|
15953
16004
|
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
15954
16005
|
var WIDE = 100;
|
|
16006
|
+
var folderOf = (cwd) => (cwd ?? "").split("/").filter(Boolean).at(-1) ?? "";
|
|
15955
16007
|
function windowed(rows, selectedKey, height) {
|
|
15956
16008
|
if (rows.length <= height) return [...rows];
|
|
15957
16009
|
const at = Math.max(0, rows.findIndex((r) => r.key === selectedKey));
|
|
@@ -15964,9 +16016,8 @@ function Overview() {
|
|
|
15964
16016
|
const { columns, rows: height } = useScreenSize();
|
|
15965
16017
|
const wide = columns >= WIDE;
|
|
15966
16018
|
const left2 = wide ? Math.min(64, Math.max(44, Math.floor(columns * 0.42))) : columns;
|
|
15967
|
-
const teams = useTeams(tui.client);
|
|
15968
16019
|
const tasks = useTasks(tui.client);
|
|
15969
|
-
const view = useMemo2(() => overview(d.sessions, projects
|
|
16020
|
+
const view = useMemo2(() => overview(d.sessions, projects), [d.sessions, projects]);
|
|
15970
16021
|
const sel = selected?.id ?? null;
|
|
15971
16022
|
const closed = closedLedgeTasks(tasks);
|
|
15972
16023
|
const decisions = useMemo2(() => openDecisions(tasks), [tasks]);
|
|
@@ -15988,11 +16039,6 @@ function Overview() {
|
|
|
15988
16039
|
};
|
|
15989
16040
|
const threshold = useContextNear(tui.client);
|
|
15990
16041
|
const near = useMemo2(() => nearContext(d.sessions, threshold), [d.sessions, threshold]);
|
|
15991
|
-
const [tasksShown, setTasksShown] = useState3(true);
|
|
15992
|
-
const [joining, setJoining] = useState3(null);
|
|
15993
|
-
const node2 = selected ? view.tree.find((n) => n.branches.some((b2) => b2.sessions.includes(selected)) || n.teams.some((x) => x.sessions.includes(selected))) : void 0;
|
|
15994
|
-
const seatTeam = selected?.team ? teams?.find((x) => x.id === selected.team && x.state !== "dissolved") : void 0;
|
|
15995
|
-
const choices2 = node2?.teams.map((x) => x.team).filter((x) => x.state !== "dissolved" && x.id !== selected?.team) ?? [];
|
|
15996
16042
|
useScreenKeys((input, key) => {
|
|
15997
16043
|
if (deciding) {
|
|
15998
16044
|
if (!deciding.confirm) {
|
|
@@ -16014,50 +16060,6 @@ function Overview() {
|
|
|
16014
16060
|
if (decisions[0]) setDeciding({ id: decisions[0].id, draft: "", confirm: false });
|
|
16015
16061
|
return true;
|
|
16016
16062
|
}
|
|
16017
|
-
if (joining) {
|
|
16018
|
-
if (key.escape) {
|
|
16019
|
-
setJoining(null);
|
|
16020
|
-
return true;
|
|
16021
|
-
}
|
|
16022
|
-
if (input === "j" || key.downArrow) {
|
|
16023
|
-
setJoining({ index: (joining.index + 1) % Math.max(1, choices2.length) });
|
|
16024
|
-
return true;
|
|
16025
|
-
}
|
|
16026
|
-
if (input === "k" || key.upArrow) {
|
|
16027
|
-
setJoining({ index: (joining.index + choices2.length - 1) % Math.max(1, choices2.length) });
|
|
16028
|
-
return true;
|
|
16029
|
-
}
|
|
16030
|
-
if (key.return && selected && choices2[joining.index]) {
|
|
16031
|
-
const team = choices2[joining.index];
|
|
16032
|
-
const role = selected.role ?? team.seats.find((x) => x.sessionId === null)?.role;
|
|
16033
|
-
setJoining(null);
|
|
16034
|
-
if (!role) {
|
|
16035
|
-
tui.toast({ text: t.overview.noTeamHere, tone: "info" });
|
|
16036
|
-
return true;
|
|
16037
|
-
}
|
|
16038
|
-
tui.client.send({ type: "team.join", team: team.id, session: selected.id, role });
|
|
16039
|
-
tui.toast({ text: t.toast.joined(selected.name, team.name), tone: "ok" });
|
|
16040
|
-
return true;
|
|
16041
|
-
}
|
|
16042
|
-
return true;
|
|
16043
|
-
}
|
|
16044
|
-
if (input === "J" && selected) {
|
|
16045
|
-
if (choices2.length) setJoining({ index: 0 });
|
|
16046
|
-
else tui.toast({ text: t.overview.noTeamHere, tone: "info" });
|
|
16047
|
-
return true;
|
|
16048
|
-
}
|
|
16049
|
-
if (input === "R") {
|
|
16050
|
-
const resting = (seatTeam?.state === "resting" ? seatTeam : void 0) ?? node2?.teams.find((x) => x.team.state === "resting")?.team ?? view.tree.flatMap((n) => n.teams).find((x) => x.team.state === "resting")?.team;
|
|
16051
|
-
if (resting) {
|
|
16052
|
-
tui.client.send({ type: "team.resume", team: resting.id });
|
|
16053
|
-
tui.toast({ text: t.toast.resumed(resting.name), tone: "ok" });
|
|
16054
|
-
}
|
|
16055
|
-
return true;
|
|
16056
|
-
}
|
|
16057
|
-
if (input === "T") {
|
|
16058
|
-
setTasksShown((v) => !v);
|
|
16059
|
-
return true;
|
|
16060
|
-
}
|
|
16061
16063
|
if (input === "H") {
|
|
16062
16064
|
const s = (selected && selected.source === "launcher" && selected.state !== "exited" && selected.tool !== "omp" && (!selected.handover || selected.handover.state === "failed") ? selected : void 0) ?? near.find((x) => x.handover?.state !== "failed") ?? near[0];
|
|
16063
16065
|
if (!s) return true;
|
|
@@ -16085,8 +16087,8 @@ function Overview() {
|
|
|
16085
16087
|
return true;
|
|
16086
16088
|
}
|
|
16087
16089
|
if (key.tab) {
|
|
16088
|
-
const
|
|
16089
|
-
if (
|
|
16090
|
+
const next3 = nextWaiting(view.yours, sel);
|
|
16091
|
+
if (next3) select(next3);
|
|
16090
16092
|
return true;
|
|
16091
16093
|
}
|
|
16092
16094
|
if (key.return) {
|
|
@@ -16110,22 +16112,25 @@ function Overview() {
|
|
|
16110
16112
|
}
|
|
16111
16113
|
return false;
|
|
16112
16114
|
});
|
|
16113
|
-
const
|
|
16114
|
-
|
|
16115
|
-
|
|
16115
|
+
const groupRows = (kind) => view.tree.filter((n) => n.kind === kind).flatMap((n) => [
|
|
16116
|
+
...kind === "rig" ? [{ kind: "project", key: n.key, label: n.label, color: C.blue, count: n.count, rig: true, folder: folderOf(n.branches[0]?.sessions[0]?.cwd) }] : [],
|
|
16117
|
+
...n.branches.flatMap((b2) => b2.sessions.map((s) => ({ kind: "session", key: s.id, s, indent: kind === "rig" ? 2 : 0, group: kind })))
|
|
16118
|
+
]);
|
|
16119
|
+
const rigRows = groupRows("rig"), kernelRows = groupRows("kernel");
|
|
16120
|
+
const tree2 = view.tree.filter((n) => !n.kind).flatMap((n) => {
|
|
16116
16121
|
return [
|
|
16117
16122
|
{ kind: "project", key: n.key, label: n.label, color: projectColor(n.color), count: n.count },
|
|
16118
|
-
...
|
|
16119
|
-
...n.branches.flatMap((b2) => [{ kind: "branch", key: `${n.key}|${b2.branch}`, branch: b2.branch, indent: teamed ? 4 : 2 }, ...b2.sessions.map((s) => ({ kind: "session", key: s.id, s, indent: teamed ? 2 : 0 }))]),
|
|
16120
|
-
...n.teams.flatMap((x) => [{ kind: "team", key: x.key, team: x.team, done: x.done, given: x.given }, ...x.sessions.map((s) => ({ kind: "session", key: s.id, s, indent: 2 }))])
|
|
16123
|
+
...n.branches.flatMap((b2) => [{ kind: "branch", key: `${n.key}|${b2.branch}`, branch: b2.branch, indent: 2 }, ...b2.sessions.map((s) => ({ kind: "session", key: s.id, s, indent: 0 }))])
|
|
16121
16124
|
];
|
|
16122
16125
|
});
|
|
16123
16126
|
const yoursCount = view.yours.length + decisions.length + closed.length + near.length;
|
|
16124
16127
|
const yoursHeight = Math.max(1, Math.min(yoursCount, 6));
|
|
16125
|
-
const joinHeight = joining && selected ? Math.max(1, choices2.length) + 2 : 0;
|
|
16126
16128
|
const answerLines = deciding?.confirm ? wrap2(deciding.draft.trim(), Math.max(10, columns - 4)) : [];
|
|
16127
16129
|
const decideHeight = !deciding ? 0 : deciding.confirm ? Math.min(answerLines.length, Math.max(1, height - 12)) + 2 : fieldRows(columns, height) + 2;
|
|
16128
|
-
const
|
|
16130
|
+
const allHeight = Math.max(3, height - 3 - (yoursHeight + 2) - decideHeight - 3);
|
|
16131
|
+
const kernelHeight = kernelRows.length ? Math.min(kernelRows.length, 5) : 0;
|
|
16132
|
+
const rigsHeight = rigRows.length ? Math.min(rigRows.length, Math.max(3, Math.floor(allHeight / 3))) : 0;
|
|
16133
|
+
const treeHeight = Math.max(3, allHeight - (rigsHeight ? rigsHeight + 2 : 0) - (kernelHeight ? kernelHeight + 2 : 0));
|
|
16129
16134
|
const inner = left2 - 4, nameW = 7;
|
|
16130
16135
|
const stateW = Math.max(...Object.values(t.state).map((x) => x.length)) + 1;
|
|
16131
16136
|
const topicW = Math.max(6, inner - 6 - nameW - stateW - 3);
|
|
@@ -16138,8 +16143,13 @@ function Overview() {
|
|
|
16138
16143
|
" "
|
|
16139
16144
|
] }),
|
|
16140
16145
|
/* @__PURE__ */ jsx10(Text7, { color: C.fg, bold: true, children: fit(s.name, nameW) }),
|
|
16141
|
-
/* @__PURE__ */
|
|
16142
|
-
|
|
16146
|
+
s.rig ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
16147
|
+
/* @__PURE__ */ jsx10(Text7, { children: " " }),
|
|
16148
|
+
/* @__PURE__ */ jsx10(Text7, { color: C.blue, children: rigTag(s) }),
|
|
16149
|
+
/* @__PURE__ */ jsx10(Text7, { color: C.dim, children: seatSecond(s, "") }),
|
|
16150
|
+
/* @__PURE__ */ jsx10(Text7, { children: " " })
|
|
16151
|
+
] }) : /* @__PURE__ */ jsx10(Text7, { color: C.dim, children: fit(s.repo ?? s.project, 9) }),
|
|
16152
|
+
/* @__PURE__ */ jsx10(Text7, { color: STATE_COLOR[st], children: fit(oneLine(s.pending?.text ?? ""), s.rig ? Math.max(6, askW + 9 - rigTag(s).length - seatSecond(s, "").length - 4) : askW) }),
|
|
16143
16153
|
/* @__PURE__ */ jsxs6(Text7, { color: C.faint, children: [
|
|
16144
16154
|
" ",
|
|
16145
16155
|
/* @__PURE__ */ jsx10(Ago, { iso: s.lastActivityAt })
|
|
@@ -16166,7 +16176,7 @@ function Overview() {
|
|
|
16166
16176
|
s.handover?.state === "failed" ? g.fail : "\u25D4",
|
|
16167
16177
|
" "
|
|
16168
16178
|
] }),
|
|
16169
|
-
/* @__PURE__ */ jsx10(Text7, { color: C.fg, children: s.handover?.state === "failed" ? t.overview.reliefFailed(s.name, s.handover.reason ?? "?") : t.overview.near(
|
|
16179
|
+
/* @__PURE__ */ jsx10(Text7, { color: C.fg, children: s.handover?.state === "failed" ? t.overview.reliefFailed(s.name, s.handover.reason ?? "?") : t.overview.near(s.name, Math.round((s.context?.used ?? 0) / (s.context?.window ?? 1) * 100)) })
|
|
16170
16180
|
] }, `near:${s.id}`))] });
|
|
16171
16181
|
const treeBox = /* @__PURE__ */ jsx10(TitledBox, { title: t.overview.projects, flexGrow: 1, children: tree2.length === 0 ? /* @__PURE__ */ jsx10(Text7, { color: C.faint, children: t.overview.noSession }) : windowed(tree2, sel, treeHeight).map((r) => r.kind === "project" ? /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", children: [
|
|
16172
16182
|
/* @__PURE__ */ jsx10(Text7, { color: r.color, children: g.project }),
|
|
@@ -16174,32 +16184,32 @@ function Overview() {
|
|
|
16174
16184
|
/* @__PURE__ */ jsx10(Text7, { color: C.fg, bold: true, children: r.label }),
|
|
16175
16185
|
" ",
|
|
16176
16186
|
/* @__PURE__ */ jsx10(Text7, { color: C.faint, children: t.overview.sessions(r.count) })
|
|
16177
|
-
] }, r.key) : r.kind === "common" ? /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", color: C.faint, children: [
|
|
16178
|
-
" ",
|
|
16179
|
-
g.common,
|
|
16180
|
-
" ",
|
|
16181
|
-
t.overview.common
|
|
16182
|
-
] }, r.key) : r.kind === "team" ? /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", children: [
|
|
16183
|
-
/* @__PURE__ */ jsx10(Text7, { children: " " }),
|
|
16184
|
-
/* @__PURE__ */ jsx10(Text7, { color: C.coral, children: g.team }),
|
|
16185
|
-
" ",
|
|
16186
|
-
/* @__PURE__ */ jsx10(Text7, { color: r.team.state === "resting" ? C.dim : C.fg, bold: true, children: r.team.name }),
|
|
16187
|
-
" ",
|
|
16188
|
-
/* @__PURE__ */ jsx10(Text7, { color: C.faint, children: r.team.state === "resting" ? t.overview.resting : t.overview.teamLine(r.done, r.given) })
|
|
16189
16187
|
] }, r.key) : r.kind === "branch" ? /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", color: C.faint, children: [
|
|
16190
16188
|
" ".repeat(r.indent),
|
|
16191
16189
|
g.branch,
|
|
16192
16190
|
" ",
|
|
16193
16191
|
r.branch
|
|
16194
|
-
] }, r.key) : /* @__PURE__ */ jsx10(SessionRow, { s: r.s, on: r.s.id === sel, nameW, topicW: Math.max(6, topicW - r.indent
|
|
16192
|
+
] }, r.key) : /* @__PURE__ */ jsx10(SessionRow, { s: r.s, on: r.s.id === sel, nameW, topicW: Math.max(6, topicW - r.indent), stateW, indent: r.indent }, r.key)) });
|
|
16193
|
+
const groupBox = (title2, rows, rowsHeight) => rows.length === 0 ? null : /* @__PURE__ */ jsx10(TitledBox, { title: title2, height: rowsHeight + 2, children: windowed(rows, sel, rowsHeight).map((r) => r.kind === "project" ? /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", children: [
|
|
16194
|
+
/* @__PURE__ */ jsx10(Text7, { color: r.color, children: "\u2B21" }),
|
|
16195
|
+
" ",
|
|
16196
|
+
/* @__PURE__ */ jsx10(Text7, { color: C.fg, bold: true, children: r.label }),
|
|
16197
|
+
r.folder ? /* @__PURE__ */ jsxs6(Text7, { color: C.faint, children: [
|
|
16198
|
+
" ",
|
|
16199
|
+
r.folder
|
|
16200
|
+
] }) : null,
|
|
16201
|
+
/* @__PURE__ */ jsxs6(Text7, { color: C.faint, children: [
|
|
16202
|
+
" ",
|
|
16203
|
+
t.overview.sessions(r.count)
|
|
16204
|
+
] })
|
|
16205
|
+
] }, r.key) : r.kind === "session" ? /* @__PURE__ */ jsx10(SessionRow, { s: r.s, on: r.s.id === sel, nameW, topicW: Math.max(6, topicW - r.indent), stateW, indent: r.indent, group: r.group }, r.key) : null) });
|
|
16206
|
+
const rigsBox = groupBox(t.overview.rigsGroup, rigRows, rigsHeight);
|
|
16207
|
+
const kernelBox = groupBox(t.overview.kernelGroup, kernelRows, kernelHeight);
|
|
16195
16208
|
const keys = deciding?.confirm ? [["y", t.keys.sendAnswer], ["n esc", t.keys.edit]] : deciding ? [["\u21B5", t.keys.review], ["alt+\u21B5", t.keys.newLine], ["esc", t.keys.cancel]] : [
|
|
16196
16209
|
["j k", t.keys.navigate],
|
|
16197
16210
|
["\u21B5", t.keys.open],
|
|
16198
16211
|
...view.yours.length ? [["tab", t.keys.next], ["y n", t.keys.answer]] : [],
|
|
16199
16212
|
["a", t.keys.attach],
|
|
16200
|
-
...seatTeam ? [["T", t.keys.tasks]] : [],
|
|
16201
|
-
...choices2.length ? [["J", t.keys.join]] : [],
|
|
16202
|
-
...view.tree.some((n) => n.teams.some((x) => x.team.state === "resting")) ? [["R", t.keys.resume]] : [],
|
|
16203
16213
|
...decisions.length ? [["D", t.keys.decide]] : [],
|
|
16204
16214
|
...near.length ? [["H", t.keys.handover]] : [],
|
|
16205
16215
|
["/", t.keys.ask],
|
|
@@ -16208,36 +16218,17 @@ function Overview() {
|
|
|
16208
16218
|
["?", t.keys.help],
|
|
16209
16219
|
["q", t.keys.quit]
|
|
16210
16220
|
];
|
|
16211
|
-
const teamTasks = seatTeam ? tasks.filter((x) => x.team === seatTeam.id && (!taskClosed(x) || x.updatedAt.slice(0, 10) === (/* @__PURE__ */ new Date()).toISOString().slice(0, 10))).slice(-4) : [];
|
|
16212
16221
|
return /* @__PURE__ */ jsxs6(Frame, { crumb: tui.machines.map((m) => `${m.label} ${m.ready ? g.machine : "\u25CB"}`).join(" "), keys, children: [
|
|
16213
16222
|
/* @__PURE__ */ jsxs6(Box8, { flexGrow: 1, children: [
|
|
16214
16223
|
/* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", width: left2, flexShrink: 0, children: [
|
|
16215
16224
|
yoursBox,
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
x.name
|
|
16220
|
-
] }, x.id)) }) : null,
|
|
16221
|
-
treeBox
|
|
16225
|
+
treeBox,
|
|
16226
|
+
rigsBox,
|
|
16227
|
+
kernelBox
|
|
16222
16228
|
] }),
|
|
16223
16229
|
wide ? /* @__PURE__ */ jsxs6(Box8, { flexDirection: "column", flexGrow: 1, children: [
|
|
16224
16230
|
selected ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
16225
|
-
/* @__PURE__ */ jsx10(TitledBox, { title: `${selected.name} \xB7 ${oneLine(selected.topic ?? selected.title)}`, color: isPending(selected) ? C.red : C.line, titleColor: isPending(selected) ? C.red : C.dim, children: /* @__PURE__ */ jsx10(SessionCard, { s: selected, note: true }) }),
|
|
16226
|
-
seatTeam && tasksShown ? /* @__PURE__ */ jsx10(TitledBox, { title: t.overview.tasks(`${g.team} ${seatTeam.name}`), height: Math.max(3, teamTasks.length + 2), children: teamTasks.length === 0 ? /* @__PURE__ */ jsx10(Text7, { color: C.faint, children: t.overview.noTask }) : teamTasks.map((x) => /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", children: [
|
|
16227
|
-
/* @__PURE__ */ jsx10(Text7, { color: C.faint, children: x.id }),
|
|
16228
|
-
" ",
|
|
16229
|
-
/* @__PURE__ */ jsx10(Text7, { color: C.fg, children: x.title }),
|
|
16230
|
-
" ",
|
|
16231
|
-
/* @__PURE__ */ jsxs6(Text7, { color: C.dim, children: [
|
|
16232
|
-
x.giverName,
|
|
16233
|
-
" ",
|
|
16234
|
-
g.arrow,
|
|
16235
|
-
" ",
|
|
16236
|
-
x.ownerName
|
|
16237
|
-
] }),
|
|
16238
|
-
" ",
|
|
16239
|
-
/* @__PURE__ */ jsx10(Text7, { color: x.state === "done" ? C.green : x.state === "taken" ? C.blue : C.faint, children: t.ask.taskState[x.state] })
|
|
16240
|
-
] }, x.id)) }) : null,
|
|
16231
|
+
/* @__PURE__ */ jsx10(TitledBox, { title: `${selected.name}${selected.rig ? ` \xB7 ${t.overview.rigSeat(selected.rig.name, selected.rig.role ?? selected.rig.seat)}` : ""} \xB7 ${oneLine(selected.topic ?? selected.title)}`, color: isPending(selected) ? C.red : C.line, titleColor: isPending(selected) ? C.red : C.dim, children: /* @__PURE__ */ jsx10(SessionCard, { s: selected, note: true }) }),
|
|
16241
16232
|
/* @__PURE__ */ jsx10(TitledBox, { title: t.overview.terminal(paneName(selected)), flexGrow: 1, children: /* @__PURE__ */ jsx10(Tail, { lines: d.previews.get(selected.id) ?? [], color: C.dim, empty: t.overview.noPreview, emptyColor: C.faint }) })
|
|
16242
16233
|
] }) : /* @__PURE__ */ jsx10(TitledBox, { title: t.tabs.session, flexGrow: 1, children: /* @__PURE__ */ jsx10(Text7, { color: C.faint, children: t.session.noSession }) }),
|
|
16243
16234
|
/* @__PURE__ */ jsx10(TitledBox, { title: t.overview.exchanges, height: 5, children: (() => {
|
|
@@ -16277,7 +16268,7 @@ function Overview() {
|
|
|
16277
16268
|
) : null
|
|
16278
16269
|
] });
|
|
16279
16270
|
}
|
|
16280
|
-
function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0 }) {
|
|
16271
|
+
function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0, group }) {
|
|
16281
16272
|
const { t, g } = useTui();
|
|
16282
16273
|
const st = botState(s);
|
|
16283
16274
|
const n = helperCount(s);
|
|
@@ -16289,14 +16280,19 @@ function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0 }) {
|
|
|
16289
16280
|
" "
|
|
16290
16281
|
] }),
|
|
16291
16282
|
/* @__PURE__ */ jsx10(Text7, { color: s.offline ? C.dim : C.fg, bold: true, children: fit(s.name, nameW) }),
|
|
16292
|
-
|
|
16293
|
-
"
|
|
16294
|
-
s.role,
|
|
16295
|
-
" "
|
|
16296
|
-
] }) : null,
|
|
16297
|
-
/* @__PURE__ */ jsxs6(Text7, { color: C.dim, children: [
|
|
16298
|
-
fit(oneLine(s.topic ?? s.title), topicW),
|
|
16283
|
+
group ? /* @__PURE__ */ jsxs6(Text7, { color: C.dim, children: [
|
|
16284
|
+
" ",
|
|
16285
|
+
fit(group === "kernel" ? `${(s.rig?.role ?? "").replace(/\.(agent|lead|worker)$/, "").padEnd(11)}${s.tool}` : s.rig?.role ?? "", topicW - 1),
|
|
16299
16286
|
" "
|
|
16287
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
16288
|
+
s.rig ? /* @__PURE__ */ jsxs6(Text7, { color: C.blue, children: [
|
|
16289
|
+
" ",
|
|
16290
|
+
rigTag(s)
|
|
16291
|
+
] }) : null,
|
|
16292
|
+
/* @__PURE__ */ jsxs6(Text7, { color: C.dim, children: [
|
|
16293
|
+
fit(seatSecond(s, oneLine(s.topic ?? s.title)), s.rig ? Math.max(0, topicW - rigTag(s).length - 1) : topicW),
|
|
16294
|
+
" "
|
|
16295
|
+
] })
|
|
16300
16296
|
] }),
|
|
16301
16297
|
/* @__PURE__ */ jsx10(Text7, { color: s.offline ? C.faint : STATE_COLOR[st], children: fit(s.offline ? t.overview.offline : t.state[st], stateW).trimEnd() }),
|
|
16302
16298
|
n > 0 ? /* @__PURE__ */ jsxs6(Text7, { color: C.violet, children: [
|
|
@@ -16327,9 +16323,9 @@ function useChips(put) {
|
|
|
16327
16323
|
const { t, toast } = useTui();
|
|
16328
16324
|
const [items, setItems] = useState4([]);
|
|
16329
16325
|
const held = useRef8([]);
|
|
16330
|
-
const commit = (
|
|
16331
|
-
held.current =
|
|
16332
|
-
setItems(
|
|
16326
|
+
const commit = (next3) => {
|
|
16327
|
+
held.current = next3;
|
|
16328
|
+
setItems(next3);
|
|
16333
16329
|
};
|
|
16334
16330
|
const patch = (key, over) => commit(held.current.map((c) => c.key === key ? { ...c, ...over } : c));
|
|
16335
16331
|
const reasonOf = (e) => {
|
|
@@ -16372,10 +16368,10 @@ function useChips(put) {
|
|
|
16372
16368
|
}
|
|
16373
16369
|
};
|
|
16374
16370
|
}
|
|
16375
|
-
function ChipsLine({ chips }) {
|
|
16371
|
+
function ChipsLine({ chips: chips2 }) {
|
|
16376
16372
|
const { t } = useTui();
|
|
16377
|
-
if (
|
|
16378
|
-
return /* @__PURE__ */ jsx11(Text8, { wrap: "truncate", children:
|
|
16373
|
+
if (chips2.length === 0) return null;
|
|
16374
|
+
return /* @__PURE__ */ jsx11(Text8, { wrap: "truncate", children: chips2.map((c, i) => /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
16379
16375
|
i ? " " : "",
|
|
16380
16376
|
/* @__PURE__ */ jsxs7(Text8, { color: c.state === "refused" ? C.red : C.dim, children: [
|
|
16381
16377
|
"\u25A3 ",
|
|
@@ -16394,14 +16390,14 @@ function ChipsLine({ chips }) {
|
|
|
16394
16390
|
] }, c.key)) });
|
|
16395
16391
|
}
|
|
16396
16392
|
var EXT = { "image/png": "png", "image/jpeg": "jpg", "image/gif": "gif", "image/webp": "webp" };
|
|
16397
|
-
function usePaste2(
|
|
16393
|
+
function usePaste2(chips2) {
|
|
16398
16394
|
const { readImage, toast, t } = useTui();
|
|
16399
16395
|
const reading = useRef8(false);
|
|
16400
16396
|
return () => {
|
|
16401
16397
|
if (reading.current) return;
|
|
16402
16398
|
reading.current = true;
|
|
16403
16399
|
void readImage().then((got) => {
|
|
16404
|
-
if (got)
|
|
16400
|
+
if (got) chips2.add(got);
|
|
16405
16401
|
else toast({ text: t.images.none, tone: "info" });
|
|
16406
16402
|
}, () => toast({ text: t.images.none, tone: "info" })).finally(() => {
|
|
16407
16403
|
reading.current = false;
|
|
@@ -16556,30 +16552,30 @@ function SessionView({ s }) {
|
|
|
16556
16552
|
setAnchor({ key, offset: top - lineKeys.indexOf(key) });
|
|
16557
16553
|
};
|
|
16558
16554
|
const images = useMemo3(() => (items ? threadImages(items, unfolded) : []).map((ref) => ({ ref, route: { id: s.id } })), [items, unfolded, s.id]);
|
|
16559
|
-
const
|
|
16560
|
-
const paste = usePaste2(
|
|
16555
|
+
const chips2 = useChips((image2) => putImage(client, image2, { id: s.id }));
|
|
16556
|
+
const paste = usePaste2(chips2);
|
|
16561
16557
|
const openImage2 = useOpenImage();
|
|
16562
16558
|
const machine = splitId(s.id)?.machine ?? "local";
|
|
16563
16559
|
const canSwitch = machines.find((m) => m.id === machine)?.daemon?.modelSwitch === true;
|
|
16564
16560
|
const send = (text5, { fromHistory }) => {
|
|
16565
|
-
const withImages = mode === "reply" && !fromHistory &&
|
|
16561
|
+
const withImages = mode === "reply" && !fromHistory && chips2.items.length > 0;
|
|
16566
16562
|
if (!text5.trim() && !withImages) {
|
|
16567
16563
|
setMode("read");
|
|
16568
16564
|
return true;
|
|
16569
16565
|
}
|
|
16570
|
-
if (withImages && !
|
|
16566
|
+
if (withImages && !chips2.ready) return false;
|
|
16571
16567
|
if (withImages && p?.kind === "question") {
|
|
16572
16568
|
toast({ text: t.images.dialog, tone: "info" });
|
|
16573
16569
|
return false;
|
|
16574
16570
|
}
|
|
16575
|
-
const taken = withImages ?
|
|
16571
|
+
const taken = withImages ? chips2.clear() : [];
|
|
16576
16572
|
const back2 = (x) => {
|
|
16577
16573
|
if (!kept.drafts.get(s.id)) setDraft(x);
|
|
16578
|
-
if (taken.length)
|
|
16574
|
+
if (taken.length) chips2.putBack(taken);
|
|
16579
16575
|
};
|
|
16580
16576
|
const how = taken.length ? { attachments: taken.flatMap((c) => c.id ? [c.id] : []) } : void 0;
|
|
16581
16577
|
if (!(mode === "note" ? actions.denyWithNote(s, text5.trim(), back2) : actions.reply(s, text5, back2, how))) {
|
|
16582
|
-
if (taken.length)
|
|
16578
|
+
if (taken.length) chips2.putBack(taken);
|
|
16583
16579
|
return false;
|
|
16584
16580
|
}
|
|
16585
16581
|
if (text5.trim()) kept.sent.set(s.id, [...kept.sent.get(s.id) ?? [], text5]);
|
|
@@ -16594,7 +16590,7 @@ function SessionView({ s }) {
|
|
|
16594
16590
|
};
|
|
16595
16591
|
useInput3((input, key) => {
|
|
16596
16592
|
if (key.meta && input === "v") paste();
|
|
16597
|
-
else if ((key.backspace || key.delete) && draft === "")
|
|
16593
|
+
else if ((key.backspace || key.delete) && draft === "") chips2.removeLast();
|
|
16598
16594
|
}, { isActive: mode === "reply" });
|
|
16599
16595
|
useScreenKeys((input, key) => {
|
|
16600
16596
|
if (mode === "model") return true;
|
|
@@ -16680,7 +16676,7 @@ function SessionView({ s }) {
|
|
|
16680
16676
|
if (input === "y" || input === "n" || input === "A" || /^[1-9]$/.test(input)) return actions.key(s, input);
|
|
16681
16677
|
return false;
|
|
16682
16678
|
});
|
|
16683
|
-
const title2 = `${s.name} \xB7 ${oneLine(s.topic ?? s.title)} \xB7 ${TOOL_NAME[s.tool]} \xB7 ${modelLabel(s, t.session.defaultModel)}`;
|
|
16679
|
+
const title2 = `${s.name}${s.rig ? ` \xB7 ${t.overview.rigSeat(s.rig.name, s.rig.role ?? s.rig.seat)}` : ""} \xB7 ${oneLine(s.topic ?? s.title)} \xB7 ${TOOL_NAME[s.tool]} \xB7 ${modelLabel(s, t.session.defaultModel)}`;
|
|
16684
16680
|
const showsThread = mode !== "model" && !terminal && !!items && lines.length > 0;
|
|
16685
16681
|
const above = lines.length - view - up;
|
|
16686
16682
|
const foot = up > 0 ? t.session.scrolled(above, up) : lines.length > view ? t.session.above(lines.length - view) : void 0;
|
|
@@ -16688,7 +16684,7 @@ function SessionView({ s }) {
|
|
|
16688
16684
|
const editing = mode === "reply" || mode === "note";
|
|
16689
16685
|
const body = rows - 2 - (lastToast ? 1 : 0);
|
|
16690
16686
|
const inner = Math.max(20, columns - 4);
|
|
16691
|
-
const below = (editing ? Math.min(fieldRows(columns, rows), layout(draft, Math.max(10, columns - 4) - 2).length) + 2 : 3) + (
|
|
16687
|
+
const below = (editing ? Math.min(fieldRows(columns, rows), layout(draft, Math.max(10, columns - 4) - 2).length) + 2 : 3) + (chips2.items.length ? 1 : 0);
|
|
16692
16688
|
let request2 = p ? ask(s, p, t, inner, 4, !editing) : null;
|
|
16693
16689
|
const over = request2 ? askRows(request2, inner) + below - body : 0;
|
|
16694
16690
|
if (p && request2 && over > 0) request2 = ask(s, p, t, inner, Math.max(1, 4 - over), !editing);
|
|
@@ -16710,7 +16706,7 @@ function SessionView({ s }) {
|
|
|
16710
16706
|
}
|
|
16711
16707
|
) : terminal ? /* @__PURE__ */ jsx13(Tail, { lines: d.previews.get(s.id) ?? [], color: C.dim, empty: t.overview.noPreview, emptyColor: C.faint }) : !items ? /* @__PURE__ */ jsx13(Text10, { color: C.faint, children: t.session.loading }) : lines.length === 0 ? /* @__PURE__ */ jsx13(Text10, { color: C.faint, children: t.session.empty }) : /* @__PURE__ */ jsx13(Lines, { lines, up, onHeight: setView }) }) : null,
|
|
16712
16708
|
p && request2 ? /* @__PURE__ */ jsx13(PendingBox, { s, a: request2 }) : null,
|
|
16713
|
-
/* @__PURE__ */ jsx13(ChipsLine, { chips:
|
|
16709
|
+
/* @__PURE__ */ jsx13(ChipsLine, { chips: chips2.items }),
|
|
16714
16710
|
mode === "reply" || mode === "note" ? /* @__PURE__ */ jsx13(
|
|
16715
16711
|
Field,
|
|
16716
16712
|
{
|
|
@@ -16780,7 +16776,7 @@ function actionRowOf(a) {
|
|
|
16780
16776
|
if (a.vars !== void 0) row2.vars = a.vars;
|
|
16781
16777
|
if (a.detail !== void 0 && a.action === "session.decide" && a.vars?.kind) row2.request = { kind: a.vars.kind, text: a.detail };
|
|
16782
16778
|
else if (a.detail !== void 0) row2.detail = a.detail;
|
|
16783
|
-
const target = a.vars?.session ?? a.vars?.owner
|
|
16779
|
+
const target = a.vars?.session ?? a.vars?.owner;
|
|
16784
16780
|
if (target !== void 0) row2.target = target;
|
|
16785
16781
|
if (a.vars?.decision === "accept" || a.vars?.decision === "deny") row2.decision = a.vars.decision;
|
|
16786
16782
|
if (a.action === "session.decide" && row2.decision !== "deny") row2.deny = { summary: a.summary };
|
|
@@ -16873,7 +16869,6 @@ function chatView(turns2, live, o) {
|
|
|
16873
16869
|
out.push([{ text: "" }], ...markdownLines(text5, { width: width - 2, g, color: C.fg }).map((l) => [pad(2), ...l]));
|
|
16874
16870
|
if (streaming !== void 0) out.push([pad(2), { text: g.caret, color: C.coral }]);
|
|
16875
16871
|
} else out.push([{ text: ` ${t.ask.reading}`, color: C.faint }]);
|
|
16876
|
-
if (turn.team?.teamId && turn.team.launchedAt) out.push([{ text: ` ${g.team} ${turn.team.name} \xB7 ${t.ask.teamLaunched(clock(turn.team.launchedAt))}`, color: C.green }]);
|
|
16877
16872
|
for (const c of turn.tasks ?? []) if (c.taskId) out.push([{ text: ` ${c.title} \xB7 ${t.ask.given(c.ownerName ?? c.toName ?? c.to, c.taskId, t.ask.taskState[c.state ?? "open"])}`, color: C.green }]);
|
|
16878
16873
|
out.push(...actionTrace(turn, t, g, width));
|
|
16879
16874
|
for (const l of out) {
|
|
@@ -16885,7 +16880,7 @@ function chatView(turns2, live, o) {
|
|
|
16885
16880
|
}
|
|
16886
16881
|
function actionTrace(turn, t, g, width) {
|
|
16887
16882
|
const a = t.ask.action, c = a.copy;
|
|
16888
|
-
const cards = !!(turn.actions || turn.proposal || turn.relay || turn.closes || turn.
|
|
16883
|
+
const cards = !!(turn.actions || turn.proposal || turn.relay || turn.closes || turn.tasks || turn.projectProposal);
|
|
16889
16884
|
if (turn.ignoredAt) {
|
|
16890
16885
|
const shown = turn.actions ? cardPlan(turn.actions).shown : [];
|
|
16891
16886
|
const sent = { done: shown.filter((s) => s === "done").length, denied: shown.filter((s) => s === "denied").length, failed: shown.filter((s) => s === "failed").length };
|
|
@@ -16914,7 +16909,6 @@ function openCards(turns2) {
|
|
|
16914
16909
|
for (const turn of [...turns2].reverse()) {
|
|
16915
16910
|
if (!turn.answeredAt || turn.ignoredAt) continue;
|
|
16916
16911
|
if (turn.actions && !cardClosed(turn.actions)) out.push({ kind: "action", qid: turn.qid });
|
|
16917
|
-
if (turn.team && !turn.team.teamId) out.push({ kind: "team", qid: turn.qid });
|
|
16918
16912
|
const tasks = (turn.tasks ?? []).map((c, i) => c.taskId ? -1 : i).filter((i) => i >= 0);
|
|
16919
16913
|
if (tasks.length) out.push({ kind: "task", qid: turn.qid, rows: tasks });
|
|
16920
16914
|
const launch2 = proposalRows(turn).map((p, i) => p.launchedId ? -1 : i).filter((i) => i >= 0);
|
|
@@ -17109,8 +17103,8 @@ function Ask() {
|
|
|
17109
17103
|
const [focus, setFocus] = useState9(-1);
|
|
17110
17104
|
const [anchor, setAnchor] = useState9(null);
|
|
17111
17105
|
const [view, setView] = useState9(10);
|
|
17112
|
-
const
|
|
17113
|
-
const paste = usePaste2(
|
|
17106
|
+
const chips2 = useChips(null);
|
|
17107
|
+
const paste = usePaste2(chips2);
|
|
17114
17108
|
const openImage2 = useOpenImage();
|
|
17115
17109
|
const [busy, setBusy] = useState9(null);
|
|
17116
17110
|
const [rowOf2, setRowOf] = useState9({});
|
|
@@ -17124,7 +17118,7 @@ function Ask() {
|
|
|
17124
17118
|
if (!s || !turn) return;
|
|
17125
17119
|
if (turn.error) {
|
|
17126
17120
|
sentAsk.current = null;
|
|
17127
|
-
|
|
17121
|
+
chips2.putBack(s.taken);
|
|
17128
17122
|
setDraft(kept.drafts.get("ask") || s.text);
|
|
17129
17123
|
} else if (turn.answeredAt) sentAsk.current = null;
|
|
17130
17124
|
}, [d.chat]);
|
|
@@ -17133,7 +17127,7 @@ function Ask() {
|
|
|
17133
17127
|
lines: Math.floor((height - 6) / Math.max(1, cards.length)),
|
|
17134
17128
|
height: (text5, indent2) => text5.split("\n").reduce((n, l) => n + Math.max(1, wrapSegs([{ text: l, color: C.fg }], Math.max(10, columns - 8 - indent2)).length), 0)
|
|
17135
17129
|
};
|
|
17136
|
-
const
|
|
17130
|
+
const planOf2 = (turn) => cardPlan(turn.actions ?? [], room);
|
|
17137
17131
|
useEffect10(() => {
|
|
17138
17132
|
if (focus >= cards.length) setFocus(cards.length ? cards.length - 1 : -1);
|
|
17139
17133
|
}, [cards.length, focus]);
|
|
@@ -17150,7 +17144,7 @@ function Ask() {
|
|
|
17150
17144
|
}, [confirming, cards]);
|
|
17151
17145
|
useEffect10(() => {
|
|
17152
17146
|
const turn = confirming && d.chat.find((x) => x.qid === confirming.qid);
|
|
17153
|
-
if (turn && !confirming.rows.every((i) => appliable(
|
|
17147
|
+
if (turn && !confirming.rows.every((i) => appliable(planOf2(turn).shown[i]))) setConfirming(null);
|
|
17154
17148
|
});
|
|
17155
17149
|
const ignored = [...d.chat].filter((x) => x.ignoredAt).sort((a, b2) => b2.ignoredAt.localeCompare(a.ignoredAt))[0];
|
|
17156
17150
|
useEffect10(() => {
|
|
@@ -17172,7 +17166,7 @@ function Ask() {
|
|
|
17172
17166
|
const local = machines.find((m) => m.id === "local");
|
|
17173
17167
|
const asking = d.chat.find((x) => !x.answeredAt && !x.error);
|
|
17174
17168
|
const ask2 = (text5, { fromHistory }) => {
|
|
17175
|
-
const images = fromHistory ? [] :
|
|
17169
|
+
const images = fromHistory ? [] : chips2.uploads();
|
|
17176
17170
|
if (!text5.trim() && images.length === 0) return true;
|
|
17177
17171
|
if (!local?.ready) {
|
|
17178
17172
|
toast({ text: t.ask.offline, tone: "info" });
|
|
@@ -17183,7 +17177,7 @@ function Ask() {
|
|
|
17183
17177
|
daemonStore.beginTurn({ qid, ...asked2, steps: [] });
|
|
17184
17178
|
client.send({ type: "chat.ask", qid, text: asked2.question, ...images.length ? { images } : {} });
|
|
17185
17179
|
kept.asked.push(asked2);
|
|
17186
|
-
if (images.length) sentAsk.current = { qid, taken:
|
|
17180
|
+
if (images.length) sentAsk.current = { qid, taken: chips2.clear(), text: asked2.question };
|
|
17187
17181
|
if (!fromHistory) setDraft("");
|
|
17188
17182
|
return true;
|
|
17189
17183
|
};
|
|
@@ -17192,21 +17186,13 @@ function Ask() {
|
|
|
17192
17186
|
const turn = d.chat.find((x) => x.qid === card2.qid);
|
|
17193
17187
|
if (!turn) return;
|
|
17194
17188
|
if (card2.kind === "task") {
|
|
17195
|
-
const row2 = card2.rows
|
|
17196
|
-
const c = turn.tasks[r];
|
|
17197
|
-
return !c.to.startsWith("@") || c.team || turn.team?.teamId;
|
|
17198
|
-
});
|
|
17199
|
-
if (row2 === void 0) {
|
|
17200
|
-
toast({ text: t.ask.waitTeam, tone: "info" });
|
|
17201
|
-
return;
|
|
17202
|
-
}
|
|
17189
|
+
const row2 = card2.rows[0];
|
|
17203
17190
|
setBusy({ qid: card2.qid, turn, errorSeq: d.errors.at(-1)?.seq ?? 0, at: Date.now() });
|
|
17204
17191
|
client.send({ type: "task.cmd", rid: randomUUID2(), by: LEDGE_GIVER, op: "give", qid: card2.qid, row: row2 });
|
|
17205
17192
|
return;
|
|
17206
17193
|
}
|
|
17207
17194
|
setBusy({ qid: card2.qid, turn, errorSeq: d.errors.at(-1)?.seq ?? 0, at: Date.now() });
|
|
17208
|
-
if (card2.kind === "
|
|
17209
|
-
else if (card2.kind === "launch") {
|
|
17195
|
+
if (card2.kind === "launch") {
|
|
17210
17196
|
const first = proposalRows(turn)[card2.rows[0]];
|
|
17211
17197
|
client.send({ type: "session.launch", tool: first.tool, cwd: first.cwd, ...first.prompt ? { prompt: first.prompt } : {}, qid: card2.qid, rows: card2.rows });
|
|
17212
17198
|
} else if (card2.kind === "relay") client.send({ type: turn.relay?.status === "queued" ? "session.relay.cancel" : "session.relay", qid: card2.qid });
|
|
@@ -17221,7 +17207,7 @@ function Ask() {
|
|
|
17221
17207
|
const actionKey = (qid, input, key) => {
|
|
17222
17208
|
const turn = d.chat.find((x) => x.qid === qid);
|
|
17223
17209
|
if (!turn?.actions) return false;
|
|
17224
|
-
const p =
|
|
17210
|
+
const p = planOf2(turn);
|
|
17225
17211
|
const sel = selectedRow(p, rowOf2[qid]);
|
|
17226
17212
|
const ask3 = (rows) => {
|
|
17227
17213
|
if (rows.some((i) => p.rows[i].risk === "destructive")) setConfirming({ qid, rows });
|
|
@@ -17313,7 +17299,7 @@ function Ask() {
|
|
|
17313
17299
|
return;
|
|
17314
17300
|
}
|
|
17315
17301
|
if ((key.backspace || key.delete) && l.focus === -1 && l.draft === "") {
|
|
17316
|
-
|
|
17302
|
+
chips2.removeLast();
|
|
17317
17303
|
return;
|
|
17318
17304
|
}
|
|
17319
17305
|
if (key.meta && input === "o" && l.turnImages.length) {
|
|
@@ -17373,11 +17359,6 @@ function Ask() {
|
|
|
17373
17359
|
act(cards[focus]);
|
|
17374
17360
|
return true;
|
|
17375
17361
|
}
|
|
17376
|
-
if (input === "s" && cards[focus].kind === "team") {
|
|
17377
|
-
const team = d.chat.find((x) => x.qid === cards[focus].qid)?.team;
|
|
17378
|
-
if (team && !team.template && !team.savedPath) client.send({ type: "team.save", rid: randomUUID2(), qid: cards[focus].qid, name: team.name, seats: team.seats.map((x) => ({ role: x.role, tool: x.tool, ...x.model ? { model: x.model } : {}, ...x.effort ? { effort: x.effort } : {}, ...x.name ? { name: x.name } : {} })) });
|
|
17379
|
-
return true;
|
|
17380
|
-
}
|
|
17381
17362
|
if (key.escape) {
|
|
17382
17363
|
setFocus(-1);
|
|
17383
17364
|
return true;
|
|
@@ -17391,23 +17372,23 @@ function Ask() {
|
|
|
17391
17372
|
const turn = d.chat.find((x) => x.qid === qid);
|
|
17392
17373
|
if (!turn?.actions) return [];
|
|
17393
17374
|
if (confirming?.qid === qid) return [["y", t.keys.apply], ["esc", t.keys.cancel]];
|
|
17394
|
-
const p =
|
|
17375
|
+
const p = planOf2(turn);
|
|
17395
17376
|
const sel = selectedRow(p, rowOf2[qid]);
|
|
17396
17377
|
const r = p.rows[sel], s = p.shown[sel], many = p.rows.length > 1;
|
|
17397
|
-
const
|
|
17398
|
-
if (s === "cut") return [["n", t.keys.deny], ["o", t.keys.openSession(r.target ?? "")], ["esc", t.keys.ignore],
|
|
17399
|
-
if (!p.open.length) return [
|
|
17378
|
+
const next3 = ["tab", focus + 1 < cards.length ? t.keys.nextCard : t.keys.conversation];
|
|
17379
|
+
if (s === "cut") return [["n", t.keys.deny], ["o", t.keys.openSession(r.target ?? "")], ["esc", t.keys.ignore], next3, ["ctrl+n", t.keys.newChat]];
|
|
17380
|
+
if (!p.open.length) return [next3, ["ctrl+n", t.keys.newChat], ["esc", t.keys.back]];
|
|
17400
17381
|
return [
|
|
17401
17382
|
["\u21B5", many ? t.keys.applyRow : t.keys.apply],
|
|
17402
17383
|
...many ? [["a", t.keys.applyAll], ["\u2191 \u2193", t.keys.line]] : [],
|
|
17403
17384
|
...deniable(r, s) ? [["n", t.keys.deny]] : [],
|
|
17404
17385
|
["esc", t.keys.ignore],
|
|
17405
|
-
|
|
17386
|
+
next3,
|
|
17406
17387
|
["ctrl+n", t.keys.newChat]
|
|
17407
17388
|
];
|
|
17408
17389
|
};
|
|
17409
17390
|
const history = askHistory(d.chat, kept.asked);
|
|
17410
|
-
const keys = confirm ? [["n esc", t.keys.keep], ["y", t.keys.wipe]] : focus === -1 && browsing ? [["\u21B5", t.keys.resend], ["\u2191 \u2193", t.keys.history], ["esc", t.keys.backToDraft]] : focus === -1 ? [["\u21B5", t.keys.sendOnly], ...review$, ["alt+\u21B5", t.keys.newLine], ["esc", t.keys.back], ["PgUp PgDn", t.keys.scroll], ["\u2191 \u2193", t.keys.history], ["tab", cards.length ? t.keys.nextCard : t.keys.conversation], ["alt+v", t.keys.image], ...turnImages.length ? [["alt+o", t.keys.openImage]] : [], ["ctrl+n", t.keys.newChat], ...stop] : focus === CONVO ? [["j k", t.keys.line], ["PgUp PgDn", t.keys.page], ["G", t.keys.end], ...stop, ["tab", t.keys.question], ["esc", t.keys.question]] : card?.kind === "action" ? [...actionKeys(card.qid), ...stop, ...review$] : [["\u21B5", t.keys.send], ["tab", focus + 1 < cards.length ? t.keys.nextCard : t.keys.conversation],
|
|
17391
|
+
const keys = confirm ? [["n esc", t.keys.keep], ["y", t.keys.wipe]] : focus === -1 && browsing ? [["\u21B5", t.keys.resend], ["\u2191 \u2193", t.keys.history], ["esc", t.keys.backToDraft]] : focus === -1 ? [["\u21B5", t.keys.sendOnly], ...review$, ["alt+\u21B5", t.keys.newLine], ["esc", t.keys.back], ["PgUp PgDn", t.keys.scroll], ["\u2191 \u2193", t.keys.history], ["tab", cards.length ? t.keys.nextCard : t.keys.conversation], ["alt+v", t.keys.image], ...turnImages.length ? [["alt+o", t.keys.openImage]] : [], ["ctrl+n", t.keys.newChat], ...stop] : focus === CONVO ? [["j k", t.keys.line], ["PgUp PgDn", t.keys.page], ["G", t.keys.end], ...stop, ["tab", t.keys.question], ["esc", t.keys.question]] : card?.kind === "action" ? [...actionKeys(card.qid), ...stop, ...review$] : [["\u21B5", t.keys.send], ["tab", focus + 1 < cards.length ? t.keys.nextCard : t.keys.conversation], ["ctrl+n", t.keys.newChat], ...stop, ["esc", t.keys.back]];
|
|
17411
17392
|
const foot = up > 0 ? asking && live?.qid === asking.qid ? t.ask.answering : t.session.scrolled(lines.length - view - up, up) : lines.length > view ? focus === CONVO ? t.session.above(lines.length - view) : t.ask.above(lines.length - view) : void 0;
|
|
17412
17393
|
const reading = focus === CONVO;
|
|
17413
17394
|
return /* @__PURE__ */ jsxs11(Frame, { crumb: `${t.tabs.ask}`, keys, kept: draft !== "", children: [
|
|
@@ -17426,7 +17407,7 @@ function Ask() {
|
|
|
17426
17407
|
cards.map((c, i) => {
|
|
17427
17408
|
const turn = d.chat.find((x) => x.qid === c.qid);
|
|
17428
17409
|
if (c.kind !== "action") return /* @__PURE__ */ jsx15(CardBox, { card: c, turn, focused: i === focus, busy: busy?.qid === c.qid }, `${c.kind}:${c.qid}`);
|
|
17429
|
-
const p =
|
|
17410
|
+
const p = planOf2(turn);
|
|
17430
17411
|
const sel = selectedRow(p, rowOf2[c.qid]);
|
|
17431
17412
|
return /* @__PURE__ */ jsx15(ActionBox, { turn, plan: p, focused: i === focus, busy: busy?.qid === c.qid, sel, confirming: confirming?.qid === c.qid ? confirming.rows : null }, `action:${c.qid}`);
|
|
17432
17413
|
}),
|
|
@@ -17440,7 +17421,7 @@ function Ask() {
|
|
|
17440
17421
|
/* @__PURE__ */ jsx15(Button, { label: t.ask.wipe, k: "y" })
|
|
17441
17422
|
] })
|
|
17442
17423
|
] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
17443
|
-
/* @__PURE__ */ jsx15(ChipsLine, { chips:
|
|
17424
|
+
/* @__PURE__ */ jsx15(ChipsLine, { chips: chips2.items }),
|
|
17444
17425
|
/* @__PURE__ */ jsx15(
|
|
17445
17426
|
Field,
|
|
17446
17427
|
{
|
|
@@ -17463,46 +17444,8 @@ function Ask() {
|
|
|
17463
17444
|
function CardBox({ card, turn, focused, busy }) {
|
|
17464
17445
|
const { t, g } = useTui();
|
|
17465
17446
|
const color2 = focused ? C.coral : C.line;
|
|
17466
|
-
if (card.kind === "team") {
|
|
17467
|
-
const team = turn.team;
|
|
17468
|
-
const auto = team.seats.filter((x) => x.autonomy === "auto").map((x) => `@${x.role}`);
|
|
17469
|
-
return /* @__PURE__ */ jsxs11(TitledBox, { title: t.ask.teamCard(team.name), flexShrink: 0, color: color2, titleColor: C.coral, children: [
|
|
17470
|
-
/* @__PURE__ */ jsxs11(Text12, { wrap: "truncate", children: [
|
|
17471
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.dim, children: t.ask.folder.padEnd(13) }),
|
|
17472
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.faint, children: team.cwd })
|
|
17473
|
-
] }),
|
|
17474
|
-
/* @__PURE__ */ jsxs11(Text12, { wrap: "truncate", children: [
|
|
17475
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.dim, children: t.ask.table.padEnd(13) }),
|
|
17476
|
-
g.team,
|
|
17477
|
-
" ",
|
|
17478
|
-
t.ask.newTable(team.projectName ?? team.project)
|
|
17479
|
-
] }),
|
|
17480
|
-
team.seats.map((x) => /* @__PURE__ */ jsxs11(Text12, { wrap: "truncate", children: [
|
|
17481
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.dim, children: "".padEnd(13) }),
|
|
17482
|
-
/* @__PURE__ */ jsxs11(Text12, { color: C.violet, children: [
|
|
17483
|
-
"@",
|
|
17484
|
-
x.role
|
|
17485
|
-
] }),
|
|
17486
|
-
" ",
|
|
17487
|
-
x.label,
|
|
17488
|
-
" ",
|
|
17489
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.faint, children: [TOOL_NAME[x.tool], x.model, x.effort].filter(Boolean).join(" \xB7 ") }),
|
|
17490
|
-
" ",
|
|
17491
|
-
/* @__PURE__ */ jsx15(Text12, { color: x.autonomy === "auto" ? C.yellow : C.faint, children: t.ask.autonomy[x.autonomy ?? "ask"] })
|
|
17492
|
-
] }, x.role)),
|
|
17493
|
-
auto.length ? /* @__PURE__ */ jsx15(Text12, { color: C.yellow, wrap: "truncate", children: t.ask.autoWarning(auto.join(", ")) }) : null,
|
|
17494
|
-
team.error ? /* @__PURE__ */ jsx15(Text12, { color: C.red, wrap: "truncate", children: team.error }) : null,
|
|
17495
|
-
team.saveError && !team.savedPath ? /* @__PURE__ */ jsx15(Text12, { color: C.red, wrap: "truncate", children: team.saveError }) : null,
|
|
17496
|
-
/* @__PURE__ */ jsxs11(Box12, { columnGap: 2, children: [
|
|
17497
|
-
/* @__PURE__ */ jsx15(Button, { label: busy ? `${g.live} ${t.ask.launchTeam}` : t.ask.launchTeam, k: "\u21B5", primary: focused }),
|
|
17498
|
-
!team.template ? team.savedPath ? /* @__PURE__ */ jsx15(Text12, { color: C.faint, children: t.ask.saved }) : /* @__PURE__ */ jsx15(Button, { label: t.ask.save, k: "s" }) : null,
|
|
17499
|
-
/* @__PURE__ */ jsx15(Text12, { color: C.faint, children: t.ask.nothingWithoutYou })
|
|
17500
|
-
] })
|
|
17501
|
-
] });
|
|
17502
|
-
}
|
|
17503
17447
|
if (card.kind === "task") {
|
|
17504
17448
|
const tasks = turn.tasks;
|
|
17505
|
-
const waits = !!turn.team && !turn.team.teamId;
|
|
17506
17449
|
return /* @__PURE__ */ jsxs11(TitledBox, { title: t.ask.taskCard, flexShrink: 0, color: color2, titleColor: C.violet, children: [
|
|
17507
17450
|
card.rows.map((r) => {
|
|
17508
17451
|
const c = tasks[r];
|
|
@@ -17516,10 +17459,7 @@ function CardBox({ card, turn, focused, busy }) {
|
|
|
17516
17459
|
] }) : null
|
|
17517
17460
|
] }, r);
|
|
17518
17461
|
}),
|
|
17519
|
-
/* @__PURE__ */
|
|
17520
|
-
/* @__PURE__ */ jsx15(Button, { label: busy ? `${g.live} ${t.ask.give}` : t.ask.give, k: "\u21B5", primary: focused && !waits }),
|
|
17521
|
-
waits ? /* @__PURE__ */ jsx15(Text12, { color: C.faint, children: t.ask.waitTeam }) : null
|
|
17522
|
-
] })
|
|
17462
|
+
/* @__PURE__ */ jsx15(Box12, { columnGap: 2, children: /* @__PURE__ */ jsx15(Button, { label: busy ? `${g.live} ${t.ask.give}` : t.ask.give, k: "\u21B5", primary: focused }) })
|
|
17523
17463
|
] });
|
|
17524
17464
|
}
|
|
17525
17465
|
if (card.kind === "launch") {
|
|
@@ -17579,7 +17519,7 @@ function CardBox({ card, turn, focused, busy }) {
|
|
|
17579
17519
|
}
|
|
17580
17520
|
|
|
17581
17521
|
// src/tui/screens/Launch.tsx
|
|
17582
|
-
import { useEffect as useEffect11, useMemo as useMemo5,
|
|
17522
|
+
import { useEffect as useEffect11, useMemo as useMemo5, useState as useState10 } from "react";
|
|
17583
17523
|
import { Box as Box13, Text as Text14, useInput as useInput6 } from "ink";
|
|
17584
17524
|
|
|
17585
17525
|
// ../fleet/src/launch.ts
|
|
@@ -17624,8 +17564,8 @@ function missingOf(f, machines) {
|
|
|
17624
17564
|
return null;
|
|
17625
17565
|
}
|
|
17626
17566
|
function previewOf(f, sessions, projectIdOf) {
|
|
17627
|
-
const
|
|
17628
|
-
const taken = sessions.filter((s) => s.state !== "exited" &&
|
|
17567
|
+
const machineOf2 = (s) => splitId(s.id)?.machine ?? s.machineId ?? "local";
|
|
17568
|
+
const taken = sessions.filter((s) => s.state !== "exited" && machineOf2(s) === f.machine).map((s) => s.name);
|
|
17629
17569
|
const seated = f.project === null ? 0 : sessions.filter((s) => projectIdOf(s) === f.project).length;
|
|
17630
17570
|
return { name: pickName(taken), seat: seated + 1 };
|
|
17631
17571
|
}
|
|
@@ -17646,9 +17586,6 @@ function launchMessage(f, name) {
|
|
|
17646
17586
|
};
|
|
17647
17587
|
}
|
|
17648
17588
|
|
|
17649
|
-
// src/tui/screens/Launch.tsx
|
|
17650
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
17651
|
-
|
|
17652
17589
|
// src/tui/ui/TextInput.tsx
|
|
17653
17590
|
import { Text as Text13, useInput as useInput5 } from "ink";
|
|
17654
17591
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
@@ -17707,25 +17644,9 @@ function ProjectChoice({ project, on }) {
|
|
|
17707
17644
|
] });
|
|
17708
17645
|
}
|
|
17709
17646
|
function Launch() {
|
|
17710
|
-
const { catalog } = useTui();
|
|
17711
|
-
const [prefill] = useState10(() => {
|
|
17712
|
-
const p = catalog.current.launch;
|
|
17713
|
-
catalog.current.launch = void 0;
|
|
17714
|
-
return p;
|
|
17715
|
-
});
|
|
17716
|
-
const [team, setTeam] = useState10(prefill?.template !== void 0);
|
|
17717
|
-
return team ? /* @__PURE__ */ jsx17(TeamLaunch, { onSession: () => setTeam(false), prefill: prefill?.template !== void 0 ? prefill : void 0 }) : /* @__PURE__ */ jsx17(SessionLaunch, { onTeam: () => setTeam(true), prefill: prefill?.template === void 0 ? prefill : void 0 });
|
|
17718
|
-
}
|
|
17719
|
-
function SessionLaunch({ onTeam, prefill }) {
|
|
17720
17647
|
const { client, d, machines, projects, t, g, toast, go, select, small } = useTui();
|
|
17721
17648
|
const list3 = projects?.projects ?? [];
|
|
17722
|
-
const
|
|
17723
|
-
const [form, setForm] = useState10(() => {
|
|
17724
|
-
const tool = prefill?.role?.tool ?? "claude";
|
|
17725
|
-
const base = withPick(launchDefaults(list3, machines, prefill?.project ? { project: prefill.project } : {}, tool), rolePick(prefill?.role, tool));
|
|
17726
|
-
const f = prefill ? withMachine(base, list3, prefill.machine) : base;
|
|
17727
|
-
return prefill?.cwd ? { ...f, repos: [prefill.cwd] } : f;
|
|
17728
|
-
});
|
|
17649
|
+
const [form, setForm] = useState10(() => launchDefaults(list3, machines, {}, "claude"));
|
|
17729
17650
|
const [field, setField] = useState10("prompt");
|
|
17730
17651
|
const [folder, setFolder] = useState10("");
|
|
17731
17652
|
const [repoAt, setRepoAt] = useState10(0);
|
|
@@ -17749,33 +17670,6 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17749
17670
|
return own4.length ? own4 : (machine?.recents ?? []).slice(0, 6).map((r) => r.cwd);
|
|
17750
17671
|
}, [project, form.machine, machine?.recents]);
|
|
17751
17672
|
const withFolder = folder.trim() ? { ...form, repos: MULTI_REPO_TOOLS.has(form.tool) ? [folder.trim(), ...form.repos.filter((r) => r !== folder.trim())] : [folder.trim()] } : form;
|
|
17752
|
-
const target = withFolder.repos[0] ?? null;
|
|
17753
|
-
const sameMachine = !!prefill?.role && withFolder.machine === prefill.machine;
|
|
17754
|
-
const readHere = sameMachine && target !== null && target === prefill.cwd;
|
|
17755
|
-
const asked2 = sameMachine && !readHere && target !== null ? `${withFolder.machine}\0${target}` : null;
|
|
17756
|
-
const [seen, setSeen] = useState10(null);
|
|
17757
|
-
useEffect11(() => {
|
|
17758
|
-
if (!asked2) return;
|
|
17759
|
-
const [machineId, cwd] = asked2.split("\0");
|
|
17760
|
-
const requestId = `tui-role-${randomUUID3()}`;
|
|
17761
|
-
const off = client.onMessage((m) => {
|
|
17762
|
-
if (m.type !== "roles.listing" || m.requestId !== requestId) return;
|
|
17763
|
-
off();
|
|
17764
|
-
const found = m.error ? null : m.roles.find((r) => r.id === prefill.role.id) ?? null;
|
|
17765
|
-
setSeen({ key: asked2, role: found });
|
|
17766
|
-
const was = prefill.role;
|
|
17767
|
-
if (found && (found.tool !== was.tool || found.model !== was.model || found.effort !== was.effort))
|
|
17768
|
-
setForm((f) => found.tool && found.tool !== f.tool ? withTool(f, found.tool, rolePick(found, found.tool)) : withPick(f, rolePick(found, f.tool)));
|
|
17769
|
-
});
|
|
17770
|
-
const timer2 = setTimeout(() => client.send({ type: "roles.list", cwd, requestId, ...machineId !== "local" ? { machineId } : {} }), 250);
|
|
17771
|
-
return () => {
|
|
17772
|
-
clearTimeout(timer2);
|
|
17773
|
-
off();
|
|
17774
|
-
};
|
|
17775
|
-
}, [asked2]);
|
|
17776
|
-
const checking = asked2 !== null && seen?.key !== asked2;
|
|
17777
|
-
const role = readHere ? prefill.role : asked2 !== null && seen?.key === asked2 ? seen.role ?? void 0 : void 0;
|
|
17778
|
-
const other = !!role && role.path !== prefill?.role?.path;
|
|
17779
17673
|
const projectIdOf = (s) => projects ? projectOf(s, projects) : null;
|
|
17780
17674
|
const drawn = useMemo5(() => previewOf(withFolder, d.sessions, projectIdOf), [form.machine, form.project, d.sessions.length]);
|
|
17781
17675
|
const [name, setName] = useState10(null);
|
|
@@ -17801,17 +17695,13 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17801
17695
|
}, [launching, d.lastLaunched, d.errors]);
|
|
17802
17696
|
const launch2 = () => {
|
|
17803
17697
|
if (launching) return;
|
|
17804
|
-
if (checking && !missing) {
|
|
17805
|
-
toast({ text: t.catalog.roleChecking(prefill.role.id), tone: "info" });
|
|
17806
|
-
return;
|
|
17807
|
-
}
|
|
17808
17698
|
if (missing) {
|
|
17809
17699
|
toast({ text: t.launch.missing[missing], tone: "info" });
|
|
17810
17700
|
setField(missing === "prompt" ? "prompt" : missing === "machine" ? "machine" : "repos");
|
|
17811
17701
|
return;
|
|
17812
17702
|
}
|
|
17813
17703
|
setLaunching({ seq: d.lastLaunched?.seq ?? 0, errorSeq: d.errors.at(-1)?.seq ?? 0, at: Date.now(), name: shownName });
|
|
17814
|
-
client.send(
|
|
17704
|
+
client.send(launchMessage(withFolder, shownName));
|
|
17815
17705
|
};
|
|
17816
17706
|
useInput6((input, key) => {
|
|
17817
17707
|
if (small && !key.escape) return;
|
|
@@ -17823,10 +17713,6 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17823
17713
|
launch2();
|
|
17824
17714
|
return;
|
|
17825
17715
|
}
|
|
17826
|
-
if (key.ctrl && input === "t") {
|
|
17827
|
-
onTeam();
|
|
17828
|
-
return;
|
|
17829
|
-
}
|
|
17830
17716
|
if (key.ctrl && input === "r") {
|
|
17831
17717
|
setName(pickName([...d.sessions.map((s) => s.name), shownName]));
|
|
17832
17718
|
return;
|
|
@@ -17852,16 +17738,16 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17852
17738
|
}
|
|
17853
17739
|
if (!by) return;
|
|
17854
17740
|
if (field === "tool") setForm((f) => {
|
|
17855
|
-
const
|
|
17856
|
-
return withTool(f,
|
|
17741
|
+
const next3 = cycle(tools, f.tool, by);
|
|
17742
|
+
return withTool(f, next3);
|
|
17857
17743
|
});
|
|
17858
17744
|
else if (field === "model") setForm((f) => withPick(f, { model: cycle(modelIds, f.model, by), effort: null }));
|
|
17859
17745
|
else if (field === "effort") setForm((f) => withPick(f, { model: f.model, effort: cycle(efforts, f.effort, by) }));
|
|
17860
17746
|
else if (field === "project") {
|
|
17861
17747
|
const ids = [...list3.map((p) => p.id), null];
|
|
17862
17748
|
setForm((f) => {
|
|
17863
|
-
const
|
|
17864
|
-
return
|
|
17749
|
+
const next3 = cycle(ids, f.project, by);
|
|
17750
|
+
return next3 === null ? { ...f, project: null, repos: [] } : withProject(f, list3, next3);
|
|
17865
17751
|
});
|
|
17866
17752
|
setRepoAt(0);
|
|
17867
17753
|
} else if (field === "machine") {
|
|
@@ -17879,43 +17765,8 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17879
17765
|
x === cur ? /* @__PURE__ */ jsx17(Text14, { color: C.fg, bold: true, children: `${g.prev} ${label(x)} ${g.next}` }) : /* @__PURE__ */ jsx17(Text14, { color: C.dim, children: label(x) }),
|
|
17880
17766
|
" "
|
|
17881
17767
|
] }, i)) });
|
|
17882
|
-
return /* @__PURE__ */ jsxs13(Frame, { crumb: t.launch.title, keys: [["tab", t.keys.nextField], ["\u2190 \u2192", t.keys.choose], [t.keys.space, t.keys.tick], ["ctrl+s", t.keys.start], ["ctrl+
|
|
17768
|
+
return /* @__PURE__ */ jsxs13(Frame, { crumb: t.launch.title, keys: [["tab", t.keys.nextField], ["\u2190 \u2192", t.keys.choose], [t.keys.space, t.keys.tick], ["ctrl+s", t.keys.start], ["ctrl+r", t.keys.redraw], ["esc", t.keys.cancel]], children: [
|
|
17883
17769
|
/* @__PURE__ */ jsxs13(TitledBox, { title: t.launch.title, flexGrow: 1, children: [
|
|
17884
|
-
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
17885
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.faint, children: " " }),
|
|
17886
|
-
/* @__PURE__ */ jsx17(Box13, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text14, { color: C.dim, children: t.launch.mode }) }),
|
|
17887
|
-
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
17888
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.coral, children: [
|
|
17889
|
-
g.radioOn,
|
|
17890
|
-
" ",
|
|
17891
|
-
t.launch.session
|
|
17892
|
-
] }),
|
|
17893
|
-
" ",
|
|
17894
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.dim, children: [
|
|
17895
|
-
g.radioOff,
|
|
17896
|
-
" ",
|
|
17897
|
-
t.launch.team
|
|
17898
|
-
] }),
|
|
17899
|
-
" ",
|
|
17900
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.faint, children: "ctrl+t" })
|
|
17901
|
-
] })
|
|
17902
|
-
] }),
|
|
17903
|
-
prefill?.role ? /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
17904
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.faint, children: " " }),
|
|
17905
|
-
/* @__PURE__ */ jsx17(Box13, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text14, { color: C.dim, children: t.catalog.role }) }),
|
|
17906
|
-
role ? /* @__PURE__ */ jsxs13(Text14, { wrap: "truncate", children: [
|
|
17907
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.violet, children: [
|
|
17908
|
-
"@",
|
|
17909
|
-
role.id
|
|
17910
|
-
] }),
|
|
17911
|
-
" ",
|
|
17912
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.fg, children: role.label }),
|
|
17913
|
-
other ? /* @__PURE__ */ jsxs13(Text14, { color: C.faint, children: [
|
|
17914
|
-
" \xB7 ",
|
|
17915
|
-
t.catalog.roleReadIn(target)
|
|
17916
|
-
] }) : null
|
|
17917
|
-
] }) : /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", color: C.faint, children: checking ? t.catalog.roleChecking(prefill.role.id) : t.catalog.roleElsewhere(prefill.role.id, prefill.cwd ?? "~/.ledge") })
|
|
17918
|
-
] }) : null,
|
|
17919
17770
|
row2("prompt", t.launch.instruction, /* @__PURE__ */ jsx17(TextInput, { value: form.prompt, onChange: (v) => setForm((f) => ({ ...f, prompt: v })), active: field === "prompt" })),
|
|
17920
17771
|
/* @__PURE__ */ jsx17(Text14, { children: " " }),
|
|
17921
17772
|
row2("tool", t.launch.agent, /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: tools.map((x) => /* @__PURE__ */ jsxs13(Text14, { color: x === form.tool ? C.coral : C.dim, children: [
|
|
@@ -17969,216 +17820,6 @@ function SessionLaunch({ onTeam, prefill }) {
|
|
|
17969
17820
|
] })
|
|
17970
17821
|
] });
|
|
17971
17822
|
}
|
|
17972
|
-
var TEAM_FIELDS = ["project", "folder", "template", "seats", "name"];
|
|
17973
|
-
var autonomyColor = (a) => ({ ask: C.faint, edits: C.dim, auto: C.yellow })[a];
|
|
17974
|
-
function TeamLaunch({ onSession, prefill }) {
|
|
17975
|
-
const { client, machines, projects, t, g, toast, go, small } = useTui();
|
|
17976
|
-
const list3 = projects?.projects ?? [];
|
|
17977
|
-
const [projectId, setProjectId] = useState10(prefill ? prefill.project : list3[0]?.id ?? null);
|
|
17978
|
-
const project = list3.find((p) => p.id === projectId);
|
|
17979
|
-
const folders = useMemo5(() => {
|
|
17980
|
-
const own4 = (project?.repos ?? []).filter((r) => r.machine === "local").map((r) => r.path);
|
|
17981
|
-
const base = own4.length ? own4 : (machines.find((m) => m.id === "local")?.recents ?? []).slice(0, 6).map((r) => r.cwd);
|
|
17982
|
-
return prefill?.cwd && projectId === prefill.project && !base.includes(prefill.cwd) ? [prefill.cwd, ...base] : base;
|
|
17983
|
-
}, [project, machines]);
|
|
17984
|
-
const [folderAt, setFolderAt] = useState10(() => Math.max(0, prefill?.cwd ? folders.indexOf(prefill.cwd) : 0));
|
|
17985
|
-
const wanted = useRef11(prefill?.template);
|
|
17986
|
-
const cwd = folders[folderAt] ?? folders[0] ?? null;
|
|
17987
|
-
const [field, setField] = useState10("template");
|
|
17988
|
-
const [defs, setDefs] = useState10(null);
|
|
17989
|
-
const [template, setTemplate] = useState10(null);
|
|
17990
|
-
const [seats, setSeats] = useState10([]);
|
|
17991
|
-
const [seatAt, setSeatAt] = useState10(0);
|
|
17992
|
-
const [name, setName] = useState10("");
|
|
17993
|
-
const [launching, setLaunching] = useState10(false);
|
|
17994
|
-
useEditing(true);
|
|
17995
|
-
useEffect11(() => {
|
|
17996
|
-
if (!cwd) {
|
|
17997
|
-
setDefs({ roles: [], templates: [] });
|
|
17998
|
-
return;
|
|
17999
|
-
}
|
|
18000
|
-
setDefs(null);
|
|
18001
|
-
const requestId = `tui-roles-${randomUUID3()}`;
|
|
18002
|
-
const off = client.onMessage((m) => {
|
|
18003
|
-
if (m.type !== "roles.listing" || m.requestId !== requestId) return;
|
|
18004
|
-
off();
|
|
18005
|
-
setDefs({ roles: m.roles, templates: m.templates });
|
|
18006
|
-
setSeats(m.roles.map((role) => ({ role, tool: role.tool ?? "claude", on: false })));
|
|
18007
|
-
const first = m.templates.find((x) => x.id === wanted.current) ?? m.templates[0];
|
|
18008
|
-
wanted.current = void 0;
|
|
18009
|
-
setTemplate(first?.id ?? null);
|
|
18010
|
-
setName((n) => n || first?.name || project?.name || "");
|
|
18011
|
-
});
|
|
18012
|
-
client.send({ type: "roles.list", cwd, requestId });
|
|
18013
|
-
return off;
|
|
18014
|
-
}, [cwd]);
|
|
18015
|
-
const tpl = defs?.templates.find((x) => x.id === template);
|
|
18016
|
-
const chosen = tpl ? tpl.seats.map((x) => {
|
|
18017
|
-
const role = defs.roles.find((r) => r.id === x.role);
|
|
18018
|
-
return { id: x.role, tool: x.tool ?? role?.tool ?? "claude", autonomy: role?.autonomy ?? "ask" };
|
|
18019
|
-
}) : seats.filter((x) => x.on).map((x) => ({ id: x.role.id, tool: x.tool, autonomy: x.role.autonomy ?? "ask" }));
|
|
18020
|
-
const auto = chosen.filter((x) => x.autonomy === "auto").map((x) => `@${x.id}`);
|
|
18021
|
-
const teamName = name.trim() || tpl?.name || project?.name || "team";
|
|
18022
|
-
const launch2 = () => {
|
|
18023
|
-
if (launching || !cwd) return;
|
|
18024
|
-
if (!chosen.length) {
|
|
18025
|
-
toast({ text: t.launch.noSeat, tone: "info" });
|
|
18026
|
-
return;
|
|
18027
|
-
}
|
|
18028
|
-
const rid = randomUUID3();
|
|
18029
|
-
setLaunching(true);
|
|
18030
|
-
const off = client.onMessage((m) => {
|
|
18031
|
-
if (m.type !== "team.launched" && m.type !== "team.failed" || m.rid !== rid) return;
|
|
18032
|
-
off();
|
|
18033
|
-
setLaunching(false);
|
|
18034
|
-
if (m.type === "team.launched") {
|
|
18035
|
-
toast({ text: t.launch.teamLaunched(m.team.name), tone: "ok" });
|
|
18036
|
-
go("overview");
|
|
18037
|
-
} else toast({ text: t.launch.teamFailed(m.reason), tone: "error" });
|
|
18038
|
-
});
|
|
18039
|
-
client.send({ type: "team.launch", rid, cwd, name: teamName, ...tpl ? { template: tpl.id } : { seats: chosen.map((x) => ({ role: x.id, tool: x.tool })) } });
|
|
18040
|
-
};
|
|
18041
|
-
const tools = ["claude", "codex", "cursor", "omp"];
|
|
18042
|
-
const templates = [...(defs?.templates ?? []).map((x) => x.id), null];
|
|
18043
|
-
useInput6((input, key) => {
|
|
18044
|
-
if (small && !key.escape) return;
|
|
18045
|
-
if (key.escape) {
|
|
18046
|
-
go("overview");
|
|
18047
|
-
return;
|
|
18048
|
-
}
|
|
18049
|
-
if (key.ctrl && input === "s") {
|
|
18050
|
-
launch2();
|
|
18051
|
-
return;
|
|
18052
|
-
}
|
|
18053
|
-
if (key.ctrl && input === "t") {
|
|
18054
|
-
onSession();
|
|
18055
|
-
return;
|
|
18056
|
-
}
|
|
18057
|
-
if (key.tab || key.downArrow || key.return) {
|
|
18058
|
-
setField((f) => cycle(TEAM_FIELDS, f, key.shift ? -1 : 1));
|
|
18059
|
-
return;
|
|
18060
|
-
}
|
|
18061
|
-
if (key.upArrow) {
|
|
18062
|
-
setField((f) => cycle(TEAM_FIELDS, f, -1));
|
|
18063
|
-
return;
|
|
18064
|
-
}
|
|
18065
|
-
if (field === "name") return;
|
|
18066
|
-
const by = key.rightArrow || input === "l" ? 1 : key.leftArrow || input === "h" ? -1 : 0;
|
|
18067
|
-
if (field === "project" && by) {
|
|
18068
|
-
const ids = list3.map((p) => p.id);
|
|
18069
|
-
if (ids.length) {
|
|
18070
|
-
setProjectId((cur) => cycle(ids, cur ?? ids[0], by));
|
|
18071
|
-
setFolderAt(0);
|
|
18072
|
-
}
|
|
18073
|
-
} else if (field === "folder" && by && folders.length) setFolderAt((i) => (i + by + folders.length) % folders.length);
|
|
18074
|
-
else if (field === "template" && by) {
|
|
18075
|
-
const next2 = cycle(templates, template, by);
|
|
18076
|
-
setTemplate(next2);
|
|
18077
|
-
const x = defs?.templates.find((y) => y.id === next2);
|
|
18078
|
-
if (x) setName(x.name);
|
|
18079
|
-
} else if (field === "seats" && !tpl) {
|
|
18080
|
-
if (input === "j") setSeatAt((i) => seats.length ? (i + 1) % seats.length : 0);
|
|
18081
|
-
else if (input === "k") setSeatAt((i) => seats.length ? (i + seats.length - 1) % seats.length : 0);
|
|
18082
|
-
else if (input === " ") setSeats((xs) => xs.map((x, i) => i === seatAt ? { ...x, on: !x.on } : x));
|
|
18083
|
-
else if (by) setSeats((xs) => xs.map((x, i) => i === seatAt ? { ...x, tool: cycle(tools, x.tool, by) } : x));
|
|
18084
|
-
}
|
|
18085
|
-
});
|
|
18086
|
-
const row2 = (f, label, value) => /* @__PURE__ */ jsxs13(Box13, { backgroundColor: field === f ? C.sel : void 0, children: [
|
|
18087
|
-
/* @__PURE__ */ jsx17(Text14, { color: field === f ? C.coral : C.faint, children: field === f ? "\u258C" : " " }),
|
|
18088
|
-
/* @__PURE__ */ jsx17(Box13, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text14, { color: C.dim, children: label }) }),
|
|
18089
|
-
/* @__PURE__ */ jsx17(Box13, { flexGrow: 1, overflow: "hidden", flexDirection: "column", children: value })
|
|
18090
|
-
] }, f);
|
|
18091
|
-
return /* @__PURE__ */ jsxs13(Frame, { crumb: t.launch.teamTitle, keys: [["tab", t.keys.nextField], ["\u2190 \u2192", t.keys.choose], [t.keys.space, t.keys.tick], ["ctrl+s", t.keys.start], ["ctrl+t", t.keys.teamMode], ["esc", t.keys.cancel]], children: [
|
|
18092
|
-
/* @__PURE__ */ jsxs13(TitledBox, { title: t.launch.teamTitle, flexGrow: 1, children: [
|
|
18093
|
-
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
18094
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.faint, children: " " }),
|
|
18095
|
-
/* @__PURE__ */ jsx17(Box13, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx17(Text14, { color: C.dim, children: t.launch.mode }) }),
|
|
18096
|
-
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
18097
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.dim, children: [
|
|
18098
|
-
g.radioOff,
|
|
18099
|
-
" ",
|
|
18100
|
-
t.launch.session
|
|
18101
|
-
] }),
|
|
18102
|
-
" ",
|
|
18103
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.coral, children: [
|
|
18104
|
-
g.radioOn,
|
|
18105
|
-
" ",
|
|
18106
|
-
t.launch.team
|
|
18107
|
-
] }),
|
|
18108
|
-
" ",
|
|
18109
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.faint, children: "ctrl+t" })
|
|
18110
|
-
] })
|
|
18111
|
-
] }),
|
|
18112
|
-
row2("project", t.launch.project, /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: list3.length === 0 ? /* @__PURE__ */ jsx17(Text14, { color: C.faint, children: t.launch.none }) : list3.map((p) => /* @__PURE__ */ jsx17(ProjectChoice, { project: p, on: p.id === projectId }, p.id)) })),
|
|
18113
|
-
row2("folder", t.launch.folder, /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: cwd ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
18114
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.fg, children: cwd }),
|
|
18115
|
-
folders.length > 1 ? /* @__PURE__ */ jsxs13(Text14, { color: C.faint, children: [
|
|
18116
|
-
" (",
|
|
18117
|
-
folderAt + 1,
|
|
18118
|
-
"/",
|
|
18119
|
-
folders.length,
|
|
18120
|
-
")"
|
|
18121
|
-
] }) : null
|
|
18122
|
-
] }) : /* @__PURE__ */ jsx17(Text14, { color: C.faint, children: t.launch.none }) })),
|
|
18123
|
-
row2("template", t.launch.template, defs === null ? /* @__PURE__ */ jsx17(Text14, { color: C.faint, children: t.launch.loadingRoles }) : /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: templates.map((x) => /* @__PURE__ */ jsxs13(Text14, { color: x === template ? C.fg : C.dim, bold: x === template, children: [
|
|
18124
|
-
x === template ? `${g.prev} ${x ?? t.launch.custom} ${g.next}` : x ?? t.launch.custom,
|
|
18125
|
-
" "
|
|
18126
|
-
] }, x ?? "-")) })),
|
|
18127
|
-
row2("seats", t.launch.seats, tpl ? /* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: chosen.map((x) => /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
18128
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.violet, children: [
|
|
18129
|
-
"@",
|
|
18130
|
-
x.id
|
|
18131
|
-
] }),
|
|
18132
|
-
" ",
|
|
18133
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.dim, children: TOOL_NAME[x.tool] }),
|
|
18134
|
-
" "
|
|
18135
|
-
] }, x.id)) }) : seats.length === 0 ? /* @__PURE__ */ jsx17(Text14, { color: C.faint, children: t.launch.noRole }) : /* @__PURE__ */ jsx17(Fragment5, { children: seats.map((x, i) => /* @__PURE__ */ jsxs13(Text14, { wrap: "truncate", backgroundColor: field === "seats" && i === seatAt ? C.line : void 0, children: [
|
|
18136
|
-
/* @__PURE__ */ jsx17(Text14, { color: x.on ? C.green : C.faint, children: x.on ? g.boxOn : g.boxOff }),
|
|
18137
|
-
" ",
|
|
18138
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.violet, children: [
|
|
18139
|
-
"@",
|
|
18140
|
-
x.role.id
|
|
18141
|
-
] }),
|
|
18142
|
-
" ",
|
|
18143
|
-
x.role.label,
|
|
18144
|
-
" ",
|
|
18145
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.dim, children: [
|
|
18146
|
-
g.prev,
|
|
18147
|
-
" ",
|
|
18148
|
-
TOOL_NAME[x.tool],
|
|
18149
|
-
" ",
|
|
18150
|
-
g.next
|
|
18151
|
-
] }),
|
|
18152
|
-
" ",
|
|
18153
|
-
/* @__PURE__ */ jsx17(Text14, { color: autonomyColor(x.role.autonomy ?? "ask"), children: t.ask.autonomy[x.role.autonomy ?? "ask"] })
|
|
18154
|
-
] }, x.role.id)) })),
|
|
18155
|
-
row2("name", t.launch.teamName, /* @__PURE__ */ jsx17(TextInput, { value: name, onChange: setName, active: field === "name", placeholder: teamName }))
|
|
18156
|
-
] }),
|
|
18157
|
-
/* @__PURE__ */ jsxs13(TitledBox, { title: t.launch.preview, color: C.coral, titleColor: C.coral, children: [
|
|
18158
|
-
/* @__PURE__ */ jsxs13(Text14, { wrap: "truncate", children: [
|
|
18159
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.coral, children: g.team }),
|
|
18160
|
-
" ",
|
|
18161
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.fg, bold: true, children: t.launch.teamPreview(teamName, project?.name ?? cwd ?? "-") })
|
|
18162
|
-
] }),
|
|
18163
|
-
/* @__PURE__ */ jsx17(Text14, { wrap: "truncate", children: chosen.map((x) => /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
18164
|
-
/* @__PURE__ */ jsxs13(Text14, { color: C.violet, children: [
|
|
18165
|
-
"@",
|
|
18166
|
-
x.id
|
|
18167
|
-
] }),
|
|
18168
|
-
" ",
|
|
18169
|
-
/* @__PURE__ */ jsx17(Text14, { color: C.dim, children: TOOL_NAME[x.tool] }),
|
|
18170
|
-
" ",
|
|
18171
|
-
/* @__PURE__ */ jsx17(Text14, { color: autonomyColor(x.autonomy), children: t.ask.autonomy[x.autonomy] }),
|
|
18172
|
-
" "
|
|
18173
|
-
] }, x.id)) }),
|
|
18174
|
-
auto.length ? /* @__PURE__ */ jsx17(Text14, { color: C.yellow, wrap: "truncate", children: t.ask.autoWarning(auto.join(", ")) }) : null,
|
|
18175
|
-
/* @__PURE__ */ jsxs13(Box13, { marginTop: 1, columnGap: 2, children: [
|
|
18176
|
-
/* @__PURE__ */ jsx17(Button, { label: launching ? t.launch.launching : t.ask.launchTeam, k: "ctrl+s", primary: true }),
|
|
18177
|
-
/* @__PURE__ */ jsx17(Button, { label: t.launch.cancel, k: "esc" })
|
|
18178
|
-
] })
|
|
18179
|
-
] })
|
|
18180
|
-
] });
|
|
18181
|
-
}
|
|
18182
17823
|
|
|
18183
17824
|
// src/tui/screens/Settings.tsx
|
|
18184
17825
|
import { useState as useState11 } from "react";
|
|
@@ -18284,7 +17925,8 @@ function Help() {
|
|
|
18284
17925
|
[t.help.field, [["\u21B5", k.sendOnly], ["alt+\u21B5 ctrl+j", k.newLine], ["\u2191 \u2193", k.lineHistory], ["ctrl \u2190 \u2192", k.word], ["ctrl+w", t.help.wordBefore], ["ctrl+u", k.clear], ["esc", k.keepAndLeave]]],
|
|
18285
17926
|
[t.help.launch, [["tab \u2191 \u2193", k.nextField], ["\u2190 \u2192", k.choose], [t.keys.space, k.tick], ["ctrl+r", t.keys.redraw], ["ctrl+s", k.start], ["esc", k.cancel]]],
|
|
18286
17927
|
[t.help.settings, [["\u2191 \u2193", k.navigate], ["\u2190 \u2192", k.change]]],
|
|
18287
|
-
[t.help.
|
|
17928
|
+
[t.help.rigLaunch, [["tab \u2191 \u2193", k.nextField], ["\u2190 \u2192", k.choose], ["- +", t.rigLaunch.count], ["m", t.rigLaunch.modelKey], ["o", t.rigLaunch.policyKey], [t.keys.space, k.tick], ["p ctrl+p", t.rigLaunch.check], ["ctrl+s", k.start], ["esc", k.cancel]]],
|
|
17929
|
+
[t.help.openrig, [["tab", t.openrig.machine], ["j k \u2191 \u2193", k.navigate], ["\u21B5", t.openrig.unfold], ["s", t.openrig.toggle], ["R", t.openrig.restart], ["\xB1 =", t.rigSeats.key], ["+", t.rigLaunch.launchKey], ["D", `${t.openrig.daemonKey} \xB7 ${t.openrig.toggle}`], ["K", `${t.openrig.kernelKey} \xB7 ${t.openrig.toggle}`], ["y n", `${t.openrig.yes} \xB7 ${t.openrig.no}`]]]
|
|
18288
17930
|
];
|
|
18289
17931
|
const lines = helpLines(groups, Math.max(20, columns - 4));
|
|
18290
17932
|
const [view, setView] = useState12(10);
|
|
@@ -18315,419 +17957,917 @@ function Help() {
|
|
|
18315
17957
|
return /* @__PURE__ */ jsx19(Frame, { crumb: t.help.title, keys: [["esc", k.back], ...maxTop ? [["j k PgUp PgDn", k.scroll]] : []], children: /* @__PURE__ */ jsx19(TitledBox, { title: t.help.title, flexGrow: 1, foot: foot || void 0, children: /* @__PURE__ */ jsx19(Lines, { lines, up: Math.max(0, below), onHeight: setView }) }) });
|
|
18316
17958
|
}
|
|
18317
17959
|
|
|
18318
|
-
// src/tui/screens/
|
|
18319
|
-
import { useEffect as
|
|
17960
|
+
// src/tui/screens/OpenRig.tsx
|
|
17961
|
+
import { useEffect as useEffect13, useRef as useRef12, useState as useState14 } from "react";
|
|
18320
17962
|
import { Box as Box16, Text as Text17 } from "ink";
|
|
18321
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
18322
17963
|
|
|
18323
|
-
// src/
|
|
18324
|
-
|
|
18325
|
-
|
|
18326
|
-
|
|
18327
|
-
|
|
18328
|
-
|
|
18329
|
-
|
|
18330
|
-
|
|
18331
|
-
const
|
|
18332
|
-
const
|
|
18333
|
-
const
|
|
18334
|
-
|
|
18335
|
-
const
|
|
18336
|
-
|
|
17964
|
+
// ../fleet/src/openrig.ts
|
|
17965
|
+
import { useCallback, useEffect as useEffect12, useRef as useRef11, useState as useState13 } from "react";
|
|
17966
|
+
var OPENRIG_POLL_MS = 5e3;
|
|
17967
|
+
var next2 = 0;
|
|
17968
|
+
function useOpenRig(client, machine, pollMs = OPENRIG_POLL_MS) {
|
|
17969
|
+
const [view, setView] = useState13({ machine, state: null });
|
|
17970
|
+
const [pending, setPending] = useState13(null);
|
|
17971
|
+
const [last, setLast] = useState13(null);
|
|
17972
|
+
const waiting = useRef11(/* @__PURE__ */ new Map());
|
|
17973
|
+
const asked2 = useRef11(null);
|
|
17974
|
+
const ask2 = useCallback(() => {
|
|
17975
|
+
if (machine === null) return;
|
|
17976
|
+
const requestId = `openrig-${++next2}`;
|
|
17977
|
+
asked2.current = requestId;
|
|
17978
|
+
client.send({ type: "openrig.status", requestId, machineId: machine });
|
|
17979
|
+
}, [client, machine]);
|
|
17980
|
+
useEffect12(() => {
|
|
17981
|
+
setView({ machine, state: null });
|
|
17982
|
+
setPending(null);
|
|
17983
|
+
setLast(null);
|
|
17984
|
+
if (machine === null) return;
|
|
17985
|
+
const off = client.onMessage((m) => {
|
|
17986
|
+
if (m.type === "openrig.state") {
|
|
17987
|
+
if ((m.machineId ?? "local") !== machine) return;
|
|
17988
|
+
if (m.requestId !== void 0 && m.requestId !== asked2.current) return;
|
|
17989
|
+
setView((v) => ({ machine, state: m.state ?? (m.error ? null : v.state), ...m.error ? { error: m.error } : {} }));
|
|
17990
|
+
} else if (m.type === "openrig.done") {
|
|
17991
|
+
const resolve = waiting.current.get(m.requestId);
|
|
17992
|
+
if (!resolve) return;
|
|
17993
|
+
waiting.current.delete(m.requestId);
|
|
17994
|
+
resolve(m);
|
|
17995
|
+
}
|
|
17996
|
+
});
|
|
17997
|
+
ask2();
|
|
17998
|
+
const timer2 = setInterval(ask2, pollMs);
|
|
17999
|
+
return () => {
|
|
18000
|
+
off();
|
|
18001
|
+
clearInterval(timer2);
|
|
18002
|
+
for (const [, r] of waiting.current) r({ type: "openrig.done", requestId: "", ok: false, commands: [], error: "cancelled" });
|
|
18003
|
+
waiting.current.clear();
|
|
18004
|
+
};
|
|
18005
|
+
}, [client, machine, ask2, pollMs]);
|
|
18006
|
+
const act = useCallback((action) => {
|
|
18007
|
+
if (machine === null) return Promise.resolve({ type: "openrig.done", requestId: "", ok: false, commands: [], error: "offline" });
|
|
18008
|
+
const requestId = `openrig-act-${++next2}`;
|
|
18009
|
+
setPending(action);
|
|
18010
|
+
setLast(null);
|
|
18011
|
+
return new Promise((resolve) => {
|
|
18012
|
+
waiting.current.set(requestId, (d) => {
|
|
18013
|
+
setPending((p) => p === action ? null : p);
|
|
18014
|
+
setLast(d);
|
|
18015
|
+
resolve(d);
|
|
18016
|
+
});
|
|
18017
|
+
client.send({ type: "openrig.act", requestId, action, machineId: machine });
|
|
18018
|
+
});
|
|
18019
|
+
}, [client, machine]);
|
|
18020
|
+
const shown = view.machine === machine ? view : { state: null };
|
|
18021
|
+
return { state: shown.state, ..."error" in shown && shown.error ? { error: shown.error } : {}, pending, last, act, refresh: ask2 };
|
|
18022
|
+
}
|
|
18023
|
+
function useRigSpecs(client, machine) {
|
|
18024
|
+
const [answer, setAnswer] = useState13(null);
|
|
18025
|
+
const [round, setRound] = useState13(0);
|
|
18026
|
+
useEffect12(() => {
|
|
18027
|
+
if (machine === null) return;
|
|
18028
|
+
const requestId = `openrig-specs-${++next2}`;
|
|
18029
|
+
setAnswer((a) => a?.machine === machine ? a : null);
|
|
18030
|
+
const off = client.onMessage((m) => {
|
|
18031
|
+
if (m.type !== "openrig.specList" || m.requestId !== requestId) return;
|
|
18032
|
+
setAnswer({ machine, specs: m.specs, ...m.error ? { error: m.error } : {} });
|
|
18033
|
+
});
|
|
18034
|
+
client.send({ type: "openrig.specs", requestId, machineId: machine });
|
|
18035
|
+
return off;
|
|
18036
|
+
}, [client, machine, round]);
|
|
18037
|
+
const reload = useCallback(() => setRound((r) => r + 1), []);
|
|
18038
|
+
if (machine === null) return { status: "idle", specs: [], reload };
|
|
18039
|
+
if (!answer || answer.machine !== machine) return { status: "loading", specs: [], reload };
|
|
18040
|
+
return { status: "ready", specs: answer.specs, ...answer.error ? { error: answer.error } : {}, reload };
|
|
18041
|
+
}
|
|
18042
|
+
function launchRig(client, machine, launch2) {
|
|
18043
|
+
const requestId = `openrig-launch-${++next2}`;
|
|
18044
|
+
return new Promise((resolve) => {
|
|
18045
|
+
const off = client.onMessage((m) => {
|
|
18046
|
+
if (m.type !== "openrig.launched" || m.requestId !== requestId) return;
|
|
18047
|
+
off();
|
|
18048
|
+
resolve(m);
|
|
18049
|
+
});
|
|
18050
|
+
client.send({ type: "openrig.launch", requestId, launch: launch2, machineId: machine });
|
|
18337
18051
|
});
|
|
18338
|
-
|
|
18339
|
-
|
|
18340
|
-
const
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18052
|
+
}
|
|
18053
|
+
function reseatRig(client, machine, rig, seats, delegation) {
|
|
18054
|
+
const requestId = `openrig-seats-${++next2}`;
|
|
18055
|
+
return new Promise((resolve) => {
|
|
18056
|
+
const off = client.onMessage((m) => {
|
|
18057
|
+
if (m.type !== "openrig.reseated" || m.requestId !== requestId) return;
|
|
18058
|
+
off();
|
|
18059
|
+
resolve(m);
|
|
18060
|
+
});
|
|
18061
|
+
client.send({ type: "openrig.seats", requestId, machineId: machine, rig, seats, ...delegation ? { delegation } : {} });
|
|
18062
|
+
});
|
|
18063
|
+
}
|
|
18064
|
+
|
|
18065
|
+
// src/tui/model/openrig.ts
|
|
18066
|
+
var listedRigs = (s) => (s?.rigs ?? []).filter((r) => r.name !== KERNEL_RIG);
|
|
18067
|
+
var daemonUp = (s) => !!s?.installed && s.daemon.state === "running";
|
|
18068
|
+
var rigRunning = (r) => r.status === "running" || r.running > 0;
|
|
18069
|
+
function rigLook(r) {
|
|
18070
|
+
if (r.attention > 0) return "attention";
|
|
18071
|
+
if (r.status === "running") return "running";
|
|
18072
|
+
return r.running > 0 ? "starting" : "stopped";
|
|
18073
|
+
}
|
|
18074
|
+
var seatBusy = (s) => s.activity === "running" || s.work > 0;
|
|
18075
|
+
var rigToggle = (r) => rigRunning(r) ? { kind: "rig.stop", rig: r.name, snapshot: true } : { kind: "rig.start", rig: r.name };
|
|
18076
|
+
var daemonToggle = (s) => s.daemon.state === "running" ? { kind: "daemon.stop" } : { kind: "daemon.start", restore: "last" };
|
|
18077
|
+
var kernelToggle = (s) => s.kernel.state === "ready" || s.kernel.state === "starting" ? { kind: "kernel.stop" } : { kind: "kernel.start" };
|
|
18078
|
+
var asksFirst = (a) => a.kind.endsWith(".stop") || a.kind.endsWith(".restart");
|
|
18079
|
+
function busySeats(s, a) {
|
|
18080
|
+
const of = (r) => (r?.nodes ?? []).filter(seatBusy);
|
|
18081
|
+
if (a.kind === "rig.stop" || a.kind === "rig.restart") return of(s.rigs.find((r) => r.name === a.rig)).map((n) => n.logicalId);
|
|
18082
|
+
if (a.kind === "kernel.stop" || a.kind === "kernel.restart") return of(s.rigs.find((r) => r.name === KERNEL_RIG)).map((n) => n.logicalId);
|
|
18083
|
+
if (a.kind === "daemon.stop" || a.kind === "daemon.restart") return s.rigs.flatMap((r) => of(r).map((n) => `${r.name} \xB7 ${n.logicalId}`));
|
|
18084
|
+
return [];
|
|
18085
|
+
}
|
|
18086
|
+
var commandsOf = (a) => rigCommands(a).map(showRigCommand);
|
|
18087
|
+
var confirmOf = (s, a) => ({ action: a, busy: busySeats(s, a), commands: commandsOf(a) });
|
|
18088
|
+
var step2 = (at, by, n) => n ? (at + by + n) % n : 0;
|
|
18089
|
+
function keepRig(rigs, at, id) {
|
|
18090
|
+
const found = id ? rigs.findIndex((r) => r.id === id) : -1;
|
|
18091
|
+
return found >= 0 ? found : Math.max(0, Math.min(at, rigs.length - 1));
|
|
18092
|
+
}
|
|
18093
|
+
|
|
18094
|
+
// src/tui/model/rigSeats.ts
|
|
18095
|
+
var canReseat = (r) => !!r && rigRunning(r) && r.nodes.length > 0;
|
|
18096
|
+
function seatRows(r) {
|
|
18097
|
+
const byId = new Map(r.nodes.map((n) => [n.logicalId, n]));
|
|
18098
|
+
return [...seatsByRole(r.nodes)].map(([role, seats]) => ({ role, seats, first: byId.get(seats[0]) }));
|
|
18099
|
+
}
|
|
18100
|
+
var countsOf = (rows) => Object.fromEntries(rows.map((r) => [r.role, r.seats.length]));
|
|
18101
|
+
var withCount = (counts, role, by) => ({ ...counts, [role]: Math.max(0, Math.min(9, (counts[role] ?? 0) + by)) });
|
|
18102
|
+
var changedCounts = (rows, counts) => Object.fromEntries(rows.filter((r) => (counts[r.role] ?? r.seats.length) !== r.seats.length).map((r) => [r.role, counts[r.role]]));
|
|
18103
|
+
var planOf = (r, rows, counts) => seatPlan(r.nodes, changedCounts(rows, counts));
|
|
18104
|
+
function chips(row2, plan) {
|
|
18105
|
+
const removed = new Set(plan.remove);
|
|
18344
18106
|
return [
|
|
18345
|
-
...
|
|
18346
|
-
|
|
18347
|
-
if (seen.has(k)) return false;
|
|
18348
|
-
seen.add(k);
|
|
18349
|
-
return true;
|
|
18350
|
-
}).map((x) => ({ cwd: x.cwd, machine: x.machine, label: label(x) })),
|
|
18351
|
-
{ cwd: null, machine: "local", label: o.homeOnly }
|
|
18107
|
+
...row2.seats.map((id) => ({ id, kind: removed.has(id) ? "removed" : "kept" })),
|
|
18108
|
+
...plan.add.filter((a) => a.role === row2.role).map((a) => ({ id: a.id, kind: "added" }))
|
|
18352
18109
|
];
|
|
18353
18110
|
}
|
|
18354
|
-
|
|
18355
|
-
const
|
|
18356
|
-
|
|
18357
|
-
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18111
|
+
var busyRemovals = (r, plan) => plan.remove.filter((id) => {
|
|
18112
|
+
const n = r.nodes.find((x) => x.logicalId === id);
|
|
18113
|
+
return !!n && seatBusy(n);
|
|
18114
|
+
});
|
|
18115
|
+
function previewCommands(rig, plan, links) {
|
|
18116
|
+
if (!plan.add.length && !plan.remove.length) return [];
|
|
18117
|
+
return [
|
|
18118
|
+
...plan.add.map((a) => `rig add ${rig} ${a.pod} ${a.id}`),
|
|
18119
|
+
...plan.remove.map((id) => `rig remove ${rig} ${id}`),
|
|
18120
|
+
...plan.add.length ? [`rig edge add \u2026 (${links})`] : [],
|
|
18121
|
+
`rig snapshot ${rig}`
|
|
18122
|
+
];
|
|
18363
18123
|
}
|
|
18364
|
-
var stepIndex = (length, i, by) => length ? ((i + by) % length + length) % length : 0;
|
|
18365
18124
|
|
|
18366
|
-
// src/tui/ui/
|
|
18367
|
-
import {
|
|
18368
|
-
import {
|
|
18369
|
-
|
|
18370
|
-
|
|
18371
|
-
const
|
|
18372
|
-
const
|
|
18373
|
-
const
|
|
18374
|
-
const
|
|
18375
|
-
return /* @__PURE__ */
|
|
18125
|
+
// src/tui/ui/RigSeats.tsx
|
|
18126
|
+
import { Box as Box15, Text as Text16 } from "ink";
|
|
18127
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
18128
|
+
function RigSeats({ rig, machine, rows, counts, at, delegation, plan, applying }) {
|
|
18129
|
+
const { t, g } = useTui();
|
|
18130
|
+
const s = t.rigSeats;
|
|
18131
|
+
const now2 = rows.map((r) => `${r.seats.length} ${r.role}`).join(", ");
|
|
18132
|
+
const commands = previewCommands(rig.name, plan, delegation === "pairs" ? s.linksPairs : s.linksAll);
|
|
18133
|
+
const busy = busyRemovals(rig, plan);
|
|
18134
|
+
return /* @__PURE__ */ jsxs15(TitledBox, { title: s.title(rig.name, machine), color: C.coral, titleColor: C.coral, titleBold: true, flexGrow: 1, children: [
|
|
18135
|
+
/* @__PURE__ */ jsx20(Text16, { wrap: "truncate", color: C.dim, children: s.stays(now2) }),
|
|
18136
|
+
/* @__PURE__ */ jsx20(Text16, { children: " " }),
|
|
18137
|
+
rows.map((r, i) => {
|
|
18138
|
+
const on = i === at, n = counts[r.role] ?? r.seats.length;
|
|
18139
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexShrink: 0, backgroundColor: on ? C.sel : void 0, children: [
|
|
18140
|
+
/* @__PURE__ */ jsx20(Text16, { color: on ? C.coral : C.faint, children: on ? "\u258C" : " " }),
|
|
18141
|
+
/* @__PURE__ */ jsx20(Box15, { width: 16, flexShrink: 0, children: /* @__PURE__ */ jsx20(Text16, { wrap: "truncate", color: C.fg, bold: true, children: r.role }) }),
|
|
18142
|
+
/* @__PURE__ */ jsx20(Box15, { width: 26, flexShrink: 0, children: /* @__PURE__ */ jsx20(Text16, { wrap: "truncate", color: C.dim, children: [r.first.runtime, r.first.model].filter(Boolean).join(" \xB7 ") }) }),
|
|
18143
|
+
/* @__PURE__ */ jsx20(Box15, { width: 8, flexShrink: 0, children: /* @__PURE__ */ jsxs15(Text16, { children: [
|
|
18144
|
+
/* @__PURE__ */ jsx20(Text16, { color: C.dim, children: "\u2212 " }),
|
|
18145
|
+
/* @__PURE__ */ jsx20(Text16, { color: n === r.seats.length ? C.fg : C.green, bold: true, children: n }),
|
|
18146
|
+
/* @__PURE__ */ jsx20(Text16, { color: C.dim, children: " +" })
|
|
18147
|
+
] }) }),
|
|
18148
|
+
/* @__PURE__ */ jsx20(Box15, { flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx20(Text16, { wrap: "truncate", children: chips(r, plan).map((c) => /* @__PURE__ */ jsxs15(Text16, { color: c.kind === "added" ? C.green : c.kind === "removed" ? C.red : C.dim, strikethrough: c.kind === "removed", children: [
|
|
18149
|
+
c.kind === "added" ? `+${c.id}` : c.id,
|
|
18150
|
+
" "
|
|
18151
|
+
] }, c.id)) }) })
|
|
18152
|
+
] }, r.role);
|
|
18153
|
+
}),
|
|
18154
|
+
/* @__PURE__ */ jsx20(Text16, { children: " " }),
|
|
18155
|
+
plan.add.length ? /* @__PURE__ */ jsxs15(Text16, { wrap: "truncate", children: [
|
|
18156
|
+
delegation === "pairs" ? /* @__PURE__ */ jsx20(Text16, { color: C.fg, bold: true, children: `${g.prev} ${s.pairs} ${g.next}` }) : /* @__PURE__ */ jsx20(Text16, { color: C.dim, children: s.pairs }),
|
|
18157
|
+
" ",
|
|
18158
|
+
delegation === "all" ? /* @__PURE__ */ jsx20(Text16, { color: C.fg, bold: true, children: `${g.prev} ${s.all} ${g.next}` }) : /* @__PURE__ */ jsx20(Text16, { color: C.dim, children: s.all })
|
|
18159
|
+
] }) : null,
|
|
18160
|
+
busy.map((id) => /* @__PURE__ */ jsx20(Text16, { wrap: "truncate", color: C.red, children: s.busy(id) }, id)),
|
|
18161
|
+
commands.length ? /* @__PURE__ */ jsx20(Box15, { marginTop: 1, flexDirection: "column", children: commands.map((c) => /* @__PURE__ */ jsx20(Text16, { wrap: "truncate", color: C.faint, children: c }, c)) }) : /* @__PURE__ */ jsx20(Text16, { color: C.faint, children: s.nothing }),
|
|
18162
|
+
applying ? /* @__PURE__ */ jsx20(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx20(Text16, { color: C.blue, children: s.applying }) }) : null
|
|
18163
|
+
] });
|
|
18376
18164
|
}
|
|
18377
18165
|
|
|
18378
|
-
// src/tui/screens/
|
|
18379
|
-
import {
|
|
18380
|
-
var
|
|
18381
|
-
|
|
18382
|
-
|
|
18166
|
+
// src/tui/screens/OpenRig.tsx
|
|
18167
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
18168
|
+
var LOOK = {
|
|
18169
|
+
running: { glyph: "\u25CF", color: () => C.green },
|
|
18170
|
+
starting: { glyph: "\u25CC", color: () => C.blue },
|
|
18171
|
+
attention: { glyph: "\u25B2", color: () => C.yellow },
|
|
18172
|
+
stopped: { glyph: "\u25CB", color: () => C.faint }
|
|
18173
|
+
};
|
|
18174
|
+
function question(t, a) {
|
|
18175
|
+
const w = t.openrig.what;
|
|
18176
|
+
if (a.kind === "rig.stop") return t.openrig.confirm(w["rig.stop"](a.rig));
|
|
18177
|
+
if (a.kind === "rig.restart") return t.openrig.confirm(w["rig.restart"](a.rig));
|
|
18178
|
+
if (a.kind === "daemon.stop" || a.kind === "daemon.restart" || a.kind === "kernel.stop" || a.kind === "kernel.restart") return t.openrig.confirm(w[a.kind]);
|
|
18179
|
+
return "";
|
|
18180
|
+
}
|
|
18181
|
+
function OpenRigScreen() {
|
|
18383
18182
|
const tui = useTui();
|
|
18384
|
-
const {
|
|
18385
|
-
const
|
|
18386
|
-
const
|
|
18387
|
-
const
|
|
18388
|
-
|
|
18389
|
-
const
|
|
18390
|
-
const
|
|
18391
|
-
const
|
|
18392
|
-
const [
|
|
18393
|
-
const
|
|
18394
|
-
const [
|
|
18395
|
-
const [
|
|
18396
|
-
const [
|
|
18397
|
-
const
|
|
18398
|
-
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
|
|
18402
|
-
|
|
18403
|
-
|
|
18404
|
-
|
|
18405
|
-
|
|
18406
|
-
|
|
18407
|
-
setDefs({ roles: m.roles, templates: m.templates, problems: m.problems, ...m.error ? { error: m.error } : {} });
|
|
18183
|
+
const { t, machines } = tui;
|
|
18184
|
+
const o = t.openrig;
|
|
18185
|
+
const [machineId, setMachineId] = useState14(tui.kept.rigMachine ?? null);
|
|
18186
|
+
const machine = machines.find((m) => m.id === machineId) ?? machines[0] ?? null;
|
|
18187
|
+
tui.kept.rigMachine = machine?.id ?? null;
|
|
18188
|
+
const rig = useOpenRig(tui.client, machine?.id ?? null);
|
|
18189
|
+
const state2 = rig.state;
|
|
18190
|
+
const rigs = listedRigs(state2);
|
|
18191
|
+
const [at, setAt] = useState14(0);
|
|
18192
|
+
const selectedId = useRef12(null);
|
|
18193
|
+
const [open, setOpen] = useState14(/* @__PURE__ */ new Set());
|
|
18194
|
+
const [confirm, setConfirm] = useState14(null);
|
|
18195
|
+
const [seats, setSeats] = useState14(null);
|
|
18196
|
+
const ids = rigs.map((r) => r.id).join(",");
|
|
18197
|
+
useEffect13(() => {
|
|
18198
|
+
setAt((a) => keepRig(rigs, a, selectedId.current));
|
|
18199
|
+
}, [ids]);
|
|
18200
|
+
const current2 = rigs[Math.min(at, rigs.length - 1)];
|
|
18201
|
+
selectedId.current = current2?.id ?? null;
|
|
18202
|
+
const run2 = (a) => {
|
|
18203
|
+
void rig.act(a).then((d) => {
|
|
18204
|
+
if (d.error === "cancelled") return;
|
|
18205
|
+
tui.toast(d.ok ? { text: o.done(d.commands.join(" && ")), tone: "ok" } : { text: o.failed(o.why[d.error ?? ""] ?? d.error ?? ""), tone: "error" });
|
|
18408
18206
|
});
|
|
18409
|
-
|
|
18410
|
-
|
|
18411
|
-
|
|
18412
|
-
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
|
|
18416
|
-
|
|
18417
|
-
|
|
18418
|
-
|
|
18419
|
-
|
|
18420
|
-
const
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18207
|
+
};
|
|
18208
|
+
const ask2 = (a) => {
|
|
18209
|
+
if (!state2) return;
|
|
18210
|
+
if (asksFirst(a)) setConfirm(confirmOf(state2, a));
|
|
18211
|
+
else run2(a);
|
|
18212
|
+
};
|
|
18213
|
+
const seatRig = seats ? rigs.find((r) => r.name === seats.rig) : void 0;
|
|
18214
|
+
const rows = seatRig ? seatRows(seatRig) : [];
|
|
18215
|
+
useEffect13(() => {
|
|
18216
|
+
if (seats && !seats.applying && !canReseat(seatRig)) setSeats(null);
|
|
18217
|
+
}, [seats, seatRig]);
|
|
18218
|
+
const apply = () => {
|
|
18219
|
+
if (!seats || !seatRig || !machine || seats.applying) return;
|
|
18220
|
+
const changed = changedCounts(rows, seats.counts);
|
|
18221
|
+
if (!Object.keys(changed).length) return;
|
|
18222
|
+
const adds = planOf(seatRig, rows, seats.counts).add.length > 0;
|
|
18223
|
+
setSeats((x) => x ? { ...x, applying: true } : x);
|
|
18224
|
+
void reseatRig(tui.client, machine.id, seatRig.name, changed, adds ? seats.delegation : void 0).then((r) => {
|
|
18225
|
+
if (!r.ok) {
|
|
18226
|
+
setSeats((x) => x ? { ...x, applying: false } : x);
|
|
18227
|
+
tui.toast({ text: t.rigSeats.why[r.error ?? ""] ?? r.error ?? "", tone: "error" });
|
|
18228
|
+
return;
|
|
18229
|
+
}
|
|
18230
|
+
setSeats(null);
|
|
18231
|
+
rig.refresh();
|
|
18232
|
+
const done = t.rigSeats.done(r.added.length, r.removed.length, r.links);
|
|
18233
|
+
tui.toast({ text: r.linksUnsupported ? `${done} \xB7 ${t.rigSeats.linksUnsupported}` : done, tone: r.linksUnsupported ? "info" : "ok" });
|
|
18234
|
+
});
|
|
18235
|
+
};
|
|
18433
18236
|
useScreenKeys((input, key) => {
|
|
18434
|
-
if (
|
|
18435
|
-
|
|
18237
|
+
if (seats) {
|
|
18238
|
+
if (seats.applying) return true;
|
|
18239
|
+
if (key.escape) {
|
|
18240
|
+
setSeats(null);
|
|
18241
|
+
return true;
|
|
18242
|
+
}
|
|
18243
|
+
if (key.return) {
|
|
18244
|
+
apply();
|
|
18245
|
+
return true;
|
|
18246
|
+
}
|
|
18247
|
+
if (key.upArrow || input === "k") {
|
|
18248
|
+
setSeats((x) => x ? { ...x, at: step2(x.at, -1, rows.length) } : x);
|
|
18249
|
+
return true;
|
|
18250
|
+
}
|
|
18251
|
+
if (key.downArrow || input === "j") {
|
|
18252
|
+
setSeats((x) => x ? { ...x, at: step2(x.at, 1, rows.length) } : x);
|
|
18253
|
+
return true;
|
|
18254
|
+
}
|
|
18255
|
+
const role = rows[seats.at]?.role;
|
|
18256
|
+
if (role && (input === "+" || input === "=")) {
|
|
18257
|
+
setSeats((x) => x ? { ...x, counts: withCount(x.counts, role, 1) } : x);
|
|
18258
|
+
return true;
|
|
18259
|
+
}
|
|
18260
|
+
if (role && input === "-") {
|
|
18261
|
+
setSeats((x) => x ? { ...x, counts: withCount(x.counts, role, -1) } : x);
|
|
18262
|
+
return true;
|
|
18263
|
+
}
|
|
18264
|
+
if (key.leftArrow || key.rightArrow) {
|
|
18265
|
+
setSeats((x) => x ? { ...x, delegation: x.delegation === "pairs" ? "all" : "pairs" } : x);
|
|
18266
|
+
return true;
|
|
18267
|
+
}
|
|
18436
18268
|
return true;
|
|
18437
18269
|
}
|
|
18438
|
-
if (
|
|
18439
|
-
if (
|
|
18270
|
+
if (confirm) {
|
|
18271
|
+
if (input === "y") {
|
|
18272
|
+
run2(confirm.action);
|
|
18273
|
+
setConfirm(null);
|
|
18274
|
+
return true;
|
|
18275
|
+
}
|
|
18276
|
+
if (input === "n" || key.escape) {
|
|
18277
|
+
setConfirm(null);
|
|
18278
|
+
return true;
|
|
18279
|
+
}
|
|
18440
18280
|
return true;
|
|
18441
18281
|
}
|
|
18442
|
-
if (
|
|
18443
|
-
|
|
18282
|
+
if (key.tab) {
|
|
18283
|
+
const i = Math.max(0, machines.findIndex((m) => m.id === machine?.id));
|
|
18284
|
+
setMachineId(machines[step2(i, key.shift ? -1 : 1, machines.length)]?.id ?? null);
|
|
18285
|
+
setOpen(/* @__PURE__ */ new Set());
|
|
18444
18286
|
return true;
|
|
18445
18287
|
}
|
|
18446
|
-
if (
|
|
18447
|
-
|
|
18448
|
-
setProblems(false);
|
|
18288
|
+
if (input === "+") {
|
|
18289
|
+
if (machine) tui.go("rigLaunch");
|
|
18449
18290
|
return true;
|
|
18450
18291
|
}
|
|
18451
|
-
if (
|
|
18452
|
-
|
|
18453
|
-
const next2 = order2[stepIndex(order2.length, i, input === "j" || key.downArrow ? 1 : -1)];
|
|
18454
|
-
if (next2) setAt((x) => ({ ...x, [view]: next2.key }));
|
|
18292
|
+
if (key.upArrow || input === "k") {
|
|
18293
|
+
setAt((i) => step2(i, -1, rigs.length));
|
|
18455
18294
|
return true;
|
|
18456
18295
|
}
|
|
18457
|
-
if (input === "
|
|
18458
|
-
|
|
18459
|
-
catalog.current.folder = next2.cwd;
|
|
18460
|
-
catalog.current.machine = next2.machine;
|
|
18461
|
-
setScope(next2);
|
|
18462
|
-
setProblems(false);
|
|
18296
|
+
if (key.downArrow || input === "j") {
|
|
18297
|
+
setAt((i) => step2(i, 1, rigs.length));
|
|
18463
18298
|
return true;
|
|
18464
18299
|
}
|
|
18465
|
-
if (key.return
|
|
18466
|
-
|
|
18467
|
-
|
|
18300
|
+
if (key.return) {
|
|
18301
|
+
if (current2) setOpen((s) => {
|
|
18302
|
+
const n = new Set(s);
|
|
18303
|
+
if (n.has(current2.id)) n.delete(current2.id);
|
|
18304
|
+
else n.add(current2.id);
|
|
18305
|
+
return n;
|
|
18306
|
+
});
|
|
18307
|
+
return true;
|
|
18308
|
+
}
|
|
18309
|
+
const busy = rig.pending !== null;
|
|
18310
|
+
if (input === "D") {
|
|
18311
|
+
if (state2?.installed && !busy) ask2(daemonToggle(state2));
|
|
18312
|
+
return true;
|
|
18313
|
+
}
|
|
18314
|
+
if (input === "K") {
|
|
18315
|
+
if (daemonUp(state2) && !busy) ask2(kernelToggle(state2));
|
|
18316
|
+
return true;
|
|
18317
|
+
}
|
|
18318
|
+
if (input === "O") {
|
|
18319
|
+
const op = operatorSession(state2, tui.d.sessions, machine?.id ?? "local");
|
|
18320
|
+
if (op) {
|
|
18321
|
+
tui.select(op.id);
|
|
18322
|
+
tui.go("session");
|
|
18323
|
+
} else if (daemonUp(state2)) tui.toast({ text: o.operatorNotYet, tone: "info" });
|
|
18324
|
+
return true;
|
|
18325
|
+
}
|
|
18326
|
+
if (input === "s") {
|
|
18327
|
+
if (daemonUp(state2) && current2 && !busy) ask2(rigToggle(current2));
|
|
18328
|
+
return true;
|
|
18329
|
+
}
|
|
18330
|
+
if (input === "R") {
|
|
18331
|
+
if (daemonUp(state2) && current2 && !busy) ask2({ kind: "rig.restart", rig: current2.name });
|
|
18468
18332
|
return true;
|
|
18469
18333
|
}
|
|
18470
|
-
if (input === "
|
|
18471
|
-
|
|
18472
|
-
tui.
|
|
18334
|
+
if (input === "\xB1" || input === "=") {
|
|
18335
|
+
if (!busy && canReseat(current2)) setSeats({ rig: current2.name, counts: countsOf(seatRows(current2)), at: 0, delegation: "pairs", applying: false });
|
|
18336
|
+
else if (current2) tui.toast({ text: t.rigSeats.notRunning, tone: "info" });
|
|
18473
18337
|
return true;
|
|
18474
18338
|
}
|
|
18475
18339
|
return false;
|
|
18476
18340
|
});
|
|
18477
|
-
const
|
|
18478
|
-
const
|
|
18479
|
-
|
|
18480
|
-
|
|
18481
|
-
|
|
18482
|
-
|
|
18483
|
-
|
|
18484
|
-
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
const
|
|
18488
|
-
const
|
|
18489
|
-
const
|
|
18490
|
-
const
|
|
18491
|
-
|
|
18492
|
-
/* @__PURE__ */
|
|
18493
|
-
|
|
18494
|
-
|
|
18495
|
-
|
|
18496
|
-
|
|
18497
|
-
|
|
18498
|
-
" ",
|
|
18499
|
-
r.text
|
|
18500
|
-
] }, r.key);
|
|
18501
|
-
const on = r.key === current2?.key;
|
|
18502
|
-
return /* @__PURE__ */ jsxs15(Text17, { wrap: "truncate", backgroundColor: on ? C.sel : void 0, children: [
|
|
18503
|
-
/* @__PURE__ */ jsx21(Text17, { color: on ? C.coral : C.faint, children: on ? "\u258C" : " " }),
|
|
18504
|
-
r.kind === "role" ? /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
18505
|
-
/* @__PURE__ */ jsxs15(Text17, { color: C.violet, children: [
|
|
18506
|
-
"@",
|
|
18507
|
-
fit(r.role.id, 8)
|
|
18341
|
+
const keys = seats ? [["\u2191 \u2193", t.rigSeats.role], ["- +", t.rigSeats.count], ["\u2190 \u2192", t.rigSeats.delegationKey], ["\u21B5", t.rigSeats.apply], ["esc", t.rigSeats.cancel]] : confirm ? [["y", o.yes], ["n", o.no]] : [["tab", o.machine], ["j k", t.keys.navigate], ["\u21B5", o.unfold], ["s", o.toggle], ["R", o.restart], ["\xB1 =", t.rigSeats.key], ["+", t.rigLaunch.launchKey], ["D", o.daemonKey], ["K", o.kernelKey], ["O", o.operatorKey], ["esc", t.keys.back]];
|
|
18342
|
+
const crumb = [state2?.version ? o.version(state2.version) : o.title, machine?.label].filter(Boolean).join(" \xB7 ");
|
|
18343
|
+
return /* @__PURE__ */ jsxs16(Frame, { crumb, crumbShort: o.title, keys, children: [
|
|
18344
|
+
!machine ? null : rig.error ? /* @__PURE__ */ jsx21(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx21(Text17, { color: C.yellow, children: rig.error === "offline" ? o.offline : o.outdated }) }) : !state2 ? /* @__PURE__ */ jsx21(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx21(Text17, { color: C.faint, children: o.loading }) }) : !state2.installed ? /* @__PURE__ */ jsx21(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx21(Text17, { color: C.dim, children: o.notInstalled }) }) : seats && seatRig ? /* @__PURE__ */ jsx21(RigSeats, { rig: seatRig, machine: machine.label, rows, counts: seats.counts, at: seats.at, delegation: seats.delegation, plan: planOf(seatRig, rows, seats.counts), applying: seats.applying }) : /* @__PURE__ */ jsx21(Body, { state: state2, rigs, at, open, machineLabel: machine.label }),
|
|
18345
|
+
confirm ? /* @__PURE__ */ jsx21(ConfirmBox, { confirm }) : null,
|
|
18346
|
+
rig.pending ? /* @__PURE__ */ jsx21(Box16, { paddingX: 1, height: 1, children: /* @__PURE__ */ jsx21(Text17, { wrap: "truncate", color: C.blue, children: o.running(confirmOf(state2 ?? EMPTY2, rig.pending).commands.join(" && ")) }) }) : null
|
|
18347
|
+
] });
|
|
18348
|
+
}
|
|
18349
|
+
var EMPTY2 = { installed: true, daemon: { state: "unknown" }, kernel: { state: "unknown" }, rigs: [], at: "" };
|
|
18350
|
+
function Body({ state: state2, rigs, at, open, machineLabel: machineLabel2 }) {
|
|
18351
|
+
const { t } = useTui();
|
|
18352
|
+
const o = t.openrig;
|
|
18353
|
+
const up = daemonUp(state2);
|
|
18354
|
+
const kernelColor = state2.kernel.state === "ready" ? C.green : state2.kernel.state === "starting" ? C.blue : C.faint;
|
|
18355
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", flexGrow: 1, children: [
|
|
18356
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
18357
|
+
/* @__PURE__ */ jsxs16(TitledBox, { title: `${o.daemon} \xB7 ${machineLabel2}`, flexGrow: 1, width: "50%", children: [
|
|
18358
|
+
/* @__PURE__ */ jsxs16(Text17, { wrap: "truncate", children: [
|
|
18359
|
+
/* @__PURE__ */ jsxs16(Text17, { color: up ? C.green : C.faint, children: [
|
|
18360
|
+
up ? "\u25CF " : "\u25CB ",
|
|
18361
|
+
o.daemonState[state2.daemon.state] ?? state2.daemon.state
|
|
18508
18362
|
] }),
|
|
18509
|
-
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18520
|
-
|
|
18521
|
-
|
|
18522
|
-
|
|
18523
|
-
|
|
18524
|
-
|
|
18525
|
-
|
|
18526
|
-
|
|
18527
|
-
|
|
18528
|
-
|
|
18529
|
-
|
|
18530
|
-
|
|
18531
|
-
|
|
18532
|
-
] })
|
|
18363
|
+
/* @__PURE__ */ jsxs16(Text17, { color: C.dim, children: [
|
|
18364
|
+
" ",
|
|
18365
|
+
up ? o.daemonMeta(state2.daemon.port, state2.daemon.pid) : state2.daemon.message ?? ""
|
|
18366
|
+
] })
|
|
18367
|
+
] }),
|
|
18368
|
+
/* @__PURE__ */ jsx21(Text17, { wrap: "truncate", color: C.faint, children: up ? o.restoreHint : o.stoppedDaemon })
|
|
18369
|
+
] }),
|
|
18370
|
+
/* @__PURE__ */ jsxs16(TitledBox, { title: o.kernel, flexGrow: 1, width: "50%", children: [
|
|
18371
|
+
/* @__PURE__ */ jsxs16(Text17, { wrap: "truncate", color: up ? kernelColor : C.faint, children: [
|
|
18372
|
+
state2.kernel.state === "ready" ? "\u25CF " : "\u25CB ",
|
|
18373
|
+
o.kernelState[state2.kernel.state] ?? state2.kernel.state
|
|
18374
|
+
] }),
|
|
18375
|
+
/* @__PURE__ */ jsx21(Text17, { wrap: "truncate", color: C.faint, children: o.kernelHint }),
|
|
18376
|
+
up && (state2.rigs.find((r) => r.name === "kernel")?.nodes ?? []).map((n) => /* @__PURE__ */ jsxs16(Text17, { wrap: "truncate", children: [
|
|
18377
|
+
/* @__PURE__ */ jsx21(Text17, { color: n.sessionStatus !== "running" ? C.faint : n.activity === "running" ? C.blue : C.green, children: "\u25C6 " }),
|
|
18378
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, children: n.logicalId.padEnd(16) }),
|
|
18379
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: n.runtime.padEnd(13) }),
|
|
18380
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: n.sessionStatus === "running" ? o.activity(n.activity) : n.sessionStatus }),
|
|
18381
|
+
n.logicalId === "operator.agent" && /* @__PURE__ */ jsxs16(Text17, { color: C.faint, children: [
|
|
18382
|
+
" ",
|
|
18383
|
+
o.operatorHint
|
|
18384
|
+
] })
|
|
18385
|
+
] }, n.session))
|
|
18533
18386
|
] })
|
|
18534
|
-
] })
|
|
18387
|
+
] }),
|
|
18388
|
+
/* @__PURE__ */ jsx21(TitledBox, { title: `${o.rigs} \xB7 ${rigs.length}`, flexGrow: 1, children: !up ? /* @__PURE__ */ jsx21(Text17, { color: C.faint, children: o.stoppedDaemon }) : !rigs.length ? /* @__PURE__ */ jsx21(Text17, { color: C.faint, children: o.noRigs }) : rigs.map((r, i) => /* @__PURE__ */ jsx21(RigRow, { rig: r, selected: i === at, open: open.has(r.id) }, r.id)) })
|
|
18535
18389
|
] });
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18390
|
+
}
|
|
18391
|
+
function RigRow({ rig, selected, open }) {
|
|
18392
|
+
const { t } = useTui();
|
|
18393
|
+
const o = t.openrig;
|
|
18394
|
+
const look = rigLook(rig), l = LOOK[look];
|
|
18395
|
+
const onPurpose = look === "stopped" && rig.nodes.length > 0 && rig.nodes.every((n) => n.stopped);
|
|
18396
|
+
const note = rig.attention > 0 ? { text: o.attention(rig.attention), color: C.yellow } : onPurpose ? { text: o.stoppedOnPurpose, color: C.dim } : null;
|
|
18397
|
+
const when = [rig.uptime ? o.since(rig.uptime) : "", rig.snapshot ? o.snapshot(rig.snapshot) : ""].filter(Boolean).join(" \xB7 ");
|
|
18398
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
18399
|
+
/* @__PURE__ */ jsx21(Box16, { backgroundColor: selected ? C.sel : void 0, children: /* @__PURE__ */ jsxs16(Text17, { wrap: "truncate", children: [
|
|
18400
|
+
/* @__PURE__ */ jsx21(Text17, { color: selected ? C.coral : C.faint, children: selected ? "\u258C" : " " }),
|
|
18401
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: open ? "\u25BE " : "\u25B8 " }),
|
|
18402
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, bold: true, children: rig.name.padEnd(16) }),
|
|
18403
|
+
/* @__PURE__ */ jsx21(Text17, { color: l.color(), children: ` ${l.glyph} ${o.look[look]}`.padEnd(18) }),
|
|
18404
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, children: o.seats(rig.running, rig.seats).padEnd(7) }),
|
|
18405
|
+
note ? /* @__PURE__ */ jsx21(Text17, { color: note.color, children: note.text.padEnd(34) }) : /* @__PURE__ */ jsx21(Text17, { children: "".padEnd(34) }),
|
|
18406
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: when })
|
|
18407
|
+
] }) }),
|
|
18408
|
+
open ? rig.nodes.map((n) => /* @__PURE__ */ jsxs16(Text17, { wrap: "truncate", children: [
|
|
18409
|
+
/* @__PURE__ */ jsx21(Text17, { color: seatBusy(n) ? C.blue : C.faint, children: " \u25C6 " }),
|
|
18410
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, children: n.logicalId.padEnd(18) }),
|
|
18411
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: [n.runtime, n.model].filter(Boolean).join(" \xB7 ").padEnd(26) }),
|
|
18412
|
+
/* @__PURE__ */ jsx21(Text17, { color: n.activity === "running" ? C.blue : C.dim, children: o.activity(n.activity).padEnd(12) }),
|
|
18413
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: o.work(n.work) })
|
|
18414
|
+
] }, n.logicalId)) : null
|
|
18539
18415
|
] });
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
18545
|
-
|
|
18546
|
-
|
|
18547
|
-
|
|
18548
|
-
|
|
18549
|
-
|
|
18550
|
-
|
|
18551
|
-
|
|
18552
|
-
|
|
18553
|
-
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18416
|
+
}
|
|
18417
|
+
function ConfirmBox({ confirm }) {
|
|
18418
|
+
const { t } = useTui();
|
|
18419
|
+
const o = t.openrig;
|
|
18420
|
+
return /* @__PURE__ */ jsxs16(TitledBox, { title: o.confirmTitle, color: C.coral, titleColor: C.coral, titleBold: true, double: true, children: [
|
|
18421
|
+
/* @__PURE__ */ jsx21(Text17, { wrap: "truncate", color: C.fg, bold: true, children: question(t, confirm.action) }),
|
|
18422
|
+
/* @__PURE__ */ jsx21(Text17, { wrap: "wrap", color: confirm.busy.length ? C.yellow : C.dim, children: o.busy(confirm.busy.join(", "), confirm.busy.length) }),
|
|
18423
|
+
confirm.commands.map((c) => /* @__PURE__ */ jsx21(Text17, { wrap: "truncate", color: C.faint, children: c }, c)),
|
|
18424
|
+
/* @__PURE__ */ jsxs16(Text17, { children: [
|
|
18425
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, bold: true, children: " y " }),
|
|
18426
|
+
/* @__PURE__ */ jsxs16(Text17, { color: C.dim, children: [
|
|
18427
|
+
o.yes,
|
|
18428
|
+
" "
|
|
18429
|
+
] }),
|
|
18430
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.fg, bold: true, children: " n " }),
|
|
18431
|
+
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: o.no })
|
|
18432
|
+
] })
|
|
18433
|
+
] });
|
|
18434
|
+
}
|
|
18435
|
+
function operatorSession(state2, sessions, machine) {
|
|
18436
|
+
const seat = state2?.rigs.find((r) => r.name === "kernel")?.nodes.find((n) => n.logicalId === "operator.agent")?.session;
|
|
18437
|
+
return seat ? sessions.find((x) => x.rig?.seat === seat && x.state !== "exited" && (x.machineId ?? "local") === machine) : void 0;
|
|
18438
|
+
}
|
|
18439
|
+
|
|
18440
|
+
// src/tui/screens/RigLaunch.tsx
|
|
18441
|
+
import { useEffect as useEffect14, useMemo as useMemo6, useRef as useRef13, useState as useState15 } from "react";
|
|
18442
|
+
import { Box as Box17, Text as Text18, useInput as useInput7 } from "ink";
|
|
18443
|
+
|
|
18444
|
+
// src/tui/model/rigLaunch.ts
|
|
18445
|
+
var RUNTIMES = ["claude-code", "codex"];
|
|
18446
|
+
var orderSpecs = (specs) => [...specs].sort((a, b2) => a.source === b2.source ? a.name.localeCompare(b2.name) : a.source === "user" ? -1 : b2.source === "user" ? 1 : a.source.localeCompare(b2.source));
|
|
18447
|
+
var rolesOf = (spec) => (spec?.pods ?? []).flatMap((p) => p.members.map((m) => ({ role: `${p.id}.${m.id}`, pod: p.id, member: m.id, agent: m.agent, runtime: m.runtime, ...m.model ? { model: m.model } : {}, ...m.policy ? { policy: m.policy } : {} })));
|
|
18448
|
+
var emptyForm = (spec, cwd = "") => ({ spec, cwd, name: null, seats: {}, runtimes: {}, models: {}, delegation: "pairs", save: false, policy: null, policies: {}, nonInterruptive: false });
|
|
18449
|
+
var withSpec = (f, spec) => ({ ...f, spec, seats: {}, runtimes: {}, models: {}, policies: {} });
|
|
18450
|
+
function withPolicy(f, by) {
|
|
18451
|
+
const all2 = [null, ...RIG_POLICIES];
|
|
18452
|
+
return { ...f, policy: all2[(all2.indexOf(f.policy) + by + all2.length) % all2.length] };
|
|
18453
|
+
}
|
|
18454
|
+
function withRolePolicy(f, role) {
|
|
18455
|
+
const all2 = [void 0, ...RIG_POLICIES];
|
|
18456
|
+
const next3 = all2[(all2.indexOf(f.policies[role]) + 1) % all2.length];
|
|
18457
|
+
const { [role]: _gone, ...rest } = f.policies;
|
|
18458
|
+
return { ...f, policies: next3 ? { ...rest, [role]: next3 } : rest };
|
|
18459
|
+
}
|
|
18460
|
+
var yoloChosen = (f, roles) => f.policy === "yolo" || roles.some((r) => f.policies[r.role] === "yolo");
|
|
18461
|
+
var seatsOf = (f, role) => f.seats[role] ?? 1;
|
|
18462
|
+
var withSeats = (f, role, by) => ({ ...f, seats: { ...f.seats, [role]: Math.max(0, Math.min(9, seatsOf(f, role) + by)) } });
|
|
18463
|
+
var runtimeOf = (f, r) => f.runtimes[r.role] ?? r.runtime;
|
|
18464
|
+
function withRuntime(f, r, by) {
|
|
18465
|
+
const cur = runtimeOf(f, r), i = RUNTIMES.indexOf(cur);
|
|
18466
|
+
const next3 = RUNTIMES[((i < 0 ? by > 0 ? -1 : 0 : i) + by + RUNTIMES.length) % RUNTIMES.length];
|
|
18467
|
+
const { [r.role]: _gone, ...rest } = f.runtimes;
|
|
18468
|
+
return { ...f, runtimes: next3 === r.runtime ? rest : { ...rest, [r.role]: next3 } };
|
|
18469
|
+
}
|
|
18470
|
+
var modelOf = (f, r) => f.models[r.role] ?? r.model;
|
|
18471
|
+
function withModel(f, r, model) {
|
|
18472
|
+
const { [r.role]: _gone, ...rest } = f.models;
|
|
18473
|
+
const m = model.trim();
|
|
18474
|
+
return { ...f, models: m && m !== r.model ? { ...rest, [r.role]: m } : rest };
|
|
18475
|
+
}
|
|
18476
|
+
var totalSeats = (f, roles) => roles.reduce((n, r) => n + seatsOf(f, r.role), 0);
|
|
18477
|
+
var scaled = (f, roles) => roles.some((r) => seatsOf(f, r.role) > 1);
|
|
18478
|
+
var nameOf = (f) => f.name?.trim() || f.spec || "";
|
|
18479
|
+
function missingOf2(f, roles) {
|
|
18480
|
+
if (!f.spec) return "spec";
|
|
18481
|
+
if (!f.cwd.trim()) return "cwd";
|
|
18482
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(nameOf(f))) return "name";
|
|
18483
|
+
if (totalSeats(f, roles) === 0) return "seats";
|
|
18484
|
+
return null;
|
|
18485
|
+
}
|
|
18486
|
+
function launchOf(f, roles, plan) {
|
|
18487
|
+
const seats = Object.fromEntries(roles.filter((r) => seatsOf(f, r.role) !== 1).map((r) => [r.role, seatsOf(f, r.role)]));
|
|
18488
|
+
const runtimes = Object.fromEntries(roles.filter((r) => f.runtimes[r.role]).map((r) => [r.role, f.runtimes[r.role]]));
|
|
18489
|
+
const models = Object.fromEntries(roles.filter((r) => f.models[r.role]).map((r) => [r.role, f.models[r.role]]));
|
|
18490
|
+
const policies = Object.fromEntries(roles.filter((r) => f.policies[r.role]).map((r) => [r.role, f.policies[r.role]]));
|
|
18491
|
+
return {
|
|
18492
|
+
spec: f.spec,
|
|
18493
|
+
cwd: f.cwd.trim(),
|
|
18494
|
+
name: nameOf(f),
|
|
18495
|
+
...Object.keys(seats).length ? { seats } : {},
|
|
18496
|
+
...Object.keys(runtimes).length ? { runtimes } : {},
|
|
18497
|
+
...Object.keys(models).length ? { models } : {},
|
|
18498
|
+
...f.policy ? { policy: f.policy } : {},
|
|
18499
|
+
...Object.keys(policies).length ? { policies } : {},
|
|
18500
|
+
...f.nonInterruptive && yoloChosen(f, roles) ? { nonInterruptive: true } : {},
|
|
18501
|
+
...scaled(f, roles) ? { delegation: f.delegation } : {},
|
|
18502
|
+
...f.save ? { save: true } : {},
|
|
18503
|
+
...plan ? { plan: true } : {}
|
|
18504
|
+
};
|
|
18505
|
+
}
|
|
18506
|
+
var folderChoices = (projects, machine) => (projects?.projects ?? []).flatMap((p) => p.repos.filter((r) => r.machine === machine).map((r) => ({ project: p.name, path: r.path })));
|
|
18507
|
+
function nextFolder(choices2, cwd, by) {
|
|
18508
|
+
if (!choices2.length) return cwd;
|
|
18509
|
+
const i = choices2.findIndex((c) => c.path === cwd);
|
|
18510
|
+
return choices2[i < 0 ? by > 0 ? 0 : choices2.length - 1 : (i + by + choices2.length) % choices2.length].path;
|
|
18511
|
+
}
|
|
18512
|
+
function warningLines(warnings) {
|
|
18513
|
+
const groups = /* @__PURE__ */ new Map();
|
|
18514
|
+
for (const w of warnings) {
|
|
18515
|
+
const m = /^([A-Za-z0-9_-]+\.[A-Za-z0-9_-]+):\s*(.+)$/.exec(w.trim());
|
|
18516
|
+
const key = m ? m[2] : w.trim(), who = m ? [m[1]] : [];
|
|
18517
|
+
groups.set(key, [...groups.get(key) ?? [], ...who]);
|
|
18518
|
+
}
|
|
18519
|
+
return [...groups].map(([text5, seats]) => ({ text: text5, seats }));
|
|
18520
|
+
}
|
|
18521
|
+
var fieldsOf = (roles, yolo = false) => ["spec", "cwd", "name", ...roles.map((_, i) => `role:${i}`), "policy", ...yolo ? ["nonInterruptive"] : [], "delegation", "save"];
|
|
18522
|
+
var roleAt = (field) => field.startsWith("role:") ? Number(field.slice(5)) : null;
|
|
18523
|
+
function moveField(fields, cur, by) {
|
|
18524
|
+
const i = fields.indexOf(cur);
|
|
18525
|
+
return fields[i < 0 ? 0 : (i + by + fields.length) % fields.length];
|
|
18526
|
+
}
|
|
18527
|
+
var isText = (field) => field === "cwd" || field === "name";
|
|
18528
|
+
|
|
18529
|
+
// src/tui/screens/RigLaunch.tsx
|
|
18530
|
+
import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
18531
|
+
var SPEC_ROWS = 7;
|
|
18532
|
+
var specLine = (s) => {
|
|
18533
|
+
const members = s.pods.flatMap((p) => p.members.map((m) => m.id));
|
|
18534
|
+
return `${members.slice(0, 4).join(" + ")}${members.length > 4 ? "\u2026" : ""} \xB7 ${members.length}`;
|
|
18535
|
+
};
|
|
18536
|
+
function RigLaunchScreen() {
|
|
18537
|
+
const tui = useTui();
|
|
18538
|
+
const { t, g, machines, projects, client, toast, go, small } = tui;
|
|
18539
|
+
const l = t.rigLaunch;
|
|
18540
|
+
const machine = machines.find((m) => m.id === tui.kept.rigMachine) ?? machines[0] ?? null;
|
|
18541
|
+
const machineId = machine?.id ?? null;
|
|
18542
|
+
const specsView = useRigSpecs(client, machineId);
|
|
18543
|
+
const specs = useMemo6(() => orderSpecs(specsView.specs), [specsView.specs]);
|
|
18544
|
+
const folders = useMemo6(() => folderChoices(projects, machineId), [projects, machineId]);
|
|
18545
|
+
const [form, setFormState] = useState15(() => emptyForm(null, folders[0]?.path ?? ""));
|
|
18546
|
+
const [field, setField] = useState15("spec");
|
|
18547
|
+
const [modelAt, setModelAt] = useState15(null);
|
|
18548
|
+
const [modelDraft, setModelDraft] = useState15("");
|
|
18549
|
+
const [busy, setBusy] = useState15(null);
|
|
18550
|
+
const [result, setResult] = useState15(null);
|
|
18551
|
+
const alive = useRef13(true);
|
|
18552
|
+
useEffect14(() => () => {
|
|
18553
|
+
alive.current = false;
|
|
18554
|
+
}, []);
|
|
18555
|
+
useEditing(true);
|
|
18556
|
+
const spec = specs.find((s) => s.name === form.spec);
|
|
18557
|
+
const roles = rolesOf(spec);
|
|
18558
|
+
const yolo = yoloChosen(form, roles);
|
|
18559
|
+
const fields = fieldsOf(roles, yolo);
|
|
18560
|
+
useEffect14(() => {
|
|
18561
|
+
if (!form.spec && specs[0]) setFormState((f) => withSpec(f, specs[0].name));
|
|
18562
|
+
}, [specs]);
|
|
18563
|
+
useEffect14(() => {
|
|
18564
|
+
if (!form.cwd && folders[0]) setFormState((f) => ({ ...f, cwd: folders[0].path }));
|
|
18565
|
+
}, [folders]);
|
|
18566
|
+
const setForm = (fn) => {
|
|
18567
|
+
setFormState(fn);
|
|
18568
|
+
setResult(null);
|
|
18569
|
+
};
|
|
18570
|
+
const submit = (plan) => {
|
|
18571
|
+
if (busy || !machineId) return;
|
|
18572
|
+
const missing = missingOf2(form, roles);
|
|
18573
|
+
if (missing) {
|
|
18574
|
+
toast({ text: l.missing[missing], tone: "info" });
|
|
18575
|
+
return;
|
|
18576
|
+
}
|
|
18577
|
+
setBusy(plan ? "check" : "launch");
|
|
18578
|
+
setResult(null);
|
|
18579
|
+
const launch2 = launchOf(form, roles, plan);
|
|
18580
|
+
void launchRig(client, machineId, launch2).then((r) => {
|
|
18581
|
+
if (!alive.current) return;
|
|
18582
|
+
setBusy(null);
|
|
18583
|
+
setResult(r);
|
|
18584
|
+
if (!r.ok) {
|
|
18585
|
+
toast({ text: l.why[r.error ?? ""] ?? r.error ?? "", tone: "error" });
|
|
18586
|
+
return;
|
|
18587
|
+
}
|
|
18588
|
+
if (!plan) {
|
|
18589
|
+
toast({ text: l.launched(launch2.name, r.seats ?? totalSeats(form, roles)), tone: "ok" });
|
|
18590
|
+
go("openrig");
|
|
18591
|
+
}
|
|
18592
|
+
});
|
|
18593
|
+
};
|
|
18594
|
+
const role = roleAt(field) !== null ? roles[roleAt(field)] : void 0;
|
|
18595
|
+
useInput7((input, key) => {
|
|
18596
|
+
if (small && !key.escape) return;
|
|
18597
|
+
if (busy === "launch") return;
|
|
18598
|
+
if (modelAt !== null) {
|
|
18599
|
+
if (key.tab) {
|
|
18600
|
+
const r = roles[modelAt];
|
|
18601
|
+
if (r) setForm((f) => withModel(f, r, modelDraft));
|
|
18602
|
+
setModelAt(null);
|
|
18603
|
+
}
|
|
18604
|
+
return;
|
|
18605
|
+
}
|
|
18606
|
+
if (key.escape) {
|
|
18607
|
+
go("openrig");
|
|
18608
|
+
return;
|
|
18609
|
+
}
|
|
18610
|
+
if (key.ctrl && input === "s") {
|
|
18611
|
+
submit(false);
|
|
18612
|
+
return;
|
|
18613
|
+
}
|
|
18614
|
+
if (key.ctrl && input === "p") {
|
|
18615
|
+
submit(true);
|
|
18616
|
+
return;
|
|
18617
|
+
}
|
|
18618
|
+
if (key.tab || key.downArrow) {
|
|
18619
|
+
setField((f) => moveField(fields, f, key.shift ? -1 : 1));
|
|
18620
|
+
return;
|
|
18621
|
+
}
|
|
18622
|
+
if (key.upArrow) {
|
|
18623
|
+
setField((f) => moveField(fields, f, -1));
|
|
18624
|
+
return;
|
|
18625
|
+
}
|
|
18626
|
+
const by = key.rightArrow ? 1 : key.leftArrow ? -1 : 0;
|
|
18627
|
+
if (field === "cwd" && by) {
|
|
18628
|
+
setForm((f) => ({ ...f, cwd: nextFolder(folders, f.cwd, by) }));
|
|
18629
|
+
return;
|
|
18630
|
+
}
|
|
18631
|
+
if (isText(field)) return;
|
|
18632
|
+
if (input === "p") {
|
|
18633
|
+
submit(true);
|
|
18634
|
+
return;
|
|
18635
|
+
}
|
|
18636
|
+
if (field === "spec" && by && specs.length) {
|
|
18637
|
+
const i = Math.max(0, specs.findIndex((s) => s.name === form.spec));
|
|
18638
|
+
setForm((f) => withSpec(f, specs[(i + by + specs.length) % specs.length].name));
|
|
18639
|
+
return;
|
|
18640
|
+
}
|
|
18641
|
+
if (role) {
|
|
18642
|
+
if (by) setForm((f) => withRuntime(f, role, by));
|
|
18643
|
+
else if (input === "+" || input === "=") setForm((f) => withSeats(f, role.role, 1));
|
|
18644
|
+
else if (input === "-") setForm((f) => withSeats(f, role.role, -1));
|
|
18645
|
+
else if (input === "m") {
|
|
18646
|
+
setModelAt(roleAt(field));
|
|
18647
|
+
setModelDraft(modelOf(form, role) ?? "");
|
|
18648
|
+
} else if (input === "o") setForm((f) => withRolePolicy(f, role.role));
|
|
18649
|
+
return;
|
|
18650
|
+
}
|
|
18651
|
+
if (field === "policy" && by) {
|
|
18652
|
+
setForm((f) => withPolicy(f, by));
|
|
18653
|
+
return;
|
|
18654
|
+
}
|
|
18655
|
+
if (field === "nonInterruptive" && (by || input === " " || key.return)) {
|
|
18656
|
+
setForm((f) => ({ ...f, nonInterruptive: !f.nonInterruptive }));
|
|
18657
|
+
return;
|
|
18658
|
+
}
|
|
18659
|
+
if (field === "delegation" && (by || input === " ")) {
|
|
18660
|
+
setForm((f) => ({ ...f, delegation: f.delegation === "pairs" ? "all" : "pairs" }));
|
|
18661
|
+
return;
|
|
18662
|
+
}
|
|
18663
|
+
if (field === "save" && (by || input === " " || key.return)) {
|
|
18664
|
+
setForm((f) => ({ ...f, save: !f.save }));
|
|
18665
|
+
return;
|
|
18666
|
+
}
|
|
18667
|
+
});
|
|
18668
|
+
const row2 = (f, label, value, width = 9) => /* @__PURE__ */ jsxs17(Box17, { flexShrink: 0, backgroundColor: field === f ? C.sel : void 0, children: [
|
|
18669
|
+
/* @__PURE__ */ jsx22(Text18, { color: field === f ? C.coral : C.faint, children: field === f ? "\u258C" : " " }),
|
|
18670
|
+
/* @__PURE__ */ jsx22(Box17, { width, flexShrink: 0, children: /* @__PURE__ */ jsx22(Text18, { color: C.dim, children: label }) }),
|
|
18671
|
+
/* @__PURE__ */ jsx22(Box17, { flexGrow: 1, overflow: "hidden", children: value })
|
|
18672
|
+
] }, f);
|
|
18673
|
+
const chosen = (on, text5) => on ? /* @__PURE__ */ jsx22(Text18, { color: C.fg, bold: true, children: `${g.prev} ${text5} ${g.next}` }) : /* @__PURE__ */ jsx22(Text18, { color: C.dim, children: text5 });
|
|
18674
|
+
const at = Math.max(0, specs.findIndex((s) => s.name === form.spec));
|
|
18675
|
+
const from = Math.max(0, Math.min(at - Math.floor(SPEC_ROWS / 2), specs.length - SPEC_ROWS));
|
|
18676
|
+
const folderOf2 = folders.find((f) => f.path === form.cwd);
|
|
18677
|
+
const seats = totalSeats(form, roles);
|
|
18678
|
+
const stopped = specsView.error === "daemon_stopped";
|
|
18679
|
+
const keys = modelAt !== null ? [["\u21B5", t.keys.apply], ["esc", t.keys.cancel]] : [["tab \u2191 \u2193", t.keys.nextField], ["\u2190 \u2192", t.keys.choose], ["- +", l.count], ["m", l.modelKey], ["o", l.policyKey], ["p", l.check], ["ctrl+s", l.launch(seats)], ["esc", t.keys.cancel]];
|
|
18680
|
+
return /* @__PURE__ */ jsx22(Frame, { crumb: `${l.title} \xB7 ${machine?.label ?? "-"}`, crumbShort: l.title, keys, children: /* @__PURE__ */ jsxs17(Box17, { flexGrow: 1, children: [
|
|
18681
|
+
/* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", width: "55%", flexShrink: 0, children: [
|
|
18682
|
+
/* @__PURE__ */ jsx22(TitledBox, { title: l.spec, color: field === "spec" ? C.coral : C.line, titleColor: field === "spec" ? C.coral : C.dim, flexShrink: 0, height: (specs.length ? Math.min(SPEC_ROWS, specs.length) : 2) + 2, children: specsView.status === "loading" ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: l.loading }) : stopped ? /* @__PURE__ */ jsx22(Text18, { color: C.yellow, children: l.daemonStopped }) : specsView.error ? /* @__PURE__ */ jsx22(Text18, { color: C.yellow, children: l.why[specsView.error] ?? specsView.error }) : !specs.length ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: l.noSpecs }) : specs.slice(from, from + SPEC_ROWS).map((s) => {
|
|
18683
|
+
const on = s.name === form.spec;
|
|
18684
|
+
return /* @__PURE__ */ jsx22(Box17, { flexShrink: 0, backgroundColor: on && field === "spec" ? C.sel : void 0, children: /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
18685
|
+
/* @__PURE__ */ jsxs17(Text18, { color: on ? C.coral : C.dim, children: [
|
|
18686
|
+
on ? g.radioOn : g.radioOff,
|
|
18687
|
+
" "
|
|
18688
|
+
] }),
|
|
18689
|
+
/* @__PURE__ */ jsx22(Text18, { color: on ? C.fg : C.dim, bold: on, children: s.name.padEnd(16) }),
|
|
18690
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: specLine(s).padEnd(24) }),
|
|
18691
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.faint, children: l.source[s.source] ?? s.source })
|
|
18692
|
+
] }) }, `${s.source}:${s.name}`);
|
|
18693
|
+
}) }),
|
|
18694
|
+
/* @__PURE__ */ jsxs17(TitledBox, { title: l.where, flexShrink: 0, height: folderOf2 ? 5 : 4, children: [
|
|
18695
|
+
row2("cwd", l.folder, /* @__PURE__ */ jsx22(Box17, { children: /* @__PURE__ */ jsx22(TextInput, { value: form.cwd, onChange: (v) => setForm((f) => ({ ...f, cwd: v })), active: field === "cwd" && modelAt === null, placeholder: l.folderHint }) })),
|
|
18696
|
+
folderOf2 ? /* @__PURE__ */ jsx22(Box17, { flexShrink: 0, children: /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", color: C.faint, children: [
|
|
18697
|
+
" ",
|
|
18698
|
+
g.prev,
|
|
18563
18699
|
" ",
|
|
18564
|
-
|
|
18565
|
-
"
|
|
18566
|
-
|
|
18567
|
-
|
|
18568
|
-
|
|
18569
|
-
|
|
18570
|
-
|
|
18571
|
-
|
|
18572
|
-
|
|
18700
|
+
l.projectFolder(folderOf2.project),
|
|
18701
|
+
" ",
|
|
18702
|
+
g.next
|
|
18703
|
+
] }) }) : null,
|
|
18704
|
+
row2("name", l.name, /* @__PURE__ */ jsx22(Box17, { children: /* @__PURE__ */ jsx22(TextInput, { value: form.name ?? "", onChange: (v) => setForm((f) => ({ ...f, name: v })), active: field === "name" && modelAt === null, placeholder: form.spec ?? "" }) }))
|
|
18705
|
+
] }),
|
|
18706
|
+
/* @__PURE__ */ jsxs17(TitledBox, { title: l.roles, flexGrow: 1, flexShrink: 1, children: [
|
|
18707
|
+
roles.length ? /* @__PURE__ */ jsx22(Box17, { flexShrink: 0, children: /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.faint, children: l.rolesHint }) }) : null,
|
|
18708
|
+
roles.map((r, i) => {
|
|
18709
|
+
const f = `role:${i}`, on = field === f, n = seatsOf(form, r.role);
|
|
18710
|
+
const runtime = runtimeOf(form, r), model = modelOf(form, r);
|
|
18711
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexShrink: 0, backgroundColor: on ? C.sel : void 0, children: [
|
|
18712
|
+
/* @__PURE__ */ jsx22(Text18, { color: on ? C.coral : C.faint, children: on ? "\u258C" : " " }),
|
|
18713
|
+
/* @__PURE__ */ jsx22(Box17, { width: 14, flexShrink: 0, children: /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.fg, bold: true, children: r.role }) }),
|
|
18714
|
+
/* @__PURE__ */ jsx22(Box17, { width: 16, flexShrink: 0, children: /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", children: chosen(on, runtime) }) }),
|
|
18715
|
+
/* @__PURE__ */ jsx22(Box17, { width: 7, flexShrink: 0, children: /* @__PURE__ */ jsxs17(Text18, { children: [
|
|
18716
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: "\u2212 " }),
|
|
18717
|
+
/* @__PURE__ */ jsx22(Text18, { color: n === 1 ? C.fg : C.green, bold: true, children: n }),
|
|
18718
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: " +" })
|
|
18719
|
+
] }) }),
|
|
18720
|
+
/* @__PURE__ */ jsx22(Box17, { width: 13, flexShrink: 0, children: /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: form.policies[r.role] === "yolo" ? C.red : form.policies[r.role] ? C.fg : C.faint, children: form.policies[r.role] ? l.policyOf[form.policies[r.role]] : l.asRig }) }),
|
|
18721
|
+
/* @__PURE__ */ jsx22(Box17, { flexGrow: 1, overflow: "hidden", children: modelAt === i ? /* @__PURE__ */ jsx22(TextInput, { value: modelDraft, onChange: setModelDraft, active: true, onSubmit: (v) => {
|
|
18722
|
+
setForm((x) => withModel(x, r, v));
|
|
18723
|
+
setModelAt(null);
|
|
18724
|
+
}, onEscape: () => setModelAt(null), placeholder: l.defaultModel }) : /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: model ? C.fg : C.faint, children: model ?? l.defaultModel }) })
|
|
18725
|
+
] }, r.role);
|
|
18726
|
+
})
|
|
18727
|
+
] }),
|
|
18728
|
+
/* @__PURE__ */ jsxs17(TitledBox, { title: l.permissions, flexShrink: 0, children: [
|
|
18729
|
+
row2("policy", "", /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
18730
|
+
chosen(field === "policy" || form.policy !== null, form.policy === null ? l.specPolicy(spec?.policy ?? l.noSpecPolicy) : l.policyOf[form.policy]),
|
|
18731
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.faint, children: ` ${[null, ...RIG_POLICIES].indexOf(form.policy) + 1}/${RIG_POLICIES.length + 1}` })
|
|
18732
|
+
] }), 1),
|
|
18733
|
+
/* @__PURE__ */ jsx22(Box17, { flexShrink: 0, paddingLeft: 3, children: /* @__PURE__ */ jsx22(Text18, { wrap: "wrap", color: (form.policy ?? spec?.policy?.replace(/^builtin:/, "")) === "yolo" ? C.red : C.faint, children: l.policyHint[form.policy ?? spec?.policy?.replace(/^builtin:/, "") ?? "none"] ?? l.policyHint.none }) }),
|
|
18734
|
+
yolo ? row2("nonInterruptive", "", /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
18735
|
+
/* @__PURE__ */ jsx22(Text18, { color: form.nonInterruptive ? C.red : C.faint, children: form.nonInterruptive ? g.boxOn : g.boxOff }),
|
|
18736
|
+
/* @__PURE__ */ jsxs17(Text18, { color: C.dim, children: [
|
|
18573
18737
|
" ",
|
|
18574
|
-
|
|
18575
|
-
] })
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18738
|
+
l.nonInterruptive
|
|
18739
|
+
] })
|
|
18740
|
+
] }), 1) : null
|
|
18741
|
+
] }),
|
|
18742
|
+
/* @__PURE__ */ jsxs17(TitledBox, { title: l.delegation, flexShrink: 0, height: 4, children: [
|
|
18743
|
+
row2("delegation", "", /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", children: scaled(form, roles) ? /* @__PURE__ */ jsxs17(Fragment6, { children: [
|
|
18744
|
+
chosen(form.delegation === "pairs", l.pairs),
|
|
18745
|
+
/* @__PURE__ */ jsxs17(Text18, { color: C.faint, children: [
|
|
18746
|
+
" ",
|
|
18747
|
+
l.pairsHint,
|
|
18748
|
+
" "
|
|
18749
|
+
] }),
|
|
18750
|
+
chosen(form.delegation === "all", l.all)
|
|
18751
|
+
] }) : /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: l.notScaled }) }), 1),
|
|
18752
|
+
row2("save", "", /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
18753
|
+
/* @__PURE__ */ jsx22(Text18, { color: form.save ? C.green : C.faint, children: form.save ? g.boxOn : g.boxOff }),
|
|
18754
|
+
/* @__PURE__ */ jsxs17(Text18, { color: C.dim, children: [
|
|
18755
|
+
" ",
|
|
18756
|
+
l.save,
|
|
18757
|
+
form.save ? ` : ${nameOf(form)}` : ""
|
|
18758
|
+
] })
|
|
18759
|
+
] }), 1)
|
|
18760
|
+
] })
|
|
18579
18761
|
] }),
|
|
18580
|
-
/* @__PURE__ */
|
|
18581
|
-
] }) : template ? /* @__PURE__ */ jsxs15(TitledBox, { title: `${g.team} ${template.name} \xB7 ${t.catalog.seats(template.seats.length)} \xB7 ${template.source === "repo" ? t.catalog.repo : t.catalog.home}`, color: C.coral, titleColor: C.coral, flexGrow: 1, children: [
|
|
18582
|
-
template.seats.map((s) => {
|
|
18583
|
-
const r = roleById(s.role);
|
|
18584
|
-
const tool = s.tool ?? r?.tool;
|
|
18585
|
-
return /* @__PURE__ */ jsxs15(Text17, { wrap: "truncate", children: [
|
|
18586
|
-
/* @__PURE__ */ jsxs15(Text17, { color: C.violet, children: [
|
|
18587
|
-
"@",
|
|
18588
|
-
fit(s.role, 8)
|
|
18589
|
-
] }),
|
|
18590
|
-
" ",
|
|
18591
|
-
/* @__PURE__ */ jsx21(Text17, { color: C.fg, children: fit(r?.label ?? "?", 12) }),
|
|
18592
|
-
" ",
|
|
18593
|
-
/* @__PURE__ */ jsx21(Text17, { color: s.tool ? C.blue : C.dim, children: tool ? TOOL_NAME[tool] : t.catalog.toolDefault }),
|
|
18594
|
-
s.model ? /* @__PURE__ */ jsxs15(Text17, { color: C.blue, children: [
|
|
18595
|
-
" \xB7 ",
|
|
18596
|
-
s.model
|
|
18597
|
-
] }) : r?.model ? /* @__PURE__ */ jsxs15(Text17, { color: C.dim, children: [
|
|
18598
|
-
" \xB7 ",
|
|
18599
|
-
r.model
|
|
18600
|
-
] }) : null,
|
|
18601
|
-
" ",
|
|
18602
|
-
/* @__PURE__ */ jsx21(Text17, { color: autonomyColor2(autonomy(r)), children: t.catalog.autonomyShort[autonomy(r)] })
|
|
18603
|
-
] }, s.role);
|
|
18604
|
-
}),
|
|
18605
|
-
/* @__PURE__ */ jsx21(Text17, { children: " " }),
|
|
18606
|
-
(() => {
|
|
18607
|
-
const auto = template.seats.filter((s) => roleById(s.role)?.autonomy === "auto").map((s) => `@${s.role}`);
|
|
18608
|
-
return auto.length ? /* @__PURE__ */ jsxs15(Text17, { color: C.yellow, wrap: "truncate", children: [
|
|
18609
|
-
"\u26A0 ",
|
|
18610
|
-
t.ask.autoWarning(auto.join(", "))
|
|
18611
|
-
] }) : null;
|
|
18612
|
-
})(),
|
|
18613
|
-
field(t.catalog.file, /* @__PURE__ */ jsxs15(Text17, { color: C.dim, children: [
|
|
18614
|
-
remote ? `${t.catalog.onMachine(machineLabel2)} ` : "",
|
|
18615
|
-
template.path
|
|
18616
|
-
] })),
|
|
18617
|
-
field(t.catalog.teams, (() => {
|
|
18618
|
-
const xs = teams.filter((x) => x.template === template.id && x.state !== "dissolved");
|
|
18619
|
-
return xs.length ? /* @__PURE__ */ jsx21(Text17, { children: xs.map((x) => /* @__PURE__ */ jsxs15(Text17, { children: [
|
|
18620
|
-
/* @__PURE__ */ jsxs15(Text17, { color: C.violet, children: [
|
|
18621
|
-
g.team,
|
|
18622
|
-
" ",
|
|
18623
|
-
x.name
|
|
18624
|
-
] }),
|
|
18625
|
-
" ",
|
|
18626
|
-
/* @__PURE__ */ jsx21(Text17, { color: C.dim, children: x.state === "active" ? t.catalog.active : t.catalog.resting }),
|
|
18627
|
-
" "
|
|
18628
|
-
] }, x.id)) }) : /* @__PURE__ */ jsx21(Text17, { color: C.faint, children: t.catalog.noTeam });
|
|
18629
|
-
})())
|
|
18630
|
-
] }) : /* @__PURE__ */ jsx21(TitledBox, { title: t.tabs.teams, flexGrow: 1, children: /* @__PURE__ */ jsx21(Text17, { color: C.faint, children: defs === null ? silent ? "" : t.catalog.loading : defs.error ? "" : view === "roles" ? t.catalog.noRole : t.catalog.noTemplateHere }) });
|
|
18631
|
-
const keys = [
|
|
18632
|
-
["j k", t.keys.navigate],
|
|
18633
|
-
["\u2190 \u2192", t.keys.rolesTemplates],
|
|
18634
|
-
["c", t.keys.folder],
|
|
18635
|
-
...reread ? [["r", t.keys.reread]] : [],
|
|
18636
|
-
...launchable ? [["\u21B5", view === "roles" ? t.keys.launchRole : t.keys.launchTeam]] : [],
|
|
18637
|
-
...current2 && !remote ? [["o", t.keys.openFile]] : [],
|
|
18638
|
-
...issues.length ? [["!", t.keys.ignored]] : [],
|
|
18639
|
-
["esc", t.keys.back]
|
|
18640
|
-
];
|
|
18641
|
-
return /* @__PURE__ */ jsx21(Frame, { crumb: t.tabs.teams, keys, children: /* @__PURE__ */ jsxs15(Box16, { flexGrow: 1, flexDirection: wide ? "row" : "column", children: [
|
|
18642
|
-
/* @__PURE__ */ jsx21(Box16, { flexDirection: "column", width: wide ? left2 : void 0, flexShrink: 0, flexGrow: wide ? 0 : 1, children: listBox }),
|
|
18643
|
-
/* @__PURE__ */ jsx21(Box16, { flexDirection: "column", flexGrow: 1, children: detail })
|
|
18762
|
+
/* @__PURE__ */ jsx22(Preview, { busy, result, seats })
|
|
18644
18763
|
] }) });
|
|
18645
18764
|
}
|
|
18765
|
+
function Preview({ busy, result, seats }) {
|
|
18766
|
+
const { t } = useTui();
|
|
18767
|
+
const l = t.rigLaunch;
|
|
18768
|
+
const check = result?.check;
|
|
18769
|
+
return /* @__PURE__ */ jsx22(TitledBox, { title: l.preview, flexGrow: 1, color: C.coral, titleColor: C.coral, children: busy ? /* @__PURE__ */ jsx22(Text18, { color: C.blue, children: busy === "check" ? l.checking : l.launching }) : !result ? /* @__PURE__ */ jsx22(Text18, { wrap: "wrap", color: C.faint, children: l.noCheck }) : /* @__PURE__ */ jsxs17(Fragment6, { children: [
|
|
18770
|
+
check ? check.status === "planned" && !check.errors.length ? /* @__PURE__ */ jsx22(Text18, { color: C.green, bold: true, children: l.passes(result.seats ?? seats) }) : /* @__PURE__ */ jsx22(Text18, { color: check.errors.length ? C.red : C.yellow, bold: true, children: l.planStatus(check.status) }) : null,
|
|
18771
|
+
!result.ok ? /* @__PURE__ */ jsx22(Text18, { wrap: "wrap", color: C.red, children: l.why[result.error ?? ""] ?? result.error }) : null,
|
|
18772
|
+
check?.errors.map((e, i) => /* @__PURE__ */ jsx22(Text18, { wrap: "wrap", color: C.red, children: e }, `e${i}`)),
|
|
18773
|
+
warningLines(check?.warnings ?? []).map((w, i) => /* @__PURE__ */ jsx22(Text18, { wrap: "wrap", color: C.yellow, children: l.warning(w.text, w.seats.join(", ")) }, `w${i}`)),
|
|
18774
|
+
result.commands.map((c) => /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.faint, children: c }, c)),
|
|
18775
|
+
result.yaml ? /* @__PURE__ */ jsx22(Box17, { marginTop: 1, flexDirection: "column", children: result.yaml.split("\n").map((line, i) => /* @__PURE__ */ jsx22(YamlLine, { line }, i)) }) : null
|
|
18776
|
+
] }) });
|
|
18777
|
+
}
|
|
18778
|
+
function YamlLine({ line }) {
|
|
18779
|
+
const m = /^(\s*-?\s*)([A-Za-z0-9_.-]+:)(.*)$/.exec(line);
|
|
18780
|
+
if (line.trim().startsWith("#")) return /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.faint, children: line || " " });
|
|
18781
|
+
if (!m) return /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.dim, children: line || " " });
|
|
18782
|
+
return /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
18783
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: m[1] }),
|
|
18784
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.blue, children: m[2] }),
|
|
18785
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.green, children: m[3] })
|
|
18786
|
+
] });
|
|
18787
|
+
}
|
|
18646
18788
|
|
|
18647
18789
|
// src/tui/App.tsx
|
|
18648
|
-
import { jsx as
|
|
18790
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
18649
18791
|
var TOAST_MS = 5e3;
|
|
18650
18792
|
var QUIT_MS = 2e3;
|
|
18651
18793
|
function App(props) {
|
|
18652
|
-
const [lang, setLangState] =
|
|
18653
|
-
const [theme, setThemeState] =
|
|
18794
|
+
const [lang, setLangState] = useState16(props.lang);
|
|
18795
|
+
const [theme, setThemeState] = useState16(props.theme ?? "auto");
|
|
18654
18796
|
const tone2 = toneFor(theme, props.background ?? tone());
|
|
18655
18797
|
if (tone2 !== tone()) setTone(tone2);
|
|
18656
|
-
return /* @__PURE__ */
|
|
18798
|
+
return /* @__PURE__ */ jsx23(I18nProvider, { lang, children: /* @__PURE__ */ jsx23(Shell, { ...props, lang, setLang: setLangState, theme, setThemeState, tone: tone2 }) });
|
|
18657
18799
|
}
|
|
18658
18800
|
function Shell({ client, lang, setLang: setLangState, saveLang, theme, setThemeState, tone: tone2, background, saveTheme, notify, glyphs, env, run: run2, readImage, openFile }) {
|
|
18659
18801
|
const { exit: exit3, suspendTerminal } = useApp();
|
|
18660
18802
|
const { stdout } = useStdout();
|
|
18661
|
-
const write =
|
|
18803
|
+
const write = useCallback2((seq) => {
|
|
18662
18804
|
if (seq) stdout.write(seq);
|
|
18663
18805
|
}, [stdout]);
|
|
18664
18806
|
const d = useDaemon();
|
|
18665
18807
|
const machines = useMachines(client);
|
|
18666
18808
|
const projects = useProjects(client);
|
|
18667
|
-
const teams = useTeams(client);
|
|
18668
18809
|
const tasks = useTasks(client);
|
|
18669
18810
|
const fleet = client.fleet;
|
|
18670
18811
|
const t = MESSAGES[lang];
|
|
18671
|
-
const [screen, setScreen] =
|
|
18672
|
-
const [back2, setBack] =
|
|
18673
|
-
const [selectedId, setSelectedId] =
|
|
18674
|
-
const [lastToast, setToast] =
|
|
18675
|
-
const [editing, setEditingState] =
|
|
18676
|
-
const keys =
|
|
18677
|
-
const kept =
|
|
18678
|
-
const armed =
|
|
18679
|
-
|
|
18680
|
-
useEffect13(() => {
|
|
18812
|
+
const [screen, setScreen] = useState16("overview");
|
|
18813
|
+
const [back2, setBack] = useState16("overview");
|
|
18814
|
+
const [selectedId, setSelectedId] = useState16(null);
|
|
18815
|
+
const [lastToast, setToast] = useState16(null);
|
|
18816
|
+
const [editing, setEditingState] = useState16(false);
|
|
18817
|
+
const keys = useRef14(null);
|
|
18818
|
+
const kept = useRef14({ drafts: /* @__PURE__ */ new Map(), sent: /* @__PURE__ */ new Map(), asked: [] }).current;
|
|
18819
|
+
const armed = useRef14(0);
|
|
18820
|
+
useEffect15(() => {
|
|
18681
18821
|
if (!lastToast) return;
|
|
18682
18822
|
const timer2 = setTimeout(() => setToast(null), lastToast.ms ?? TOAST_MS);
|
|
18683
18823
|
return () => clearTimeout(timer2);
|
|
18684
18824
|
}, [lastToast]);
|
|
18685
|
-
const toast =
|
|
18686
|
-
const setEditing =
|
|
18687
|
-
const view =
|
|
18688
|
-
const order2 =
|
|
18689
|
-
|
|
18825
|
+
const toast = useCallback2((x) => setToast(x), []);
|
|
18826
|
+
const setEditing = useCallback2((on) => setEditingState(on), []);
|
|
18827
|
+
const view = useMemo7(() => overview(d.sessions, projects), [d.sessions, projects]);
|
|
18828
|
+
const order2 = useRef14([]);
|
|
18829
|
+
useEffect15(() => {
|
|
18690
18830
|
setSelectedId((cur) => cur === null && view.yours[0] ? view.yours[0].id : keepSelection(view.order, cur, order2.current));
|
|
18691
18831
|
order2.current = view.order;
|
|
18692
18832
|
}, [view]);
|
|
18693
18833
|
const selected = (selectedId ? d.byId.get(selectedId) : void 0) ?? null;
|
|
18694
|
-
const seen =
|
|
18695
|
-
const titled =
|
|
18696
|
-
|
|
18834
|
+
const seen = useRef14(null);
|
|
18835
|
+
const titled = useRef14("");
|
|
18836
|
+
useEffect15(() => {
|
|
18697
18837
|
if (seen.current) for (const text5 of asked(seen.current, d.sessions, t.notify)) write(notification(text5, notify, env));
|
|
18698
18838
|
seen.current = d.byId;
|
|
18699
|
-
const
|
|
18700
|
-
if (
|
|
18701
|
-
titled.current =
|
|
18702
|
-
write(
|
|
18839
|
+
const next3 = title(t.notify.title(listed(d.sessions).filter(isPending).length + openDecisions(tasks).length));
|
|
18840
|
+
if (next3 !== titled.current) {
|
|
18841
|
+
titled.current = next3;
|
|
18842
|
+
write(next3);
|
|
18703
18843
|
}
|
|
18704
18844
|
}, [d.byId, tasks]);
|
|
18705
18845
|
const actions = useActions({ client, sessions: d.sessions, errors: d.errors, t, toast });
|
|
18706
|
-
const go =
|
|
18846
|
+
const go = useCallback2((next3) => {
|
|
18707
18847
|
setScreen((cur) => {
|
|
18708
|
-
if (
|
|
18709
|
-
return
|
|
18848
|
+
if (next3 === "help" || next3 === "settings") setBack(cur === "help" || cur === "settings" ? "overview" : cur);
|
|
18849
|
+
return next3;
|
|
18710
18850
|
});
|
|
18711
18851
|
}, []);
|
|
18712
|
-
const setLang =
|
|
18713
|
-
setLangState(
|
|
18852
|
+
const setLang = useCallback2((next3) => {
|
|
18853
|
+
setLangState(next3);
|
|
18714
18854
|
try {
|
|
18715
|
-
saveLang(
|
|
18716
|
-
toast({ text: MESSAGES[
|
|
18855
|
+
saveLang(next3);
|
|
18856
|
+
toast({ text: MESSAGES[next3].settings.saved, tone: "ok" });
|
|
18717
18857
|
} catch (e) {
|
|
18718
|
-
toast({ text: MESSAGES[
|
|
18858
|
+
toast({ text: MESSAGES[next3].settings.saveFailed(e.message), tone: "error" });
|
|
18719
18859
|
}
|
|
18720
18860
|
}, [saveLang, setLangState, toast]);
|
|
18721
|
-
const setTheme =
|
|
18722
|
-
setThemeState(
|
|
18861
|
+
const setTheme = useCallback2((next3) => {
|
|
18862
|
+
setThemeState(next3);
|
|
18723
18863
|
try {
|
|
18724
|
-
saveTheme?.(
|
|
18864
|
+
saveTheme?.(next3);
|
|
18725
18865
|
toast({ text: t.settings.saved, tone: "ok" });
|
|
18726
18866
|
} catch (e) {
|
|
18727
18867
|
toast({ text: t.settings.saveFailed(e.message), tone: "error" });
|
|
18728
18868
|
}
|
|
18729
18869
|
}, [saveTheme, setThemeState, toast, t]);
|
|
18730
|
-
const attach =
|
|
18870
|
+
const attach = useCallback2((s) => {
|
|
18731
18871
|
const cmd = attachCommand(fleet, s);
|
|
18732
18872
|
if ("why" in cmd) {
|
|
18733
18873
|
toast({ text: cmd.why === "offline" ? t.toast.offline(s.name) : cmd.why === "omp" ? t.toast.noTerminalOmp(s.name) : t.toast.noTerminal(s.name), tone: "info" });
|
|
@@ -18739,7 +18879,7 @@ function Shell({ client, lang, setLang: setLangState, saveLang, theme, setThemeS
|
|
|
18739
18879
|
if (code3 !== 0) toast({ text: t.toast.attachFailed(code3), tone: "error" });
|
|
18740
18880
|
});
|
|
18741
18881
|
}, [fleet, suspendTerminal, run2, t, toast, write]);
|
|
18742
|
-
const runInTerminal =
|
|
18882
|
+
const runInTerminal = useCallback2((argv) => {
|
|
18743
18883
|
void suspendTerminal(async () => {
|
|
18744
18884
|
const code3 = await (run2 ?? runAttached)(argv);
|
|
18745
18885
|
if (code3 !== 0) toast({ text: t.toast.exited(argv[0], code3), tone: "error" });
|
|
@@ -18774,13 +18914,12 @@ function Shell({ client, lang, setLang: setLangState, saveLang, theme, setThemeS
|
|
|
18774
18914
|
attach,
|
|
18775
18915
|
runInTerminal,
|
|
18776
18916
|
env,
|
|
18777
|
-
catalog,
|
|
18778
18917
|
keys,
|
|
18779
18918
|
kept,
|
|
18780
18919
|
readImage: readImage ?? (() => readClipboardImage(env)),
|
|
18781
18920
|
openFile: openFile ?? ((file) => openImage(file, env))
|
|
18782
18921
|
};
|
|
18783
|
-
|
|
18922
|
+
useInput8((input, key) => {
|
|
18784
18923
|
if (key.ctrl && input === "c") {
|
|
18785
18924
|
if (keys.current?.(input, key)) return;
|
|
18786
18925
|
const drafts = [...kept.drafts].some(([id, x]) => x.trim() && (id === "ask" || d.byId.has(id)));
|
|
@@ -18827,8 +18966,8 @@ function Shell({ client, lang, setLang: setLangState, saveLang, theme, setThemeS
|
|
|
18827
18966
|
return;
|
|
18828
18967
|
}
|
|
18829
18968
|
});
|
|
18830
|
-
const
|
|
18831
|
-
return /* @__PURE__ */
|
|
18969
|
+
const Body2 = { overview: Overview, session: SessionScreen, ask: Ask, launch: Launch, settings: Settings, openrig: OpenRigScreen, rigLaunch: RigLaunchScreen, help: Help }[screen];
|
|
18970
|
+
return /* @__PURE__ */ jsx23(TuiContext.Provider, { value: tui, children: /* @__PURE__ */ jsx23(Body2, {}) });
|
|
18832
18971
|
}
|
|
18833
18972
|
|
|
18834
18973
|
// src/tui/fleet.ts
|
|
@@ -18883,9 +19022,6 @@ var UNICODE = {
|
|
|
18883
19022
|
next: "\u25B8",
|
|
18884
19023
|
ellipsis: "\u2026",
|
|
18885
19024
|
bar: "\u2502",
|
|
18886
|
-
/** A team's table and the common table (roles spec §3.9). */
|
|
18887
|
-
team: "\u25A3",
|
|
18888
|
-
common: "\u25AD",
|
|
18889
19025
|
/** Markdown: a list's marks, a quote's bar, a rule, a code block's corners, a link's arrow, the end of a streamed answer. */
|
|
18890
19026
|
bullet: "\u2022",
|
|
18891
19027
|
subBullet: "\u25E6",
|
|
@@ -18903,7 +19039,7 @@ var UNICODE = {
|
|
|
18903
19039
|
stale: "!",
|
|
18904
19040
|
/** Links are clickable (OSC 8); without, their address follows them. */
|
|
18905
19041
|
links: true,
|
|
18906
|
-
/** A task handed between
|
|
19042
|
+
/** A task handed between sessions in « Échanges » (#92). */
|
|
18907
19043
|
task: "\u25A4"
|
|
18908
19044
|
};
|
|
18909
19045
|
var ASCII = {
|
|
@@ -18937,8 +19073,6 @@ var ASCII = {
|
|
|
18937
19073
|
next: ">",
|
|
18938
19074
|
ellipsis: "...",
|
|
18939
19075
|
bar: "|",
|
|
18940
|
-
team: "[T]",
|
|
18941
|
-
common: "[ ]",
|
|
18942
19076
|
bullet: "-",
|
|
18943
19077
|
subBullet: "o",
|
|
18944
19078
|
quote: "|",
|
|
@@ -19136,7 +19270,7 @@ async function backgroundAtStart(theme, env, io) {
|
|
|
19136
19270
|
}
|
|
19137
19271
|
|
|
19138
19272
|
// src/tui/index.tsx
|
|
19139
|
-
import { jsx as
|
|
19273
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
19140
19274
|
var TUI_USAGE = "ledge tui [--notify bell|osc9|off] [--here]";
|
|
19141
19275
|
function tuiArgs(args) {
|
|
19142
19276
|
let notify = "bell";
|
|
@@ -19175,15 +19309,15 @@ async function runTui(args) {
|
|
|
19175
19309
|
const detach = attachClient(client);
|
|
19176
19310
|
client.connect();
|
|
19177
19311
|
const app = render(
|
|
19178
|
-
/* @__PURE__ */
|
|
19312
|
+
/* @__PURE__ */ jsx24(
|
|
19179
19313
|
App,
|
|
19180
19314
|
{
|
|
19181
19315
|
client,
|
|
19182
19316
|
lang,
|
|
19183
|
-
saveLang: (
|
|
19317
|
+
saveLang: (next3) => saveSettings({ ...loadSettings(), lang: next3 }),
|
|
19184
19318
|
theme,
|
|
19185
19319
|
background,
|
|
19186
|
-
saveTheme: (
|
|
19320
|
+
saveTheme: (next3) => saveSettings({ ...loadSettings(), theme: next3 }),
|
|
19187
19321
|
notify: parsed.notify,
|
|
19188
19322
|
glyphs: glyphsFor(process.env),
|
|
19189
19323
|
env: process.env
|