@paradow/ledge 0.40.0 → 0.41.0-snapshot.41716003612.1
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/index.js +645 -368
- package/dist/cli/reduceWorker.js +1 -1
- package/package.json +20 -6
package/dist/cli/index.js
CHANGED
|
@@ -116,6 +116,12 @@ function backendOf(s) {
|
|
|
116
116
|
function isArchived(s) {
|
|
117
117
|
return s.archivedAt !== void 0;
|
|
118
118
|
}
|
|
119
|
+
function isOmpSeat(s) {
|
|
120
|
+
return s.source === "rig" && s.tool === "omp" && s.backend === void 0;
|
|
121
|
+
}
|
|
122
|
+
function isStoppedOmpSeat(s) {
|
|
123
|
+
return isOmpSeat(s) && s.state === "exited" && !isArchived(s);
|
|
124
|
+
}
|
|
119
125
|
var ToolSchema, OmpApprovalSchema, BackendSchema, SessionStateSchema, AskQuestionSchema, PendingSchema, ReplySchema, HelperSchema, TopicSourceSchema, SessionSchema;
|
|
120
126
|
var init_session = __esm({
|
|
121
127
|
"../protocol/src/session.ts"() {
|
|
@@ -2277,7 +2283,7 @@ var init_messages = __esm({
|
|
|
2277
2283
|
agentSessionId: z24.string().optional()
|
|
2278
2284
|
});
|
|
2279
2285
|
RecentSchema = z24.object({ cwd: z24.string().min(1), project: z24.string().min(1), lastAt: z24.string().datetime() });
|
|
2280
|
-
SEMVER = /^\d+\.\d+\.\d
|
|
2286
|
+
SEMVER = /^\d+\.\d+\.\d+(?:-snapshot\.[1-9]\d*\.[1-9]\d*)?$/;
|
|
2281
2287
|
DaemonInfoSchema = z24.object({
|
|
2282
2288
|
version: z24.string(),
|
|
2283
2289
|
install: z24.enum(["npm", "git", "unknown"]),
|
|
@@ -3788,11 +3794,11 @@ function stripNote(text7) {
|
|
|
3788
3794
|
}
|
|
3789
3795
|
function formatLedgeMessage(m) {
|
|
3790
3796
|
const from = attr(m.from);
|
|
3791
|
-
const
|
|
3792
|
-
if (!m.id || inline(m.text)) return `${
|
|
3797
|
+
const open6 = `<ledge-message from="${from}" tool="${m.tool}"${m.id ? ` id="${attr(m.id)}"` : ""}>${messageNote(from, m.to)} `;
|
|
3798
|
+
if (!m.id || inline(m.text)) return `${open6}${ledgeBody(m.text)}${LEDGE_CLOSE}`;
|
|
3793
3799
|
const first = m.summary?.trim() || m.text.trim().split(/\r\n|\r|\n/)[0].trim();
|
|
3794
3800
|
const head2 = ledgeBody(first.length > POINTER_HEAD ? `${first.slice(0, POINTER_HEAD)}\u2026` : first);
|
|
3795
|
-
return `${
|
|
3801
|
+
return `${open6}${head2} \u2026 [message de ${m.text.length} caract\xE8res, ${lineCount(m.text)} lignes : lis-le en entier avec ledge read ${attr(m.id)}]${LEDGE_CLOSE}`;
|
|
3796
3802
|
}
|
|
3797
3803
|
function ledgeMessages(text7) {
|
|
3798
3804
|
const out = [];
|
|
@@ -4947,7 +4953,7 @@ __export(who_exports, {
|
|
|
4947
4953
|
});
|
|
4948
4954
|
import { basename as basename5 } from "path";
|
|
4949
4955
|
function formatWho(sessions, self, projects) {
|
|
4950
|
-
const live3 = sessions.filter((s) => s.state !== "exited" && !isArchived(s));
|
|
4956
|
+
const live3 = sessions.filter((s) => s.state !== "exited" && !isArchived(s) || isStoppedOmpSeat(s));
|
|
4951
4957
|
if (live3.length === 0) return "aucune autre session";
|
|
4952
4958
|
const rows = live3.map((s) => [
|
|
4953
4959
|
s.id === self ? "*" : " ",
|
|
@@ -5195,8 +5201,8 @@ function underCodexDaemon(read = (p) => readFileSync5(p, "utf8")) {
|
|
|
5195
5201
|
let pid = process.pid;
|
|
5196
5202
|
for (let depth = 0; depth < 8; depth++) {
|
|
5197
5203
|
try {
|
|
5198
|
-
const
|
|
5199
|
-
pid = Number(
|
|
5204
|
+
const stat8 = read(`/proc/${pid}/stat`);
|
|
5205
|
+
pid = Number(stat8.slice(stat8.lastIndexOf(")") + 2).split(" ")[1]);
|
|
5200
5206
|
if (!pid || pid <= 1) return false;
|
|
5201
5207
|
if (read(`/proc/${pid}/cmdline`).split("\0").includes("app-server")) return true;
|
|
5202
5208
|
} catch {
|
|
@@ -6764,9 +6770,9 @@ ${done.output}` : command;
|
|
|
6764
6770
|
const peer = (m.sender ? this.peerOf(m.sender) : void 0) ?? this.peerOf(m.from) ?? (m.name ? this.peerOf(m.name) : void 0);
|
|
6765
6771
|
if (!peer) return this.put(id, recv);
|
|
6766
6772
|
const head2 = (t) => ledgeBody(t).trim().slice(0, 200);
|
|
6767
|
-
const
|
|
6768
|
-
const byId2 = m.id ?
|
|
6769
|
-
const sent = byId2 ?? [...
|
|
6773
|
+
const open6 = this.items(peer).filter((i) => i.kind === "sent" && i.peer === id && i.status !== "read");
|
|
6774
|
+
const byId2 = m.id ? open6.find((i) => mailId(i.id) === m.id) : void 0;
|
|
6775
|
+
const sent = byId2 ?? [...open6].reverse().find((i) => head2(i.text) === head2(recv.text)) ?? open6.at(-1);
|
|
6770
6776
|
if (sent) this.put(peer, { ...sent, status: "read", received: recv.id });
|
|
6771
6777
|
return this.put(id, { ...recv, ...byId2 ? { text: byId2.text } : {}, peer, ...sent ? { sent: sent.id } : {} });
|
|
6772
6778
|
}
|
|
@@ -7838,6 +7844,203 @@ var init_verify = __esm({
|
|
|
7838
7844
|
}
|
|
7839
7845
|
});
|
|
7840
7846
|
|
|
7847
|
+
// src/daemon/omp/seats.ts
|
|
7848
|
+
import { homedir as homedir5 } from "os";
|
|
7849
|
+
import { join as join10 } from "path";
|
|
7850
|
+
import { open, readFile as readFile7, stat as stat2 } from "fs/promises";
|
|
7851
|
+
function entryState(raw) {
|
|
7852
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
7853
|
+
const e = raw;
|
|
7854
|
+
const at = typeof e.timestamp === "string" && !Number.isNaN(Date.parse(e.timestamp)) ? new Date(e.timestamp).toISOString() : void 0;
|
|
7855
|
+
const of = (state2) => ({ state: state2, ...at ? { at } : {} });
|
|
7856
|
+
if (e.type === "custom_message") return of("working");
|
|
7857
|
+
if (e.type === "custom") return e.customType === "tool_execution_start" ? of("working") : null;
|
|
7858
|
+
if (e.type !== "message" || !e.message || typeof e.message !== "object") return null;
|
|
7859
|
+
const m = e.message;
|
|
7860
|
+
if (m.role === "user" || m.role === "toolResult") return of("working");
|
|
7861
|
+
if (m.role !== "assistant") return null;
|
|
7862
|
+
return typeof m.stopReason === "string" ? of(m.stopReason === "toolUse" ? "working" : "idle") : null;
|
|
7863
|
+
}
|
|
7864
|
+
async function nextNewline(fh, from, size) {
|
|
7865
|
+
const buf2 = Buffer.alloc(BLOCK3);
|
|
7866
|
+
for (let at = from; at < size; ) {
|
|
7867
|
+
const { bytesRead } = await fh.read(buf2, 0, Math.min(BLOCK3, size - at), at);
|
|
7868
|
+
if (bytesRead === 0) return -1;
|
|
7869
|
+
const nl = buf2.subarray(0, bytesRead).indexOf(10);
|
|
7870
|
+
if (nl !== -1) return at + nl;
|
|
7871
|
+
at += bytesRead;
|
|
7872
|
+
}
|
|
7873
|
+
return -1;
|
|
7874
|
+
}
|
|
7875
|
+
function createOmpSeats(deps) {
|
|
7876
|
+
const { store } = deps;
|
|
7877
|
+
const root2 = deps.root ?? ompSeatsRoot();
|
|
7878
|
+
const follows = /* @__PURE__ */ new Map();
|
|
7879
|
+
let running = false, timer2 = null;
|
|
7880
|
+
async function journalOf(seat2) {
|
|
7881
|
+
try {
|
|
7882
|
+
const file = JSON.parse(await readFile7(join10(root2, seat2, "runner-state.json"), "utf8")).sessionFile;
|
|
7883
|
+
return typeof file === "string" && file ? file : null;
|
|
7884
|
+
} catch {
|
|
7885
|
+
return null;
|
|
7886
|
+
}
|
|
7887
|
+
}
|
|
7888
|
+
async function followOne(s) {
|
|
7889
|
+
const file = await journalOf(s.rig.seat);
|
|
7890
|
+
if (!file) return;
|
|
7891
|
+
let size;
|
|
7892
|
+
try {
|
|
7893
|
+
size = (await stat2(file)).size;
|
|
7894
|
+
} catch {
|
|
7895
|
+
return;
|
|
7896
|
+
}
|
|
7897
|
+
let f = follows.get(s.id);
|
|
7898
|
+
if (!f || f.file !== file) {
|
|
7899
|
+
const known2 = await lastState(file, size);
|
|
7900
|
+
f = { file, offset: known2.end };
|
|
7901
|
+
follows.set(s.id, f);
|
|
7902
|
+
if (known2.state) apply(s.id, known2.state);
|
|
7903
|
+
return;
|
|
7904
|
+
}
|
|
7905
|
+
if (size < f.offset) {
|
|
7906
|
+
f.offset = size;
|
|
7907
|
+
return;
|
|
7908
|
+
}
|
|
7909
|
+
if (size === f.offset) return;
|
|
7910
|
+
const fh = await open(file, "r");
|
|
7911
|
+
let chunk, end2;
|
|
7912
|
+
try {
|
|
7913
|
+
const readAt2 = async (want) => {
|
|
7914
|
+
const b3 = Buffer.alloc(want);
|
|
7915
|
+
return b3.subarray(0, (await fh.read(b3, 0, want, f.offset)).bytesRead);
|
|
7916
|
+
};
|
|
7917
|
+
chunk = await readAt2(Math.min(size - f.offset, READ_BYTES));
|
|
7918
|
+
end2 = chunk.lastIndexOf(10);
|
|
7919
|
+
if (end2 === -1 && chunk.length < size - f.offset) {
|
|
7920
|
+
chunk = await readAt2(Math.min(size - f.offset, BACK_BYTES));
|
|
7921
|
+
end2 = chunk.lastIndexOf(10);
|
|
7922
|
+
}
|
|
7923
|
+
if (end2 === -1 && chunk.length === BACK_BYTES) {
|
|
7924
|
+
const next4 = await nextNewline(fh, f.offset + chunk.length, size);
|
|
7925
|
+
if (next4 !== -1) {
|
|
7926
|
+
log(`omp seats: an entry of ${s.rig.seat} over ${BACK_BYTES} bytes was skipped`);
|
|
7927
|
+
f.offset = next4 + 1;
|
|
7928
|
+
}
|
|
7929
|
+
return;
|
|
7930
|
+
}
|
|
7931
|
+
} finally {
|
|
7932
|
+
await fh.close();
|
|
7933
|
+
}
|
|
7934
|
+
if (end2 === -1) return;
|
|
7935
|
+
const lines = chunk.subarray(0, end2).toString("utf8").split("\n");
|
|
7936
|
+
f.offset += end2 + 1;
|
|
7937
|
+
let last = null;
|
|
7938
|
+
for (const line2 of lines) {
|
|
7939
|
+
if (!line2.trim()) continue;
|
|
7940
|
+
let entry2;
|
|
7941
|
+
try {
|
|
7942
|
+
entry2 = JSON.parse(line2);
|
|
7943
|
+
} catch {
|
|
7944
|
+
continue;
|
|
7945
|
+
}
|
|
7946
|
+
last = entryState(entry2) ?? last;
|
|
7947
|
+
}
|
|
7948
|
+
if (last) apply(s.id, last);
|
|
7949
|
+
}
|
|
7950
|
+
function apply(id, last) {
|
|
7951
|
+
const cur = store.get(id);
|
|
7952
|
+
if (!cur || cur.state === "exited") return;
|
|
7953
|
+
const at = last.at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
7954
|
+
if (cur.state !== last.state || at > cur.lastActivityAt) store.upsert({ ...cur, state: last.state, lastActivityAt: at > cur.lastActivityAt ? at : cur.lastActivityAt });
|
|
7955
|
+
}
|
|
7956
|
+
async function lastState(file, size) {
|
|
7957
|
+
const fh = await open(file, "r");
|
|
7958
|
+
try {
|
|
7959
|
+
const newlineBefore = async (before2) => {
|
|
7960
|
+
const buf2 = Buffer.alloc(BLOCK3);
|
|
7961
|
+
for (let to = before2; to > 0; ) {
|
|
7962
|
+
if (size - to > BACK_BYTES) return null;
|
|
7963
|
+
const from = Math.max(0, to - BLOCK3);
|
|
7964
|
+
const { bytesRead } = await fh.read(buf2, 0, to - from, from);
|
|
7965
|
+
const at = buf2.subarray(0, bytesRead).lastIndexOf(10);
|
|
7966
|
+
if (at !== -1) return from + at;
|
|
7967
|
+
to = from;
|
|
7968
|
+
}
|
|
7969
|
+
return -1;
|
|
7970
|
+
};
|
|
7971
|
+
const last = await newlineBefore(size);
|
|
7972
|
+
if (last === null || last === -1) return { state: null, end: last === -1 ? 0 : size };
|
|
7973
|
+
const end2 = last + 1;
|
|
7974
|
+
for (let lineEnd = last; lineEnd > 0; ) {
|
|
7975
|
+
const start = await newlineBefore(lineEnd);
|
|
7976
|
+
if (start === null) break;
|
|
7977
|
+
const from = start + 1;
|
|
7978
|
+
const line2 = Buffer.alloc(lineEnd - from);
|
|
7979
|
+
await fh.read(line2, 0, line2.length, from);
|
|
7980
|
+
let entry2 = null;
|
|
7981
|
+
try {
|
|
7982
|
+
entry2 = JSON.parse(line2.toString("utf8"));
|
|
7983
|
+
} catch {
|
|
7984
|
+
}
|
|
7985
|
+
const state2 = entryState(entry2);
|
|
7986
|
+
if (state2) return { state: state2, end: end2 };
|
|
7987
|
+
if (start === -1) break;
|
|
7988
|
+
lineEnd = start;
|
|
7989
|
+
}
|
|
7990
|
+
return { state: null, end: end2 };
|
|
7991
|
+
} finally {
|
|
7992
|
+
await fh.close();
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7995
|
+
async function tick() {
|
|
7996
|
+
if (running) return;
|
|
7997
|
+
running = true;
|
|
7998
|
+
try {
|
|
7999
|
+
const live3 = /* @__PURE__ */ new Set();
|
|
8000
|
+
for (const s of store.all()) {
|
|
8001
|
+
if (!isOmpSeat2(s) || !s.rig || s.state === "exited" || isArchived(s)) continue;
|
|
8002
|
+
live3.add(s.id);
|
|
8003
|
+
try {
|
|
8004
|
+
await followOne(s);
|
|
8005
|
+
} catch (e) {
|
|
8006
|
+
log(`omp seats: journal of ${s.rig.seat} not read: ${e.message}`);
|
|
8007
|
+
}
|
|
8008
|
+
}
|
|
8009
|
+
for (const id of follows.keys()) if (!live3.has(id)) follows.delete(id);
|
|
8010
|
+
} finally {
|
|
8011
|
+
running = false;
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
return {
|
|
8015
|
+
tick,
|
|
8016
|
+
start() {
|
|
8017
|
+
if (!timer2) {
|
|
8018
|
+
timer2 = setInterval(() => {
|
|
8019
|
+
void tick();
|
|
8020
|
+
}, deps.intervalMs ?? 1e3);
|
|
8021
|
+
timer2.unref?.();
|
|
8022
|
+
}
|
|
8023
|
+
},
|
|
8024
|
+
stop() {
|
|
8025
|
+
if (timer2) clearInterval(timer2);
|
|
8026
|
+
timer2 = null;
|
|
8027
|
+
}
|
|
8028
|
+
};
|
|
8029
|
+
}
|
|
8030
|
+
var ompSeatsRoot, BACK_BYTES, BLOCK3, READ_BYTES, isOmpSeat2;
|
|
8031
|
+
var init_seats = __esm({
|
|
8032
|
+
"src/daemon/omp/seats.ts"() {
|
|
8033
|
+
"use strict";
|
|
8034
|
+
init_src();
|
|
8035
|
+
init_log();
|
|
8036
|
+
ompSeatsRoot = (env = process.env) => join10(env.OPENRIG_HOME?.trim() || join10(homedir5(), ".openrig"), "state", "omp");
|
|
8037
|
+
BACK_BYTES = 16 * 1024 * 1024;
|
|
8038
|
+
BLOCK3 = 64 * 1024;
|
|
8039
|
+
READ_BYTES = 4 * 1024 * 1024;
|
|
8040
|
+
isOmpSeat2 = (s) => s.source === "rig" && s.tool === "omp" && s.backend === void 0;
|
|
8041
|
+
}
|
|
8042
|
+
});
|
|
8043
|
+
|
|
7841
8044
|
// src/daemon/poller.ts
|
|
7842
8045
|
import { createHash as createHash4 } from "crypto";
|
|
7843
8046
|
function startPoller(opts) {
|
|
@@ -7902,7 +8105,7 @@ function startPoller(opts) {
|
|
|
7902
8105
|
}
|
|
7903
8106
|
if (s.state === "exited") {
|
|
7904
8107
|
forget(s.id);
|
|
7905
|
-
if (!s.archivedAt && s.exitedAt) {
|
|
8108
|
+
if (!s.archivedAt && s.exitedAt && !isOmpSeat2(s)) {
|
|
7906
8109
|
const since = Math.max(Date.parse(s.exitedAt), s.restoredAt ? Date.parse(s.restoredAt) : -Infinity);
|
|
7907
8110
|
if (t - since > retireMs) store.archive(s.id, now2());
|
|
7908
8111
|
}
|
|
@@ -7919,6 +8122,7 @@ function startPoller(opts) {
|
|
|
7919
8122
|
forget(s.id);
|
|
7920
8123
|
return;
|
|
7921
8124
|
}
|
|
8125
|
+
if (isOmpSeat2(s)) return;
|
|
7922
8126
|
const full = await tmux.capture(s.tmuxSession, PREVIEW_CAPTURE_LINES);
|
|
7923
8127
|
if (full === null) return;
|
|
7924
8128
|
const pane = full.split("\n").slice(-DETECT_LINES).join("\n");
|
|
@@ -7983,6 +8187,7 @@ var init_poller = __esm({
|
|
|
7983
8187
|
init_log();
|
|
7984
8188
|
init_git();
|
|
7985
8189
|
init_transcript();
|
|
8190
|
+
init_seats();
|
|
7986
8191
|
init_adapters();
|
|
7987
8192
|
DETECT_LINES = 60;
|
|
7988
8193
|
REST_MS = 2e3;
|
|
@@ -8528,7 +8733,7 @@ var init_project = __esm({
|
|
|
8528
8733
|
|
|
8529
8734
|
// src/daemon/omp/host.ts
|
|
8530
8735
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
8531
|
-
import { basename as basename7, join as
|
|
8736
|
+
import { basename as basename7, join as join11 } from "path";
|
|
8532
8737
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
8533
8738
|
function ompArgs(o) {
|
|
8534
8739
|
return ["--mode", "rpc-ui", "--session-dir", o.dir, "--cwd", o.cwd, "--approval-mode", o.approval ?? APPROVAL_MODE, ...ompModelArgs(o.model, o.effort), ...(o.dirs ?? []).flatMap((d) => ["--add-dir", d]), ...o.resumeFile ? ["--resume", o.resumeFile] : []];
|
|
@@ -8540,7 +8745,7 @@ function createOmpHost(deps) {
|
|
|
8540
8745
|
const live3 = /* @__PURE__ */ new Map();
|
|
8541
8746
|
let generations = 0;
|
|
8542
8747
|
async function startProcess(id, o) {
|
|
8543
|
-
const dir =
|
|
8748
|
+
const dir = join11(deps.dir, id);
|
|
8544
8749
|
await mkdir7(dir, { recursive: true });
|
|
8545
8750
|
if (await reapOwner(dir)) log(`omp ${id}: ended the process a previous daemon left`);
|
|
8546
8751
|
const key = sessionKey(id);
|
|
@@ -8720,15 +8925,15 @@ function createOmpHost(deps) {
|
|
|
8720
8925
|
async answer(id, text7) {
|
|
8721
8926
|
const l = live3.get(id);
|
|
8722
8927
|
if (!l) return "the session is not running";
|
|
8723
|
-
const
|
|
8724
|
-
if (!
|
|
8725
|
-
const a = answerFor(
|
|
8928
|
+
const open6 = l.tracking.requests[0];
|
|
8929
|
+
if (!open6) return "nothing to answer";
|
|
8930
|
+
const a = answerFor(open6, text7);
|
|
8726
8931
|
if ("refused" in a) return a.refused;
|
|
8727
8932
|
l.tracking.requests.shift();
|
|
8728
8933
|
try {
|
|
8729
8934
|
await l.rpc.write(a.frame);
|
|
8730
8935
|
} catch (e) {
|
|
8731
|
-
l.tracking.requests.unshift(
|
|
8936
|
+
l.tracking.requests.unshift(open6);
|
|
8732
8937
|
return e.message;
|
|
8733
8938
|
}
|
|
8734
8939
|
store.apply(id, { name: "Decided", at: now2(), source: "daemon" });
|
|
@@ -8777,15 +8982,15 @@ function createOmpHost(deps) {
|
|
|
8777
8982
|
async answerAsk(id, requestId3, answers, cancel = false) {
|
|
8778
8983
|
const l = live3.get(id);
|
|
8779
8984
|
if (!l) return "the session is not running";
|
|
8780
|
-
const
|
|
8781
|
-
if (!
|
|
8782
|
-
const a = cancel ? { frame: { type: "extension_ui_response", id:
|
|
8985
|
+
const open6 = l.tracking.requests[0];
|
|
8986
|
+
if (!open6 || open6.id !== requestId3) return "the request changed, look again";
|
|
8987
|
+
const a = cancel ? { frame: { type: "extension_ui_response", id: open6.id, cancelled: true } } : askAnswerFor(open6, answers);
|
|
8783
8988
|
if ("refused" in a) return a.refused;
|
|
8784
8989
|
l.tracking.requests.shift();
|
|
8785
8990
|
try {
|
|
8786
8991
|
await l.rpc.write(a.frame);
|
|
8787
8992
|
} catch (e) {
|
|
8788
|
-
l.tracking.requests.unshift(
|
|
8993
|
+
l.tracking.requests.unshift(open6);
|
|
8789
8994
|
return e.message;
|
|
8790
8995
|
}
|
|
8791
8996
|
store.apply(id, { name: "Decided", at: now2(), source: "daemon" });
|
|
@@ -8871,9 +9076,9 @@ var init_catalog = __esm({
|
|
|
8871
9076
|
// src/daemon/repos.ts
|
|
8872
9077
|
import { execFile as execFile2 } from "child_process";
|
|
8873
9078
|
import { constants } from "fs";
|
|
8874
|
-
import { open, stat as
|
|
8875
|
-
import { homedir as
|
|
8876
|
-
import { join as
|
|
9079
|
+
import { open as open2, stat as stat3 } from "fs/promises";
|
|
9080
|
+
import { homedir as homedir6 } from "os";
|
|
9081
|
+
import { join as join12, resolve as resolve2 } from "path";
|
|
8877
9082
|
function runGit(cwd, args) {
|
|
8878
9083
|
return new Promise((res) => {
|
|
8879
9084
|
execFile2("git", ["-C", cwd, ...args], { timeout: GIT_TIMEOUT_MS, windowsHide: true }, (err, out) => res(err ? null : out.trim() || null));
|
|
@@ -8891,7 +9096,7 @@ async function slot(job) {
|
|
|
8891
9096
|
}
|
|
8892
9097
|
}
|
|
8893
9098
|
async function readGitFile(path3, max = 64 * 1024) {
|
|
8894
|
-
const fh = await
|
|
9099
|
+
const fh = await open2(path3, constants.O_RDONLY | (constants.O_NONBLOCK ?? 0));
|
|
8895
9100
|
try {
|
|
8896
9101
|
if (!(await fh.stat()).isFile()) throw new Error(`not a regular file: ${path3}`);
|
|
8897
9102
|
const buf2 = Buffer.alloc(max + 1);
|
|
@@ -8905,7 +9110,7 @@ async function readGitFile(path3, max = 64 * 1024) {
|
|
|
8905
9110
|
async function headBranch(dotGit) {
|
|
8906
9111
|
let head2;
|
|
8907
9112
|
try {
|
|
8908
|
-
head2 = (await readGitFile(
|
|
9113
|
+
head2 = (await readGitFile(join12(dotGit, "HEAD"), MAX_HEAD_BYTES)).trim();
|
|
8909
9114
|
} catch {
|
|
8910
9115
|
return null;
|
|
8911
9116
|
}
|
|
@@ -8914,23 +9119,23 @@ async function headBranch(dotGit) {
|
|
|
8914
9119
|
return /^[0-9a-f]{7,}$/i.test(head2) ? head2.slice(0, 7) : null;
|
|
8915
9120
|
}
|
|
8916
9121
|
async function inspectRepos(paths2, opts = {}) {
|
|
8917
|
-
const home2 = opts.home ??
|
|
9122
|
+
const home2 = opts.home ?? homedir6();
|
|
8918
9123
|
const git = opts.git ?? runGit;
|
|
8919
9124
|
return Promise.all(paths2.map((raw) => slot(async () => {
|
|
8920
9125
|
const input = raw.trim();
|
|
8921
9126
|
const path3 = resolve2(input === "~" ? home2 : input.startsWith("~/") ? resolve2(home2, input.slice(2)) : input);
|
|
8922
9127
|
let isDir2 = false;
|
|
8923
9128
|
try {
|
|
8924
|
-
isDir2 = (await
|
|
9129
|
+
isDir2 = (await stat3(path3)).isDirectory();
|
|
8925
9130
|
} catch {
|
|
8926
9131
|
}
|
|
8927
9132
|
if (!isDir2) return { path: raw, exists: false, branch: null };
|
|
8928
9133
|
let dotDir = false;
|
|
8929
9134
|
try {
|
|
8930
|
-
dotDir = (await
|
|
9135
|
+
dotDir = (await stat3(join12(path3, ".git"))).isDirectory();
|
|
8931
9136
|
} catch {
|
|
8932
9137
|
}
|
|
8933
|
-
if (dotDir) return { path: raw, exists: true, branch: await headBranch(
|
|
9138
|
+
if (dotDir) return { path: raw, exists: true, branch: await headBranch(join12(path3, ".git")) };
|
|
8934
9139
|
const deadline = Date.now() + GIT_TIMEOUT_MS;
|
|
8935
9140
|
const bounded = (args) => new Promise((res) => {
|
|
8936
9141
|
const t = setTimeout(() => res(null), Math.max(0, deadline - Date.now()));
|
|
@@ -8962,7 +9167,7 @@ var init_repos2 = __esm({
|
|
|
8962
9167
|
|
|
8963
9168
|
// src/daemon/scan.ts
|
|
8964
9169
|
import { readdir as fsReaddir } from "fs/promises";
|
|
8965
|
-
import { dirname as dirname4, isAbsolute, join as
|
|
9170
|
+
import { dirname as dirname4, isAbsolute, join as join13, resolve as resolve3, sep as sep2 } from "path";
|
|
8966
9171
|
function extraRoots(home2, cwds) {
|
|
8967
9172
|
const h = resolve3(home2);
|
|
8968
9173
|
const out = [];
|
|
@@ -9008,19 +9213,19 @@ function originUrl(config) {
|
|
|
9008
9213
|
}
|
|
9009
9214
|
return url || void 0;
|
|
9010
9215
|
}
|
|
9011
|
-
async function remoteOf(dir, dotIsFile,
|
|
9216
|
+
async function remoteOf(dir, dotIsFile, readFile20) {
|
|
9012
9217
|
try {
|
|
9013
|
-
let gitDir =
|
|
9218
|
+
let gitDir = join13(dir, ".git");
|
|
9014
9219
|
if (dotIsFile) {
|
|
9015
|
-
const m = /^gitdir:\s*(.+)$/m.exec(await
|
|
9220
|
+
const m = /^gitdir:\s*(.+)$/m.exec(await readFile20(gitDir));
|
|
9016
9221
|
if (!m) return void 0;
|
|
9017
9222
|
gitDir = resolve3(dir, m[1].trim());
|
|
9018
9223
|
try {
|
|
9019
|
-
gitDir = resolve3(gitDir, (await
|
|
9224
|
+
gitDir = resolve3(gitDir, (await readFile20(join13(gitDir, "commondir"))).trim());
|
|
9020
9225
|
} catch {
|
|
9021
9226
|
}
|
|
9022
9227
|
}
|
|
9023
|
-
const url = originUrl(await
|
|
9228
|
+
const url = originUrl(await readFile20(join13(gitDir, "config")));
|
|
9024
9229
|
return url ? repositoryId(url) : void 0;
|
|
9025
9230
|
} catch {
|
|
9026
9231
|
return void 0;
|
|
@@ -9037,18 +9242,18 @@ function manifestName(file, text7) {
|
|
|
9037
9242
|
} else name = /<artifactId>\s*([^<]+?)\s*<\/artifactId>/.exec(text7.replace(/<!--[\s\S]*?-->/g, "").replace(/<parent>[\s\S]*?<\/parent>/g, ""))?.[1];
|
|
9038
9243
|
return typeof name === "string" && name.trim() && name.length <= 200 ? name.trim() : void 0;
|
|
9039
9244
|
}
|
|
9040
|
-
async function describe(dir, dotIsFile, home2,
|
|
9245
|
+
async function describe(dir, dotIsFile, home2, readFile20, manifest) {
|
|
9041
9246
|
const [branch, remote, named] = await Promise.all([
|
|
9042
|
-
dotIsFile ? inspectRepos([dir], { home: home2 }).then((r) => r[0]?.branch ?? null) : headBranch(
|
|
9043
|
-
remoteOf(dir, dotIsFile,
|
|
9044
|
-
manifest ?
|
|
9247
|
+
dotIsFile ? inspectRepos([dir], { home: home2 }).then((r) => r[0]?.branch ?? null) : headBranch(join13(dir, ".git")),
|
|
9248
|
+
remoteOf(dir, dotIsFile, readFile20),
|
|
9249
|
+
manifest ? readFile20(join13(dir, manifest)).then((text7) => manifestName(manifest, text7), () => void 0) : void 0
|
|
9045
9250
|
]);
|
|
9046
9251
|
return { path: dir, branch, ...remote ? { remote } : {}, ...named ? { manifest: named } : {} };
|
|
9047
9252
|
}
|
|
9048
9253
|
async function scanRepos(opts) {
|
|
9049
9254
|
const now2 = opts.now ?? Date.now;
|
|
9050
9255
|
const readdir5 = opts.readdir ?? ((p) => fsReaddir(p, { withFileTypes: true }));
|
|
9051
|
-
const
|
|
9256
|
+
const readFile20 = opts.readFile ?? ((p) => readGitFile(p));
|
|
9052
9257
|
const depth = opts.limits?.depth ?? SCAN_DEPTH, maxDirs = opts.limits?.dirs ?? SCAN_DIRS, ms = opts.limits?.ms ?? SCAN_MS, maxRepos = opts.limits?.repos ?? SCAN_REPOS;
|
|
9053
9258
|
const deadline = now2() + ms;
|
|
9054
9259
|
let timer2;
|
|
@@ -9083,11 +9288,11 @@ async function scanRepos(opts) {
|
|
|
9083
9288
|
if (!entries) return;
|
|
9084
9289
|
const dot = entries.find((e) => e.name === ".git" && (e.isDirectory() || e.isFile()));
|
|
9085
9290
|
const manifest = dot ? MANIFESTS.find((m) => entries.some((e) => e.name === m && e.isFile())) : void 0;
|
|
9086
|
-
if (dot) found.push(describe(d.path, dot.isFile(), opts.home,
|
|
9291
|
+
if (dot) found.push(describe(d.path, dot.isFile(), opts.home, readFile20, manifest));
|
|
9087
9292
|
if (dot && d.path !== home2 || d.depth >= depth) return;
|
|
9088
9293
|
const names = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !SKIP.has(e.name)).map((e) => e.name).sort();
|
|
9089
9294
|
for (const name of names) {
|
|
9090
|
-
const path3 =
|
|
9295
|
+
const path3 = join13(d.path, name);
|
|
9091
9296
|
if (!seen.has(path3)) {
|
|
9092
9297
|
seen.add(path3);
|
|
9093
9298
|
queue.push({ path: path3, depth: d.depth + 1 });
|
|
@@ -9131,23 +9336,23 @@ var init_scan2 = __esm({
|
|
|
9131
9336
|
});
|
|
9132
9337
|
|
|
9133
9338
|
// src/daemon/folders.ts
|
|
9134
|
-
import { mkdir as mkdir8, readdir as readdir3, stat as
|
|
9135
|
-
import { homedir as
|
|
9136
|
-
import { dirname as dirname5, isAbsolute as isAbsolute2, join as
|
|
9339
|
+
import { mkdir as mkdir8, readdir as readdir3, stat as stat4 } from "fs/promises";
|
|
9340
|
+
import { homedir as homedir7 } from "os";
|
|
9341
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join14, resolve as resolve4 } from "path";
|
|
9137
9342
|
async function resolveExact(raw, home2) {
|
|
9138
9343
|
const expanded = raw === "~" ? home2 : raw.startsWith("~/") ? resolve4(home2, raw.slice(2)) : raw;
|
|
9139
9344
|
if (!isAbsolute2(expanded)) throw new Error(`not an absolute path: ${raw}`);
|
|
9140
9345
|
const path3 = resolve4(expanded);
|
|
9141
9346
|
let s;
|
|
9142
9347
|
try {
|
|
9143
|
-
s = await
|
|
9348
|
+
s = await stat4(path3);
|
|
9144
9349
|
} catch {
|
|
9145
9350
|
throw new Error(`no such folder: ${path3}`);
|
|
9146
9351
|
}
|
|
9147
9352
|
if (!s.isDirectory()) throw new Error(`not a folder: ${path3}`);
|
|
9148
9353
|
return path3;
|
|
9149
9354
|
}
|
|
9150
|
-
async function resolveFolder(input, home2 =
|
|
9355
|
+
async function resolveFolder(input, home2 = homedir7()) {
|
|
9151
9356
|
return resolveExact(input.trim(), home2);
|
|
9152
9357
|
}
|
|
9153
9358
|
async function subfolders(path3) {
|
|
@@ -9156,7 +9361,7 @@ async function subfolders(path3) {
|
|
|
9156
9361
|
if (d.isDirectory()) return d.name;
|
|
9157
9362
|
if (!d.isSymbolicLink()) return null;
|
|
9158
9363
|
try {
|
|
9159
|
-
return (await
|
|
9364
|
+
return (await stat4(join14(path3, d.name))).isDirectory() ? d.name : null;
|
|
9160
9365
|
} catch {
|
|
9161
9366
|
return null;
|
|
9162
9367
|
}
|
|
@@ -9164,42 +9369,42 @@ async function subfolders(path3) {
|
|
|
9164
9369
|
return found.filter((n) => n !== null).sort(byName.compare);
|
|
9165
9370
|
}
|
|
9166
9371
|
async function gitBranchOf(dir, git) {
|
|
9167
|
-
const dot =
|
|
9372
|
+
const dot = join14(dir, ".git");
|
|
9168
9373
|
let s;
|
|
9169
9374
|
try {
|
|
9170
|
-
s = await
|
|
9375
|
+
s = await stat4(dot);
|
|
9171
9376
|
} catch {
|
|
9172
9377
|
return null;
|
|
9173
9378
|
}
|
|
9174
9379
|
if (s.isFile()) return (await inspectRepos([dir], { git }))[0]?.branch ?? null;
|
|
9175
9380
|
return s.isDirectory() ? headBranch(dot) : null;
|
|
9176
9381
|
}
|
|
9177
|
-
async function listFolder(input, home2 =
|
|
9382
|
+
async function listFolder(input, home2 = homedir7(), requestId3, git) {
|
|
9178
9383
|
const tag = requestId3 === void 0 ? {} : { requestId: requestId3 };
|
|
9179
9384
|
const asked2 = input || "~";
|
|
9180
9385
|
try {
|
|
9181
9386
|
const path3 = await resolveExact(asked2, home2);
|
|
9182
9387
|
const parent = dirname5(path3);
|
|
9183
9388
|
const entries = await subfolders(path3);
|
|
9184
|
-
const branches = await Promise.all(entries.map((name) => gitBranchOf(
|
|
9389
|
+
const branches = await Promise.all(entries.map((name) => gitBranchOf(join14(path3, name), git)));
|
|
9185
9390
|
const repos = entries.flatMap((name, i) => branches[i] === null ? [] : [{ name, branch: branches[i] }]);
|
|
9186
9391
|
return { type: "folder.listing", path: path3, parent: parent === path3 ? null : parent, entries, repos, ...tag };
|
|
9187
9392
|
} catch (e) {
|
|
9188
9393
|
return { type: "folder.listing", path: asked2, parent: null, entries: [], error: e.message, ...tag };
|
|
9189
9394
|
}
|
|
9190
9395
|
}
|
|
9191
|
-
async function createFolder(parent, name, home2 =
|
|
9396
|
+
async function createFolder(parent, name, home2 = homedir7(), requestId3) {
|
|
9192
9397
|
const at = await listFolder(parent, home2, requestId3);
|
|
9193
9398
|
if (at.error) return at;
|
|
9194
9399
|
const clean = name.trim();
|
|
9195
9400
|
if (!clean || clean === "." || clean === ".." || /[/\0]/.test(clean)) return { ...at, error: `invalid folder name: ${name}` };
|
|
9196
9401
|
try {
|
|
9197
|
-
await mkdir8(
|
|
9402
|
+
await mkdir8(join14(at.path, clean));
|
|
9198
9403
|
} catch (e) {
|
|
9199
9404
|
const code3 = e.code;
|
|
9200
9405
|
return { ...at, error: code3 === "EEXIST" ? `already exists: ${clean}` : `cannot create ${clean}: ${e.message}` };
|
|
9201
9406
|
}
|
|
9202
|
-
return listFolder(
|
|
9407
|
+
return listFolder(join14(at.path, clean), home2, requestId3);
|
|
9203
9408
|
}
|
|
9204
9409
|
var byName;
|
|
9205
9410
|
var init_folders = __esm({
|
|
@@ -9263,7 +9468,7 @@ function taskOf2(ref, ctx) {
|
|
|
9263
9468
|
return taskClosed(t) ? no("closed", `task ${t.id} is closed`) : t;
|
|
9264
9469
|
}
|
|
9265
9470
|
function writable(s) {
|
|
9266
|
-
return s.source === "hook_only" ? no("read_only", `${s.name} is read-only`) : s.state === "exited" ? no("exited", `${s.name} has exited`) : null;
|
|
9471
|
+
return s.source === "hook_only" || isOmpSeat2(s) ? no("read_only", `${s.name} is read-only`) : s.state === "exited" ? no("exited", `${s.name} has exited`) : null;
|
|
9267
9472
|
}
|
|
9268
9473
|
function cardRefusal(row3) {
|
|
9269
9474
|
if (row3.action !== "session.decide" || !row3.detailCut || row3.args.decision !== "accept") return null;
|
|
@@ -9316,6 +9521,7 @@ var init_actions2 = __esm({
|
|
|
9316
9521
|
"src/daemon/actions.ts"() {
|
|
9317
9522
|
"use strict";
|
|
9318
9523
|
init_src();
|
|
9524
|
+
init_seats();
|
|
9319
9525
|
DECIDABLE = ["permission", "diff", "plan"];
|
|
9320
9526
|
KIND = { permission: "permission", diff: "diff", plan: "plan" };
|
|
9321
9527
|
no = (code3, refused) => ({ refused, code: code3 });
|
|
@@ -9435,13 +9641,13 @@ ${p.body}` : p.text) }
|
|
|
9435
9641
|
});
|
|
9436
9642
|
|
|
9437
9643
|
// src/chat/guide.ts
|
|
9438
|
-
import { access, constants as constants2, readFile as
|
|
9439
|
-
import { delimiter, join as
|
|
9644
|
+
import { access, constants as constants2, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
9645
|
+
import { delimiter, join as join15 } from "path";
|
|
9440
9646
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9441
9647
|
async function readGuide(files = GUIDE_FILES) {
|
|
9442
9648
|
for (const f of files) {
|
|
9443
9649
|
try {
|
|
9444
|
-
return await
|
|
9650
|
+
return await readFile8(f, "utf8");
|
|
9445
9651
|
} catch {
|
|
9446
9652
|
}
|
|
9447
9653
|
}
|
|
@@ -9453,7 +9659,7 @@ async function installedAgents(path3) {
|
|
|
9453
9659
|
for (const tool of ToolSchema.options) {
|
|
9454
9660
|
for (const d of dirs) {
|
|
9455
9661
|
try {
|
|
9456
|
-
await access(
|
|
9662
|
+
await access(join15(d, AGENT_BIN2[tool]), constants2.X_OK);
|
|
9457
9663
|
found.push(tool);
|
|
9458
9664
|
break;
|
|
9459
9665
|
} catch {
|
|
@@ -9485,7 +9691,7 @@ function ledgeMd(info) {
|
|
|
9485
9691
|
].join("\n");
|
|
9486
9692
|
}
|
|
9487
9693
|
async function writeLedgeMd(dir, info) {
|
|
9488
|
-
await writeFile8(
|
|
9694
|
+
await writeFile8(join15(dir, LEDGE_MD), ledgeMd(info));
|
|
9489
9695
|
}
|
|
9490
9696
|
var LEDGE_MD, GUIDE_FILES, AGENT_BIN2, RISK;
|
|
9491
9697
|
var init_guide = __esm({
|
|
@@ -9500,8 +9706,8 @@ var init_guide = __esm({
|
|
|
9500
9706
|
});
|
|
9501
9707
|
|
|
9502
9708
|
// src/chat/notes.ts
|
|
9503
|
-
import { open as
|
|
9504
|
-
import { join as
|
|
9709
|
+
import { open as open3, readdir as readdir4, stat as stat5, writeFile as writeFile9 } from "fs/promises";
|
|
9710
|
+
import { join as join16 } from "path";
|
|
9505
9711
|
function scalarValue(raw) {
|
|
9506
9712
|
const v2 = raw.trim();
|
|
9507
9713
|
const q = v2[0];
|
|
@@ -9533,7 +9739,7 @@ function copyName(file, taken) {
|
|
|
9533
9739
|
return name;
|
|
9534
9740
|
}
|
|
9535
9741
|
async function head(path3, max) {
|
|
9536
|
-
const fh = await
|
|
9742
|
+
const fh = await open3(path3, "r");
|
|
9537
9743
|
try {
|
|
9538
9744
|
const buf2 = Buffer.alloc(max);
|
|
9539
9745
|
const { bytesRead } = await fh.read(buf2, 0, max, 0);
|
|
@@ -9552,12 +9758,12 @@ async function writeNotes(dir, from, steps, max = NOTE_MAX2) {
|
|
|
9552
9758
|
if (!files.length) lines.push(`- (none: the user can add Markdown files to \`${from}\`, with an optional front matter \`title\` and \`when\`)`);
|
|
9553
9759
|
const taken = /* @__PURE__ */ new Set();
|
|
9554
9760
|
for (const file of files.slice(0, NOTES_MAX)) {
|
|
9555
|
-
const path3 =
|
|
9761
|
+
const path3 = join16(from, file);
|
|
9556
9762
|
let text7;
|
|
9557
9763
|
let size;
|
|
9558
9764
|
let mtime;
|
|
9559
9765
|
try {
|
|
9560
|
-
const st = await
|
|
9766
|
+
const st = await stat5(path3);
|
|
9561
9767
|
size = st.size;
|
|
9562
9768
|
mtime = st.mtime.toISOString();
|
|
9563
9769
|
text7 = await head(path3, max);
|
|
@@ -9574,15 +9780,15 @@ async function writeNotes(dir, from, steps, max = NOTE_MAX2) {
|
|
|
9574
9780
|
const when = fields.when?.trim() ? `when: ${line(fields.when)}` : `first line: ${line(body.split("\n").find((l) => l.trim()) ?? "") || "(empty)"}`;
|
|
9575
9781
|
const truncated = size > max;
|
|
9576
9782
|
const name = copyName(file, taken);
|
|
9577
|
-
await writeFile9(
|
|
9783
|
+
await writeFile9(join16(dir, name), truncated ? `${text7}
|
|
9578
9784
|
|
|
9579
9785
|
[truncated by Ledge: the first ${max} of ${size} bytes]
|
|
9580
9786
|
` : text7);
|
|
9581
|
-
steps.set(name, { kind: "repo", name: file, path:
|
|
9787
|
+
steps.set(name, { kind: "repo", name: file, path: join16(from, file) });
|
|
9582
9788
|
lines.push(`- ${name} \u2014 \xAB ${title3} \xBB \u2014 ${when} \u2014 modified ${mtime}${truncated ? ` \u2014 TRUNCATED: only the first ${max} of ${size} bytes are copied` : ""}`);
|
|
9583
9789
|
}
|
|
9584
9790
|
if (files.length > NOTES_MAX) lines.push(`- (${files.length - NOTES_MAX} more notes not copied: Ledge copies ${NOTES_MAX} at most)`);
|
|
9585
|
-
await writeFile9(
|
|
9791
|
+
await writeFile9(join16(dir, NOTES_INDEX), [...lines, ""].join("\n"));
|
|
9586
9792
|
}
|
|
9587
9793
|
var NOTE_MAX2, NOTES_MAX, NOTES_INDEX, unquote, line;
|
|
9588
9794
|
var init_notes = __esm({
|
|
@@ -9601,8 +9807,8 @@ var init_notes = __esm({
|
|
|
9601
9807
|
|
|
9602
9808
|
// src/chat/context.ts
|
|
9603
9809
|
import { mkdir as mkdir9, rm as rm2, writeFile as writeFile10 } from "fs/promises";
|
|
9604
|
-
import { homedir as
|
|
9605
|
-
import { basename as basename8, join as
|
|
9810
|
+
import { homedir as homedir8 } from "os";
|
|
9811
|
+
import { basename as basename8, join as join17, resolve as resolve5 } from "path";
|
|
9606
9812
|
async function writeContext(dir, input) {
|
|
9607
9813
|
await rm2(dir, { recursive: true, force: true });
|
|
9608
9814
|
await mkdir9(dir, { recursive: true });
|
|
@@ -9631,29 +9837,29 @@ async function writeContext(dir, input) {
|
|
|
9631
9837
|
const pane = await input.capture(s).catch(() => null);
|
|
9632
9838
|
if (pane?.length) {
|
|
9633
9839
|
const f = `pane-${s.id}.txt`;
|
|
9634
|
-
await writeFile10(
|
|
9840
|
+
await writeFile10(join17(dir, f), pane.join("\n"));
|
|
9635
9841
|
steps.set(f, { kind: "pane", id: s.id, name: s.name });
|
|
9636
9842
|
lines.push(`- terminal, last lines: ${f}`);
|
|
9637
9843
|
}
|
|
9638
9844
|
if (s.lastReply?.text.trim()) {
|
|
9639
9845
|
const f = `reply-${s.id}.md`;
|
|
9640
|
-
await writeFile10(
|
|
9846
|
+
await writeFile10(join17(dir, f), s.lastReply.text);
|
|
9641
9847
|
steps.set(f, { kind: "reply", id: s.id, name: s.name });
|
|
9642
9848
|
lines.push(`- last reply (${s.lastReply.at}): ${f}`);
|
|
9643
9849
|
}
|
|
9644
9850
|
const g = await input.git(s.cwd).catch(() => null);
|
|
9645
9851
|
if (g) {
|
|
9646
9852
|
const f = `git-${s.id}.txt`;
|
|
9647
|
-
await writeFile10(
|
|
9853
|
+
await writeFile10(join17(dir, f), g);
|
|
9648
9854
|
steps.set(f, { kind: "git", id: s.id, name: s.name });
|
|
9649
9855
|
lines.push(`- git status, log and diff stat: ${f}`);
|
|
9650
9856
|
}
|
|
9651
9857
|
lines.push("");
|
|
9652
9858
|
}
|
|
9653
|
-
await writeFile10(
|
|
9859
|
+
await writeFile10(join17(dir, "sessions.md"), lines.join("\n"));
|
|
9654
9860
|
steps.set("sessions.md", { kind: "sessions" });
|
|
9655
9861
|
const recents = input.recents ?? [];
|
|
9656
|
-
await writeFile10(
|
|
9862
|
+
await writeFile10(join17(dir, "folders.md"), [
|
|
9657
9863
|
"# Recent folders",
|
|
9658
9864
|
"",
|
|
9659
9865
|
"The folders the user started sessions in, most recent first.",
|
|
@@ -9661,7 +9867,7 @@ async function writeContext(dir, input) {
|
|
|
9661
9867
|
...recents.length ? recents.map((r) => `- ${r.project}: ${r.cwd} (last used ${r.lastAt})`) : ["- (none yet)"],
|
|
9662
9868
|
""
|
|
9663
9869
|
].join("\n"));
|
|
9664
|
-
if (withProjects) await writeFile10(
|
|
9870
|
+
if (withProjects) await writeFile10(join17(dir, "projects.md"), [
|
|
9665
9871
|
"# Projects",
|
|
9666
9872
|
"",
|
|
9667
9873
|
...projects.projects.length ? projects.projects.flatMap((p) => [`## ${oneLine(p.name)}`, ...p.description.trim() ? [oneLine(p.description)] : [], "", ...p.repos.map((r) => `- ${r.machine}: ${r.path}`), ""]) : ["No projects.", ""],
|
|
@@ -9679,7 +9885,7 @@ async function writeContext(dir, input) {
|
|
|
9679
9885
|
async function writeTasksContext(dir, taskList, steps) {
|
|
9680
9886
|
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
9681
9887
|
const shown = taskList.filter((t) => !taskClosed(t) || t.updatedAt.slice(0, 10) === day);
|
|
9682
|
-
await writeFile10(
|
|
9888
|
+
await writeFile10(join17(dir, "tasks.md"), [
|
|
9683
9889
|
"# Tasks",
|
|
9684
9890
|
"",
|
|
9685
9891
|
"Open tasks and those closed today. A giver `Ledge` is the user, through you.",
|
|
@@ -9691,7 +9897,7 @@ async function writeTasksContext(dir, taskList, steps) {
|
|
|
9691
9897
|
}
|
|
9692
9898
|
function coversHome(path3) {
|
|
9693
9899
|
const p = resolve5(path3);
|
|
9694
|
-
const home2 = resolve5(
|
|
9900
|
+
const home2 = resolve5(homedir8());
|
|
9695
9901
|
return p === home2 || home2.startsWith(p.endsWith("/") ? p : `${p}/`);
|
|
9696
9902
|
}
|
|
9697
9903
|
function stepFor(path3, ctx) {
|
|
@@ -9730,14 +9936,14 @@ var LEDGE_VERSION;
|
|
|
9730
9936
|
var init_version = __esm({
|
|
9731
9937
|
"src/version.ts"() {
|
|
9732
9938
|
"use strict";
|
|
9733
|
-
LEDGE_VERSION = true ? "0.
|
|
9939
|
+
LEDGE_VERSION = true ? "0.41.0-snapshot.41716003612.1" : "0.0.0-dev";
|
|
9734
9940
|
}
|
|
9735
9941
|
});
|
|
9736
9942
|
|
|
9737
9943
|
// src/chat/forge.ts
|
|
9738
9944
|
import { execFile as execFile4 } from "child_process";
|
|
9739
9945
|
import { writeFile as writeFile11 } from "fs/promises";
|
|
9740
|
-
import { join as
|
|
9946
|
+
import { join as join18 } from "path";
|
|
9741
9947
|
function forgeOf(remote) {
|
|
9742
9948
|
const id = repositoryId(remote);
|
|
9743
9949
|
if (!id) return null;
|
|
@@ -9802,12 +10008,12 @@ function createForge(deps = {}) {
|
|
|
9802
10008
|
return;
|
|
9803
10009
|
}
|
|
9804
10010
|
const parts2 = await Promise.all(local.map((r) => section(r.path)));
|
|
9805
|
-
await writeFile11(
|
|
10011
|
+
await writeFile11(join18(ctx.dir, file), parts2.flatMap((s) => s.lines).join("\n"));
|
|
9806
10012
|
const sources = parts2.flatMap((s) => s.source ? [s.source] : []);
|
|
9807
10013
|
ctx.steps.set(file, { kind: "repo", name, path: sources.join(", ") || file });
|
|
9808
10014
|
index2.push(`- ${name}: ${file}`);
|
|
9809
10015
|
}));
|
|
9810
|
-
await writeFile11(
|
|
10016
|
+
await writeFile11(join18(ctx.dir, "forge.md"), [...index2, ""].join("\n"));
|
|
9811
10017
|
}
|
|
9812
10018
|
};
|
|
9813
10019
|
}
|
|
@@ -10074,7 +10280,7 @@ var init_codex2 = __esm({
|
|
|
10074
10280
|
// src/chat/cursor.ts
|
|
10075
10281
|
import { spawn as nodeSpawn5 } from "child_process";
|
|
10076
10282
|
import { copyFileSync, writeFileSync } from "fs";
|
|
10077
|
-
import { extname, join as
|
|
10283
|
+
import { extname, join as join19 } from "path";
|
|
10078
10284
|
function cursorArgs(o) {
|
|
10079
10285
|
return [
|
|
10080
10286
|
"-p",
|
|
@@ -10116,10 +10322,10 @@ function parseCursorLine(line2) {
|
|
|
10116
10322
|
}
|
|
10117
10323
|
function runCursor(o, onEvent, spawnImpl = nodeSpawn5) {
|
|
10118
10324
|
const [file = "cursor-agent", ...pre] = o.bin ?? ["cursor-agent"];
|
|
10119
|
-
writeFileSync(
|
|
10325
|
+
writeFileSync(join19(o.cwd, "AGENTS.md"), `${o.persona ?? buildPersona("cursor")}
|
|
10120
10326
|
`);
|
|
10121
10327
|
const copies = (o.images ?? []).map((img, n) => {
|
|
10122
|
-
const to =
|
|
10328
|
+
const to = join19(o.cwd, `image-${n + 1}${extname(img.path)}`);
|
|
10123
10329
|
copyFileSync(img.path, to);
|
|
10124
10330
|
return to;
|
|
10125
10331
|
});
|
|
@@ -10203,9 +10409,9 @@ var init_omp = __esm({
|
|
|
10203
10409
|
|
|
10204
10410
|
// src/chat/service.ts
|
|
10205
10411
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10206
|
-
import { mkdir as mkdir10, readFile as
|
|
10207
|
-
import { homedir as
|
|
10208
|
-
import { basename as basename9, dirname as dirname6, join as
|
|
10412
|
+
import { mkdir as mkdir10, readFile as readFile9, rm as rm3, writeFile as writeFile12 } from "fs/promises";
|
|
10413
|
+
import { homedir as homedir9 } from "os";
|
|
10414
|
+
import { basename as basename9, dirname as dirname6, join as join20, resolve as resolve6 } from "path";
|
|
10209
10415
|
function droppedNote(total, kept, reasons, counted) {
|
|
10210
10416
|
const dropped = total - kept;
|
|
10211
10417
|
if (dropped <= 0) return "";
|
|
@@ -10226,7 +10432,7 @@ function createChat(deps) {
|
|
|
10226
10432
|
const now2 = deps.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10227
10433
|
const today = deps.today ?? (() => now2().slice(0, 10));
|
|
10228
10434
|
const uuid = deps.uuid ?? randomUUID7;
|
|
10229
|
-
const dayFile =
|
|
10435
|
+
const dayFile = join20(deps.home, "chat.json");
|
|
10230
10436
|
let turns2 = [];
|
|
10231
10437
|
let turnsDay = "";
|
|
10232
10438
|
let busy = false;
|
|
@@ -10249,7 +10455,7 @@ function createChat(deps) {
|
|
|
10249
10455
|
const day = today();
|
|
10250
10456
|
if (!fresh && !freshNext) {
|
|
10251
10457
|
try {
|
|
10252
|
-
const saved = JSON.parse(await
|
|
10458
|
+
const saved = JSON.parse(await readFile9(dayFile, "utf8"));
|
|
10253
10459
|
if (saved.day === day && saved.sessionId && (saved.tool ?? "claude") === tool) return { sessionId: saved.sessionId, resume: true };
|
|
10254
10460
|
} catch {
|
|
10255
10461
|
}
|
|
@@ -10265,7 +10471,7 @@ function createChat(deps) {
|
|
|
10265
10471
|
const p = await deps.tmux.capture(s.tmuxSession, PANE_LINES);
|
|
10266
10472
|
return p === null ? null : p.split("\n");
|
|
10267
10473
|
};
|
|
10268
|
-
const contextDir =
|
|
10474
|
+
const contextDir = join20(deps.home, "chat", "context");
|
|
10269
10475
|
async function proposalFrom(raw, tool, qid) {
|
|
10270
10476
|
const parsed = parseActionBlock("session", raw);
|
|
10271
10477
|
if ("error" in parsed) {
|
|
@@ -10342,7 +10548,7 @@ function createChat(deps) {
|
|
|
10342
10548
|
for (const r of block2.repos) {
|
|
10343
10549
|
try {
|
|
10344
10550
|
const path3 = await resolveFolder(r.path, deps.userHome);
|
|
10345
|
-
const wide = tooWide(path3, resolve6(deps.userHome ??
|
|
10551
|
+
const wide = tooWide(path3, resolve6(deps.userHome ?? homedir9()));
|
|
10346
10552
|
if (wide) {
|
|
10347
10553
|
log(`chat ${qid}: project path dropped: ${wide}: ${path3}`);
|
|
10348
10554
|
continue;
|
|
@@ -10458,7 +10664,7 @@ function createChat(deps) {
|
|
|
10458
10664
|
let resultError = null;
|
|
10459
10665
|
const handle2 = runTool(tool, { question: mine.told.text ? `${mine.told.text}
|
|
10460
10666
|
|
|
10461
|
-
${turn.question}` : turn.question, cwd: ctx.dir, addDirs: ctx.repoPaths, sessionId: sessionId2, resume, env, bin: deps.bins?.[tool] ?? deps.bin, ...images.length > 0 ? { images } : {}, ...tool === "omp" ? { sessionDir:
|
|
10667
|
+
${turn.question}` : turn.question, cwd: ctx.dir, addDirs: ctx.repoPaths, sessionId: sessionId2, resume, env, bin: deps.bins?.[tool] ?? deps.bin, ...images.length > 0 ? { images } : {}, ...tool === "omp" ? { sessionDir: join20(deps.home, "chat", "omp", sessionId2) } : {} }, (e) => {
|
|
10462
10668
|
if (e.type === "tool") {
|
|
10463
10669
|
const step3 = e.path ? stepFor(e.path, ctx) : null;
|
|
10464
10670
|
if (step3 && !turn.steps.some((s) => sameStep(s, step3))) {
|
|
@@ -10745,8 +10951,8 @@ var init_service = __esm({
|
|
|
10745
10951
|
});
|
|
10746
10952
|
|
|
10747
10953
|
// src/chat/threads.ts
|
|
10748
|
-
import { readFile as
|
|
10749
|
-
import { join as
|
|
10954
|
+
import { readFile as readFile10, rm as rm4 } from "fs/promises";
|
|
10955
|
+
import { join as join21 } from "path";
|
|
10750
10956
|
function createSlots(max = 3) {
|
|
10751
10957
|
let used = 0;
|
|
10752
10958
|
return {
|
|
@@ -10767,7 +10973,7 @@ function createChatThreads(deps) {
|
|
|
10767
10973
|
const devices = /* @__PURE__ */ new Map();
|
|
10768
10974
|
const emitters = /* @__PURE__ */ new Map();
|
|
10769
10975
|
const dropping = /* @__PURE__ */ new Map();
|
|
10770
|
-
const deviceHome = (id) =>
|
|
10976
|
+
const deviceHome = (id) => join21(deps.home, "mobile", "chat", id);
|
|
10771
10977
|
const device = (id) => {
|
|
10772
10978
|
checkId(id);
|
|
10773
10979
|
if (dropping.has(id)) throw new Error("device thread is being dropped");
|
|
@@ -10796,7 +11002,7 @@ function createChatThreads(deps) {
|
|
|
10796
11002
|
/** The PC's tool of the day file, whatever its day: `claude` without one. */
|
|
10797
11003
|
async deviceTool() {
|
|
10798
11004
|
try {
|
|
10799
|
-
const t = JSON.parse(await
|
|
11005
|
+
const t = JSON.parse(await readFile10(join21(deps.home, "chat.json"), "utf8")).tool;
|
|
10800
11006
|
return t === "claude" || t === "codex" || t === "cursor" || t === "omp" ? t : "claude";
|
|
10801
11007
|
} catch {
|
|
10802
11008
|
return "claude";
|
|
@@ -10963,7 +11169,7 @@ var init_island2 = __esm({
|
|
|
10963
11169
|
|
|
10964
11170
|
// src/daemon/documents.ts
|
|
10965
11171
|
import { constants as constants3 } from "fs";
|
|
10966
|
-
import { open as
|
|
11172
|
+
import { open as open4, realpath } from "fs/promises";
|
|
10967
11173
|
import { isAbsolute as isAbsolute3, dirname as dirname7, extname as extname2, resolve as resolve7 } from "path";
|
|
10968
11174
|
async function readDocument(request2, context) {
|
|
10969
11175
|
const source2 = request2.path;
|
|
@@ -10984,10 +11190,10 @@ async function readDocument(request2, context) {
|
|
|
10984
11190
|
async function readAt(request2, path3) {
|
|
10985
11191
|
let file;
|
|
10986
11192
|
try {
|
|
10987
|
-
file = await
|
|
10988
|
-
const
|
|
10989
|
-
if (!
|
|
10990
|
-
if (
|
|
11193
|
+
file = await open4(path3, constants3.O_RDONLY | constants3.O_NONBLOCK);
|
|
11194
|
+
const stat8 = await file.stat();
|
|
11195
|
+
if (!stat8.isFile()) return failure(request2, "not_file");
|
|
11196
|
+
if (stat8.size > DOCUMENT_MAX_BYTES) return failure(request2, "too_large");
|
|
10991
11197
|
const chunk = Buffer.allocUnsafe(64 * 1024);
|
|
10992
11198
|
const parts2 = [];
|
|
10993
11199
|
let bytes4 = 0;
|
|
@@ -11010,7 +11216,7 @@ async function readAt(request2, path3) {
|
|
|
11010
11216
|
path: await realpath(path3),
|
|
11011
11217
|
text: text7,
|
|
11012
11218
|
bytes: bytes4,
|
|
11013
|
-
modifiedAt:
|
|
11219
|
+
modifiedAt: stat8.mtime.toISOString()
|
|
11014
11220
|
};
|
|
11015
11221
|
} catch (e) {
|
|
11016
11222
|
return failure(request2, errorCode(e));
|
|
@@ -11039,9 +11245,9 @@ var init_documents2 = __esm({
|
|
|
11039
11245
|
|
|
11040
11246
|
// src/daemon/models.ts
|
|
11041
11247
|
import { execFile as execFile5 } from "child_process";
|
|
11042
|
-
import { readFile as
|
|
11043
|
-
import { homedir as
|
|
11044
|
-
import { join as
|
|
11248
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
11249
|
+
import { homedir as homedir10 } from "os";
|
|
11250
|
+
import { join as join22 } from "path";
|
|
11045
11251
|
function claudeModels(settingsModel) {
|
|
11046
11252
|
const efforts = [...CLAUDE_EFFORTS];
|
|
11047
11253
|
const models = CLAUDE_MODELS.map((m) => ({ ...m, efforts, ...m.id === settingsModel ? { isDefault: true } : {} }));
|
|
@@ -11085,15 +11291,15 @@ function codexConfig(toml) {
|
|
|
11085
11291
|
function createModels(deps = {}) {
|
|
11086
11292
|
const env = deps.env ?? (async () => process.env);
|
|
11087
11293
|
const run4 = deps.run ?? execRun2(env);
|
|
11088
|
-
const readText2 = deps.readText ?? ((p) =>
|
|
11294
|
+
const readText2 = deps.readText ?? ((p) => readFile11(p, "utf8").catch(() => ""));
|
|
11089
11295
|
const now2 = deps.now ?? Date.now, ttl = deps.ttlMs ?? MODELS_TTL_MS;
|
|
11090
11296
|
const cache = /* @__PURE__ */ new Map();
|
|
11091
11297
|
const flying = /* @__PURE__ */ new Map();
|
|
11092
11298
|
async function ask3(tool) {
|
|
11093
11299
|
const e = await env();
|
|
11094
|
-
const home2 = e.HOME ??
|
|
11300
|
+
const home2 = e.HOME ?? homedir10();
|
|
11095
11301
|
if (tool === "claude") {
|
|
11096
|
-
const settings = await readText2(
|
|
11302
|
+
const settings = await readText2(join22(e.CLAUDE_CONFIG_DIR ?? join22(home2, ".claude"), "settings.json"));
|
|
11097
11303
|
let model;
|
|
11098
11304
|
try {
|
|
11099
11305
|
model = settings ? JSON.parse(settings).model : void 0;
|
|
@@ -11109,7 +11315,7 @@ function createModels(deps = {}) {
|
|
|
11109
11315
|
if (r.code === null) throw new Error("not installed");
|
|
11110
11316
|
if (r.code !== 0) throw new Error(r.stderr.trim().split("\n").pop() || `exit ${r.code}`);
|
|
11111
11317
|
if (tool === "cursor") return parseCursorModels(r.stdout);
|
|
11112
|
-
return parseCodexModels(r.stdout, codexConfig(await readText2(
|
|
11318
|
+
return parseCodexModels(r.stdout, codexConfig(await readText2(join22(e.CODEX_HOME ?? join22(home2, ".codex"), "config.toml"))));
|
|
11113
11319
|
}
|
|
11114
11320
|
return {
|
|
11115
11321
|
list(tool) {
|
|
@@ -11160,9 +11366,9 @@ var init_models2 = __esm({
|
|
|
11160
11366
|
|
|
11161
11367
|
// src/daemon/commands.ts
|
|
11162
11368
|
import { spawn as nodeSpawn7 } from "child_process";
|
|
11163
|
-
import { stat as
|
|
11164
|
-
import { homedir as
|
|
11165
|
-
import { join as
|
|
11369
|
+
import { stat as stat6 } from "fs/promises";
|
|
11370
|
+
import { homedir as homedir11 } from "os";
|
|
11371
|
+
import { join as join23 } from "path";
|
|
11166
11372
|
function claudeSlashRefusal(text7) {
|
|
11167
11373
|
const m = /^\/(\S+)(\s+\S[\s\S]*)?$/.exec(text7.trim());
|
|
11168
11374
|
if (!m) return null;
|
|
@@ -11271,13 +11477,13 @@ function probeClaude(o, spawnImpl = nodeSpawn7) {
|
|
|
11271
11477
|
function createCommands(deps = {}) {
|
|
11272
11478
|
const env = deps.env ?? (async () => process.env);
|
|
11273
11479
|
const claude = deps.claude ?? ((cwd, e) => probeClaude({ ...deps.claudeBin ? { bin: deps.claudeBin } : {}, cwd, env: e }));
|
|
11274
|
-
const mtime = deps.mtime ?? ((p) =>
|
|
11480
|
+
const mtime = deps.mtime ?? ((p) => stat6(p).then((s) => s.mtimeMs, () => null));
|
|
11275
11481
|
const now2 = deps.now ?? Date.now, ttl = deps.ttlMs ?? COMMANDS_TTL_MS;
|
|
11276
11482
|
const cache = /* @__PURE__ */ new Map();
|
|
11277
11483
|
const flying = /* @__PURE__ */ new Map();
|
|
11278
11484
|
async function mark(cwd, e) {
|
|
11279
|
-
const home2 = e.CLAUDE_CONFIG_DIR ??
|
|
11280
|
-
const paths2 = [
|
|
11485
|
+
const home2 = e.CLAUDE_CONFIG_DIR ?? join23(e.HOME ?? homedir11(), ".claude");
|
|
11486
|
+
const paths2 = [join23(cwd, ".claude", "commands"), join23(cwd, ".claude", "skills"), join23(home2, "commands"), join23(home2, "skills"), join23(home2, "plugins", "installed_plugins.json")];
|
|
11281
11487
|
return (await Promise.all(paths2.map(mtime))).join(",");
|
|
11282
11488
|
}
|
|
11283
11489
|
return {
|
|
@@ -11455,7 +11661,7 @@ var init_rigSpec = __esm({
|
|
|
11455
11661
|
});
|
|
11456
11662
|
|
|
11457
11663
|
// src/daemon/openrigRoles.ts
|
|
11458
|
-
import { basename as basename10, dirname as dirname8, isAbsolute as isAbsolute5, join as
|
|
11664
|
+
import { basename as basename10, dirname as dirname8, isAbsolute as isAbsolute5, join as join24, resolve as resolve9, sep as sep3 } from "path";
|
|
11459
11665
|
import { parse as parseYaml, stringify as stringify2, YAMLParseError } from "yaml";
|
|
11460
11666
|
function readLibrary(listed2) {
|
|
11461
11667
|
const out = [];
|
|
@@ -11487,15 +11693,15 @@ function parseSpec(text7) {
|
|
|
11487
11693
|
}
|
|
11488
11694
|
}
|
|
11489
11695
|
function specPath(p, specDir, home2, openrigHome) {
|
|
11490
|
-
if (p.startsWith("openrig-home:")) return
|
|
11696
|
+
if (p.startsWith("openrig-home:")) return join24(openrigHome, p.slice("openrig-home:".length));
|
|
11491
11697
|
if (p === "~") return home2;
|
|
11492
|
-
if (p.startsWith("~/")) return
|
|
11698
|
+
if (p.startsWith("~/")) return join24(home2, p.slice(2));
|
|
11493
11699
|
return isAbsolute5(p) ? resolve9(p) : resolve9(specDir, p);
|
|
11494
11700
|
}
|
|
11495
11701
|
function importPath(ref, specDir) {
|
|
11496
11702
|
const p = ref.startsWith("local:") ? resolve9(specDir, ref.slice(6)) : ref.startsWith("path:") ? resolve9(ref.slice(5)) : null;
|
|
11497
11703
|
if (!p) return null;
|
|
11498
|
-
return /\.ya?ml$/i.test(p) ? p :
|
|
11704
|
+
return /\.ya?ml$/i.test(p) ? p : join24(p, "agent.yaml");
|
|
11499
11705
|
}
|
|
11500
11706
|
function declared(spec, ctx, ns, origin) {
|
|
11501
11707
|
const out = [];
|
|
@@ -11724,7 +11930,7 @@ function layerOf(ownerRoot, path3, c) {
|
|
|
11724
11930
|
if (c.agentDir && root2 === c.agentDir) return c.profileFiles.has(path3) ? "profile" : "agent";
|
|
11725
11931
|
if (c.rigRoot && root2 === c.rigRoot) return path3 === c.cultureFile ? "culture" : c.memberFiles.has(path3) ? "member" : c.podFiles.has(path3) ? "pod" : "rig";
|
|
11726
11932
|
if (/[/\\]@openrig[/\\]cli[/\\]/.test(root2) || /[/\\]daemon[/\\]assets$/.test(root2)) return "openrig";
|
|
11727
|
-
if (under3(root2,
|
|
11933
|
+
if (under3(root2, join24(c.openrigHome, "state", "seats"))) return "seat";
|
|
11728
11934
|
return "unknown";
|
|
11729
11935
|
}
|
|
11730
11936
|
function layerOrigin(layer, c, path3) {
|
|
@@ -11734,7 +11940,7 @@ function layerOrigin(layer, c, path3) {
|
|
|
11734
11940
|
case "profile":
|
|
11735
11941
|
return { kind: "here", key: "profiles.startup.files" };
|
|
11736
11942
|
case "culture":
|
|
11737
|
-
return { kind: "inherited", from: "rig", ref: c.rig, key: "culture_file", ...c.rigRoot ? { path:
|
|
11943
|
+
return { kind: "inherited", from: "rig", ref: c.rig, key: "culture_file", ...c.rigRoot ? { path: join24(c.rigRoot, path3) } : {} };
|
|
11738
11944
|
case "rig":
|
|
11739
11945
|
return { kind: "inherited", from: "rig", ref: c.rig };
|
|
11740
11946
|
case "pod":
|
|
@@ -11762,12 +11968,12 @@ async function seatView(s, spec, profile, io, openrigHome, plugins) {
|
|
|
11762
11968
|
const cwdV = str10(node2.cwd) ?? str10(shown.cwd);
|
|
11763
11969
|
const cwd = cwdV ? { value: cwdV, origin: memberOrigin("cwd") } : { value: null, origin: { kind: "unknown", why: "not_exposed" } };
|
|
11764
11970
|
const cultureV = str10(s.rigDoc.culture_file) ?? str10(s.rigDoc.cultureFile);
|
|
11765
|
-
const cultureFile = sourced(cultureV, { kind: "inherited", from: "rig", ref: s.rig, key: "culture_file", ...cultureV && s.rigRoot ? { path:
|
|
11971
|
+
const cultureFile = sourced(cultureV, { kind: "inherited", from: "rig", ref: s.rig, key: "culture_file", ...cultureV && s.rigRoot ? { path: join24(s.rigRoot, cultureV) } : {} });
|
|
11766
11972
|
const base3 = s.rigRoot ?? (s.rigSpecPath ? dirname8(s.rigSpecPath) : "/");
|
|
11767
11973
|
const memberStartup = writtenStartup(m.startup, "startup", "member", base3, (key) => memberOrigin(key));
|
|
11768
11974
|
const pod = s.written?.pod ?? {};
|
|
11769
11975
|
const effectiveRuntime = str10(node2.runtime) ?? runtime.value ?? void 0;
|
|
11770
|
-
const into = cwdV ?
|
|
11976
|
+
const into = cwdV ? join24(cwdV, guidanceFile(effectiveRuntime, s.rigDoc)) : void 0;
|
|
11771
11977
|
const profileName = str10(m.profile) ?? str10(shown.profile) ?? "default";
|
|
11772
11978
|
const lc = {
|
|
11773
11979
|
agentDir: s.agentDir,
|
|
@@ -12003,10 +12209,14 @@ var init_openrigRoles2 = __esm({
|
|
|
12003
12209
|
import { execFile as execFile6 } from "child_process";
|
|
12004
12210
|
import { get as httpGet } from "http";
|
|
12005
12211
|
import { existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
|
|
12006
|
-
import { cp, mkdir as mkdir11, open as openFile, readFile as
|
|
12212
|
+
import { cp, mkdir as mkdir11, open as openFile, readFile as readFile12, stat as statFile, writeFile as writeFile13 } from "fs/promises";
|
|
12007
12213
|
import { parse as parseYaml2 } from "yaml";
|
|
12008
|
-
import { homedir as
|
|
12009
|
-
import { basename as basename11, delimiter as delimiter2, dirname as dirname9, isAbsolute as isAbsolute6, join as
|
|
12214
|
+
import { homedir as homedir12 } from "os";
|
|
12215
|
+
import { basename as basename11, delimiter as delimiter2, dirname as dirname9, isAbsolute as isAbsolute6, join as join25, resolve as resolve10, sep as sep4 } from "path";
|
|
12216
|
+
function specSource(raw) {
|
|
12217
|
+
const s = str11(raw);
|
|
12218
|
+
return s === "builtin" || s?.startsWith("builtin_") ? "builtin" : "user";
|
|
12219
|
+
}
|
|
12010
12220
|
function toSeat(raw) {
|
|
12011
12221
|
const n = obj9(raw);
|
|
12012
12222
|
const logicalId = str11(n.logicalId), session = str11(n.canonicalSessionName);
|
|
@@ -12079,17 +12289,17 @@ function findRig(env, exists = existsSync2, list3 = (dir) => {
|
|
|
12079
12289
|
return [];
|
|
12080
12290
|
}
|
|
12081
12291
|
}) {
|
|
12082
|
-
for (const dir of (env.PATH ?? "").split(delimiter2)) if (dir && exists(
|
|
12083
|
-
const home2 = env.HOME ??
|
|
12084
|
-
const managed = (root2, sub) => list3(root2).filter((v2) => /^v?\d/.test(v2)).sort(byVersionDesc).map((v2) =>
|
|
12292
|
+
for (const dir of (env.PATH ?? "").split(delimiter2)) if (dir && exists(join25(dir, "rig"))) return dir;
|
|
12293
|
+
const home2 = env.HOME ?? homedir12();
|
|
12294
|
+
const managed = (root2, sub) => list3(root2).filter((v2) => /^v?\d/.test(v2)).sort(byVersionDesc).map((v2) => join25(root2, v2, sub));
|
|
12085
12295
|
const candidates = [
|
|
12086
|
-
...managed(
|
|
12087
|
-
...managed(
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12296
|
+
...managed(join25(home2, ".local", "share", "nvm"), "bin"),
|
|
12297
|
+
...managed(join25(env.NVM_DIR ?? join25(home2, ".nvm"), "versions", "node"), "bin"),
|
|
12298
|
+
join25(home2, ".volta", "bin"),
|
|
12299
|
+
join25(home2, ".npm-global", "bin"),
|
|
12300
|
+
join25(home2, ".local", "share", "pnpm")
|
|
12091
12301
|
];
|
|
12092
|
-
return candidates.find((dir) => exists(
|
|
12302
|
+
return candidates.find((dir) => exists(join25(dir, "rig"))) ?? null;
|
|
12093
12303
|
}
|
|
12094
12304
|
function readCheck(output) {
|
|
12095
12305
|
const j = obj9(parse2(output));
|
|
@@ -12118,11 +12328,11 @@ function localGet(port, path3, timeoutMs) {
|
|
|
12118
12328
|
function createOpenRig(deps = {}) {
|
|
12119
12329
|
const run4 = deps.run ?? execRun3(deps.env ?? (async () => process.env));
|
|
12120
12330
|
const files = deps.fs ?? realFs;
|
|
12121
|
-
const home2 = deps.home ??
|
|
12122
|
-
const rigsDir = deps.rigsDir ??
|
|
12331
|
+
const home2 = deps.home ?? homedir12();
|
|
12332
|
+
const rigsDir = deps.rigsDir ?? join25(home2, ".ledge", "rigs");
|
|
12123
12333
|
const now2 = deps.now ?? Date.now;
|
|
12124
12334
|
const roleIo = deps.roleIo ?? realRoleIo;
|
|
12125
|
-
const openrigHome = deps.openrigHome ?? process.env.OPENRIG_HOME ??
|
|
12335
|
+
const openrigHome = deps.openrigHome ?? process.env.OPENRIG_HOME ?? join25(home2, ".openrig");
|
|
12126
12336
|
const http = deps.http ?? (async (path3) => {
|
|
12127
12337
|
const port = (await state2()).daemon.port;
|
|
12128
12338
|
if (!port) return void 0;
|
|
@@ -12206,7 +12416,7 @@ function createOpenRig(deps = {}) {
|
|
|
12206
12416
|
const e = obj9(raw), name = str11(e.name), path3 = str11(e.resolvedSourcePath) ?? str11(e.sourcePath);
|
|
12207
12417
|
if (e.kind !== "rig" || !name || !path3 || name === KERNEL_RIG) continue;
|
|
12208
12418
|
const text7 = await files.read(path3).catch(() => null);
|
|
12209
|
-
const spec = text7 === null ? null : readSpec(text7, { name, source: e.sourceType
|
|
12419
|
+
const spec = text7 === null ? null : readSpec(text7, { name, source: specSource(e.sourceType), path: path3, ...str11(e.summary) ? { summary: str11(e.summary).trim() } : {} });
|
|
12210
12420
|
if (spec) out.push(spec);
|
|
12211
12421
|
}
|
|
12212
12422
|
return { specs: out.sort((a, b3) => a.source === b3.source ? a.name.localeCompare(b3.name) : a.source === "user" ? -1 : 1) };
|
|
@@ -12216,7 +12426,7 @@ function createOpenRig(deps = {}) {
|
|
|
12216
12426
|
if (acting) return { ok: false, plan: plan2, commands: [], error: "busy" };
|
|
12217
12427
|
acting = true;
|
|
12218
12428
|
try {
|
|
12219
|
-
const cwd = l.cwd === "~" ? home2 : l.cwd.startsWith("~/") ?
|
|
12429
|
+
const cwd = l.cwd === "~" ? home2 : l.cwd.startsWith("~/") ? join25(home2, l.cwd.slice(2)) : l.cwd;
|
|
12220
12430
|
if (!isAbsolute6(cwd) || !files.exists(cwd)) return { ok: false, plan: plan2, commands: [], error: "cwd_missing" };
|
|
12221
12431
|
const listed2 = await specs();
|
|
12222
12432
|
if (listed2.error) return { ok: false, plan: plan2, commands: [], error: listed2.error };
|
|
@@ -12228,17 +12438,17 @@ function createOpenRig(deps = {}) {
|
|
|
12228
12438
|
const rename7 = l.name !== spec.name;
|
|
12229
12439
|
if (changesSpec(l) || l.save || rename7 && !can2.name) {
|
|
12230
12440
|
const composed = composeSpec(parseYaml2(text7), dirname9(spec.path), l);
|
|
12231
|
-
dir =
|
|
12441
|
+
dir = join25(rigsDir, l.name);
|
|
12232
12442
|
await files.copyDir(dirname9(spec.path), dir);
|
|
12233
|
-
await files.write(
|
|
12234
|
-
source2 =
|
|
12443
|
+
await files.write(join25(dir, "rig.yaml"), composed.yaml);
|
|
12444
|
+
source2 = join25(dir, "rig.yaml");
|
|
12235
12445
|
yaml = composed.yaml;
|
|
12236
12446
|
seats = composed.seats;
|
|
12237
12447
|
} else {
|
|
12238
12448
|
yaml = text7;
|
|
12239
12449
|
seats = specSeats(spec);
|
|
12240
12450
|
}
|
|
12241
|
-
if (!dir && rename7 && !plan2) await files.write(
|
|
12451
|
+
if (!dir && rename7 && !plan2) await files.write(join25(rigsDir, l.name, "source.json"), JSON.stringify({ spec: spec.name, path: spec.path }));
|
|
12242
12452
|
const commands = [["up", source2, ...!dir && rename7 ? ["--name", l.name] : [], "--cwd", cwd, ...l.nonInterruptive ? ["--non-interruptive"] : [], ...plan2 ? ["--plan"] : ["--yes"], "--json"]];
|
|
12243
12453
|
if (!plan2 && l.save && dir) commands.push(["specs", "add", dir, "--json"]);
|
|
12244
12454
|
const shown = commands.map(showRigCommand);
|
|
@@ -12262,9 +12472,9 @@ function createOpenRig(deps = {}) {
|
|
|
12262
12472
|
}
|
|
12263
12473
|
}
|
|
12264
12474
|
async function rootOf(rig) {
|
|
12265
|
-
const mine =
|
|
12266
|
-
if (files.exists(
|
|
12267
|
-
const marker = await files.read(
|
|
12475
|
+
const mine = join25(rigsDir, rig);
|
|
12476
|
+
if (files.exists(join25(mine, "rig.yaml"))) return mine;
|
|
12477
|
+
const marker = await files.read(join25(mine, "source.json")).catch(() => null);
|
|
12268
12478
|
const path3 = marker === null ? void 0 : str11(obj9(parse2(marker)).path);
|
|
12269
12479
|
if (path3) return dirname9(path3);
|
|
12270
12480
|
const listed2 = await specs();
|
|
@@ -12294,7 +12504,7 @@ function createOpenRig(deps = {}) {
|
|
|
12294
12504
|
const member = memberOf(show, a.pod, a.from.slice(a.pod.length + 1));
|
|
12295
12505
|
const fragment2 = member ? fragmentOf(member, a.id, root2) : null;
|
|
12296
12506
|
if (!fragment2) return { ok: false, commands: [], ...none, error: "rig_root_unknown" };
|
|
12297
|
-
const path3 =
|
|
12507
|
+
const path3 = join25(rigsDir, rigName, "seats", `${a.pod}.${a.id}.json`);
|
|
12298
12508
|
await files.write(path3, JSON.stringify(fragment2, null, 2));
|
|
12299
12509
|
commands.push(["add", rig.id, a.pod, path3, ...root2 ? ["--rig-root", root2] : [], "--json"]);
|
|
12300
12510
|
}
|
|
@@ -12344,7 +12554,7 @@ function createOpenRig(deps = {}) {
|
|
|
12344
12554
|
const r = await run4(["spec", "show", rig.id, "--json"], STATUS_MS);
|
|
12345
12555
|
if (r.code !== 0) continue;
|
|
12346
12556
|
const root2 = rig.name === KERNEL_RIG ? null : await rootOf(rig.name).catch(() => null);
|
|
12347
|
-
const specFile = root2 ?
|
|
12557
|
+
const specFile = root2 ? join25(root2, "rig.yaml") : null;
|
|
12348
12558
|
const text7 = specFile ? await roleIo.read(specFile) : null;
|
|
12349
12559
|
const written = parseSpec(text7);
|
|
12350
12560
|
const shown = obj9(parse2(r.stdout));
|
|
@@ -12508,14 +12718,14 @@ var init_openrig2 = __esm({
|
|
|
12508
12718
|
if (!dir) return { code: null, stdout: "", stderr: "rig: command not found" };
|
|
12509
12719
|
const e = { ...base3, PATH: [dir, base3.PATH].filter(Boolean).join(delimiter2), NO_COLOR: "1", CLICOLOR: "0", FORCE_COLOR: "0" };
|
|
12510
12720
|
return new Promise((res) => {
|
|
12511
|
-
execFile6(
|
|
12721
|
+
execFile6(join25(dir, "rig"), args, { env: e, timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
12512
12722
|
const code3 = !err ? 0 : err.code === "ENOENT" ? null : typeof err.code === "number" ? err.code : 1;
|
|
12513
12723
|
res({ code: code3, stdout: String(stdout), stderr: String(stderr) || (err && code3 !== 0 ? err.message : "") });
|
|
12514
12724
|
});
|
|
12515
12725
|
});
|
|
12516
12726
|
};
|
|
12517
12727
|
realRoleIo = {
|
|
12518
|
-
read: (p) =>
|
|
12728
|
+
read: (p) => readFile12(p, "utf8").catch(() => null),
|
|
12519
12729
|
stat: (p) => statFile(p).then((st) => ({ size: st.size, mtimeMs: st.mtimeMs, file: st.isFile() })).catch(() => null),
|
|
12520
12730
|
head: async (p, max) => {
|
|
12521
12731
|
const h = await openFile(p, "r").catch(() => null);
|
|
@@ -12533,7 +12743,7 @@ var init_openrig2 = __esm({
|
|
|
12533
12743
|
FILES_TTL_MS = 5 * 6e4;
|
|
12534
12744
|
HTTP_MS = 3e3;
|
|
12535
12745
|
realFs = {
|
|
12536
|
-
read: (p) =>
|
|
12746
|
+
read: (p) => readFile12(p, "utf8"),
|
|
12537
12747
|
exists: (p) => existsSync2(p),
|
|
12538
12748
|
copyDir: (from, to) => cp(from, to, { recursive: true, force: true, filter: (src) => basename11(src) !== "rig.yaml" }),
|
|
12539
12749
|
write: async (p, text7) => {
|
|
@@ -12553,7 +12763,7 @@ function goalOf(tags) {
|
|
|
12553
12763
|
return t ? t.slice(GOAL_TAG.length + 1) || null : null;
|
|
12554
12764
|
}
|
|
12555
12765
|
function parseTeam(body) {
|
|
12556
|
-
const m =
|
|
12766
|
+
const m = BLOCK4.exec(body);
|
|
12557
12767
|
if (!m) return null;
|
|
12558
12768
|
let raw;
|
|
12559
12769
|
try {
|
|
@@ -12578,13 +12788,13 @@ function parseTeam(body) {
|
|
|
12578
12788
|
launch: kind === "launch" ? { agents: typeof l.agents === "number" && Number.isInteger(l.agents) ? l.agents : null, runtimes: strings(l.runtimes), plan: text2(l.plan), writes: strings(l.writes), permissions: text2(l.permissions) } : null
|
|
12579
12789
|
};
|
|
12580
12790
|
}
|
|
12581
|
-
var GOAL_TAG, goalTag,
|
|
12791
|
+
var GOAL_TAG, goalTag, BLOCK4, obj10, text2, strings, roleOf3, withoutTeam;
|
|
12582
12792
|
var init_goalTeam = __esm({
|
|
12583
12793
|
"src/daemon/goalTeam.ts"() {
|
|
12584
12794
|
"use strict";
|
|
12585
12795
|
GOAL_TAG = "ledge-goal";
|
|
12586
12796
|
goalTag = (goalQitemId2) => `${GOAL_TAG}:${goalQitemId2}`;
|
|
12587
|
-
|
|
12797
|
+
BLOCK4 = /```ledge-team[^\n]*\n([\s\S]*?)```/;
|
|
12588
12798
|
obj10 = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : {};
|
|
12589
12799
|
text2 = (v2) => typeof v2 === "string" && v2.trim() ? v2.trim() : null;
|
|
12590
12800
|
strings = (v2) => Array.isArray(v2) ? v2.filter((x) => typeof x === "string" && x.trim() !== "").map((x) => x.trim()) : [];
|
|
@@ -12592,7 +12802,7 @@ var init_goalTeam = __esm({
|
|
|
12592
12802
|
const m = /^([A-Za-z0-9][A-Za-z0-9_]*)-([A-Za-z0-9][A-Za-z0-9_-]*)@/.exec(seat2);
|
|
12593
12803
|
return m ? `${m[1]}.${m[2]}` : null;
|
|
12594
12804
|
};
|
|
12595
|
-
withoutTeam = (body) => body.replace(
|
|
12805
|
+
withoutTeam = (body) => body.replace(BLOCK4, "").trim();
|
|
12596
12806
|
}
|
|
12597
12807
|
});
|
|
12598
12808
|
|
|
@@ -13217,7 +13427,7 @@ function createRelay(d) {
|
|
|
13217
13427
|
const now2 = d.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
13218
13428
|
const typing = d.typing ?? /* @__PURE__ */ new Set();
|
|
13219
13429
|
const sending = /* @__PURE__ */ new Set();
|
|
13220
|
-
const
|
|
13430
|
+
const open6 = (id) => free(d.store.get(id)) && !typing.has(id) && !d.closing?.has(id);
|
|
13221
13431
|
const emitTo = (thread) => (m) => {
|
|
13222
13432
|
try {
|
|
13223
13433
|
d.threads.emitterOf(thread)?.(m);
|
|
@@ -13261,14 +13471,14 @@ function createRelay(d) {
|
|
|
13261
13471
|
}
|
|
13262
13472
|
function kick(id) {
|
|
13263
13473
|
const q = queued().find((x) => x.relay.id === id);
|
|
13264
|
-
if (!q || !
|
|
13474
|
+
if (!q || !open6(id)) return;
|
|
13265
13475
|
void deliverAndKick(q.thread, q.qid, q.relay).catch((e) => log(`relay ${q.qid} failed: ${e.message}`));
|
|
13266
13476
|
}
|
|
13267
13477
|
async function deliverAndKick(thread, qid, r) {
|
|
13268
13478
|
const refused = await deliver(thread, qid, r);
|
|
13269
13479
|
if (refused) {
|
|
13270
13480
|
if (queued().some((q) => q.relay.id === r.id)) kick(r.id);
|
|
13271
|
-
else if (
|
|
13481
|
+
else if (open6(r.id)) d.next?.(r.id);
|
|
13272
13482
|
}
|
|
13273
13483
|
return refused;
|
|
13274
13484
|
}
|
|
@@ -13285,7 +13495,7 @@ function createRelay(d) {
|
|
|
13285
13495
|
}
|
|
13286
13496
|
return;
|
|
13287
13497
|
}
|
|
13288
|
-
if (
|
|
13498
|
+
if (open6(id)) kick(id);
|
|
13289
13499
|
} catch (e) {
|
|
13290
13500
|
log(`relay change handler failed: ${e.message}`);
|
|
13291
13501
|
}
|
|
@@ -13303,7 +13513,7 @@ function createRelay(d) {
|
|
|
13303
13513
|
mark(thread, qid, { error: m, code: STOPPED_CODE });
|
|
13304
13514
|
throw new Error(m);
|
|
13305
13515
|
}
|
|
13306
|
-
if (
|
|
13516
|
+
if (open6(r.id)) {
|
|
13307
13517
|
if (queued().some((q) => q.relay.id === r.id)) {
|
|
13308
13518
|
markQueued(thread, qid);
|
|
13309
13519
|
kick(r.id);
|
|
@@ -13324,7 +13534,7 @@ function createRelay(d) {
|
|
|
13324
13534
|
settle(id) {
|
|
13325
13535
|
try {
|
|
13326
13536
|
if (queued().some((q) => q.relay.id === id)) kick(id);
|
|
13327
|
-
else if (
|
|
13537
|
+
else if (open6(id)) d.next?.(id);
|
|
13328
13538
|
} catch (e) {
|
|
13329
13539
|
log(`relay settle failed: ${e.message}`);
|
|
13330
13540
|
}
|
|
@@ -13553,7 +13763,7 @@ var init_act = __esm({
|
|
|
13553
13763
|
|
|
13554
13764
|
// src/daemon/handover.ts
|
|
13555
13765
|
import { mkdirSync, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
|
|
13556
|
-
import { join as
|
|
13766
|
+
import { join as join26 } from "path";
|
|
13557
13767
|
function reliefOf(get, s) {
|
|
13558
13768
|
let cur = s;
|
|
13559
13769
|
for (let hops = 0; cur && hops < 50; hops++) {
|
|
@@ -13571,7 +13781,7 @@ function createHandovers(d) {
|
|
|
13571
13781
|
const now2 = d.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
13572
13782
|
const briefMs = d.briefMs ?? BRIEF_MS;
|
|
13573
13783
|
const waiting2 = /* @__PURE__ */ new Map();
|
|
13574
|
-
const file = (id) =>
|
|
13784
|
+
const file = (id) => join26(d.dir, `${id}.md`);
|
|
13575
13785
|
const mark = (id, h) => {
|
|
13576
13786
|
const cur = d.store.get(id);
|
|
13577
13787
|
if (cur) d.store.upsert({ ...cur, handover: { ...h, at: now2() } });
|
|
@@ -14025,7 +14235,7 @@ var init_broadcast2 = __esm({
|
|
|
14025
14235
|
});
|
|
14026
14236
|
|
|
14027
14237
|
// src/daemon/context.ts
|
|
14028
|
-
import { open as
|
|
14238
|
+
import { open as open5 } from "fs/promises";
|
|
14029
14239
|
function longWindow(model) {
|
|
14030
14240
|
if (!model) return false;
|
|
14031
14241
|
if (model.includes("[1m]")) return true;
|
|
@@ -14033,7 +14243,7 @@ function longWindow(model) {
|
|
|
14033
14243
|
return !!m && Number(m[1]) >= 5;
|
|
14034
14244
|
}
|
|
14035
14245
|
async function tail(path3) {
|
|
14036
|
-
const f = await
|
|
14246
|
+
const f = await open5(path3, "r");
|
|
14037
14247
|
try {
|
|
14038
14248
|
const { size } = await f.stat();
|
|
14039
14249
|
const start = Math.max(0, size - TAIL_BYTES2);
|
|
@@ -14117,7 +14327,7 @@ var init_context2 = __esm({
|
|
|
14117
14327
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
14118
14328
|
import { mkdtemp, rm as rm5 } from "fs/promises";
|
|
14119
14329
|
import { tmpdir } from "os";
|
|
14120
|
-
import { join as
|
|
14330
|
+
import { join as join27 } from "path";
|
|
14121
14331
|
function parseRoute(answer, context) {
|
|
14122
14332
|
const raw = answer.trim().replace(/^```(?:json)?\s*/, "").replace(/\s*```$/, "");
|
|
14123
14333
|
const result = RouteResultSchema.parse(JSON.parse(raw));
|
|
@@ -14143,7 +14353,7 @@ function createRouter(deps) {
|
|
|
14143
14353
|
let dir;
|
|
14144
14354
|
let timer2;
|
|
14145
14355
|
try {
|
|
14146
|
-
dir = await mkdtemp(
|
|
14356
|
+
dir = await mkdtemp(join27(tmpdir(), "ledge-routing-"));
|
|
14147
14357
|
const env = { ...await deps.env(), LEDGE_CHAT: "1" };
|
|
14148
14358
|
delete env.ANTHROPIC_API_KEY;
|
|
14149
14359
|
delete env.LEDGE_SESSION;
|
|
@@ -14379,7 +14589,16 @@ function compareVersions(a, b3) {
|
|
|
14379
14589
|
const d = (x[i] ?? 0) - (y[i] ?? 0);
|
|
14380
14590
|
if (d) return d > 0 ? 1 : -1;
|
|
14381
14591
|
}
|
|
14382
|
-
|
|
14592
|
+
if (a === b3) return 0;
|
|
14593
|
+
const ax = a.match(/-snapshot\.(\d+)\.(\d+)$/), bx = b3.match(/-snapshot\.(\d+)\.(\d+)$/);
|
|
14594
|
+
if (ax && bx) {
|
|
14595
|
+
for (const i of [1, 2]) {
|
|
14596
|
+
const x2 = BigInt(ax[i]), y2 = BigInt(bx[i]);
|
|
14597
|
+
if (x2 !== y2) return x2 > y2 ? 1 : -1;
|
|
14598
|
+
}
|
|
14599
|
+
return 0;
|
|
14600
|
+
}
|
|
14601
|
+
return a.includes("-") ? -1 : b3.includes("-") ? 1 : 0;
|
|
14383
14602
|
}
|
|
14384
14603
|
var parts;
|
|
14385
14604
|
var init_semver = __esm({
|
|
@@ -15173,15 +15392,15 @@ var init_operations = __esm({
|
|
|
15173
15392
|
});
|
|
15174
15393
|
|
|
15175
15394
|
// src/mobile/risk.ts
|
|
15176
|
-
import { homedir as
|
|
15177
|
-
import { resolve as resolve11, sep as sep5, join as
|
|
15395
|
+
import { homedir as homedir13 } from "os";
|
|
15396
|
+
import { resolve as resolve11, sep as sep5, join as join28 } from "path";
|
|
15178
15397
|
function isSensitive(cwd, p) {
|
|
15179
15398
|
if (p.includes("~")) return true;
|
|
15180
15399
|
const full = resolve11(cwd, p);
|
|
15181
15400
|
const segs = full.split(sep5);
|
|
15182
15401
|
if (segs.includes(".git") || segs.some((s) => s.startsWith(".env"))) return true;
|
|
15183
|
-
const home2 =
|
|
15184
|
-
return [
|
|
15402
|
+
const home2 = homedir13();
|
|
15403
|
+
return [join28(home2, ".ssh"), join28(home2, ".ledge")].some((d) => full === d || full.startsWith(d + sep5));
|
|
15185
15404
|
}
|
|
15186
15405
|
function classifyShell(command, cwd) {
|
|
15187
15406
|
if (PUSH.test(command)) return high("pushes");
|
|
@@ -16951,9 +17170,13 @@ var init_notifier = __esm({
|
|
|
16951
17170
|
// src/daemon/server.ts
|
|
16952
17171
|
import { createServer } from "http";
|
|
16953
17172
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
16954
|
-
import { homedir as
|
|
16955
|
-
import { basename as basename12, join as
|
|
17173
|
+
import { homedir as homedir14 } from "os";
|
|
17174
|
+
import { basename as basename12, join as join29, resolve as resolve12 } from "path";
|
|
16956
17175
|
import { WebSocketServer, WebSocket as WebSocket3 } from "ws";
|
|
17176
|
+
function withoutHarness(s) {
|
|
17177
|
+
const { pending: _p, lastReply: _r, transcriptPath: _t, agentSessionId: _a, agentSessionFile: _f, model: _m, effort: _e, modelNext: _n, queue: _q, backend: _b, ...rest } = s;
|
|
17178
|
+
return { ...rest, helpers: [] };
|
|
17179
|
+
}
|
|
16957
17180
|
function resumeKey(s) {
|
|
16958
17181
|
if (s.tool === "omp") return s.agentSessionFile;
|
|
16959
17182
|
if (s.agentSessionId) return s.agentSessionId;
|
|
@@ -17003,11 +17226,12 @@ async function startServer(opts) {
|
|
|
17003
17226
|
const agentEnv2 = opts.agentEnv ?? (async () => ({ ...process.env, ...await loginShellEnv() }));
|
|
17004
17227
|
const attachments = opts.attachments ?? new AttachmentStore(paths().attachments);
|
|
17005
17228
|
const reducer = new CaptureReducer();
|
|
17006
|
-
const threads = createChatThreads({ attachments, store, tmux, home: paths().dir, notesDir:
|
|
17229
|
+
const threads = createChatThreads({ attachments, store, tmux, home: paths().dir, notesDir: join29(paths().dir, "context"), userHome: opts.home, env: agentEnv2, bin: opts.claudeBin, now: now2, projects: () => projects, forge: createForge({ env: agentEnv2 }), tasks: () => tasks.all() });
|
|
17007
17230
|
const chat = opts.chat ?? threads.desktop;
|
|
17008
17231
|
const router = createRouter({ env: agentEnv2 });
|
|
17009
|
-
const omp2 = opts.omp ?? createOmpHost({ store, env: agentEnv2, dir:
|
|
17232
|
+
const omp2 = opts.omp ?? createOmpHost({ store, env: agentEnv2, dir: join29(paths().dir, "omp"), now: now2, attachments });
|
|
17010
17233
|
const openrig = opts.openrig ?? createOpenRig({ env: agentEnv2 });
|
|
17234
|
+
const ompSeatReadOnly = (s) => new Refusal(`${s.name} is the OpenRig OMP seat ${s.rig?.seat ?? ""}: Ledge follows its state only`, "read_only");
|
|
17011
17235
|
const rigOwned = (s) => new Refusal(`${s.name} is the OpenRig seat ${s.rig?.seat ?? s.tmuxSession ?? ""}: stop or restart it from OpenRig`, "read_only");
|
|
17012
17236
|
const adoptSeat = (id, seat2) => {
|
|
17013
17237
|
const session = store.get(id);
|
|
@@ -17020,9 +17244,22 @@ async function startServer(opts) {
|
|
|
17020
17244
|
const seatId = (seat2) => `rig-${seat2.replace(/[^A-Za-z0-9._-]/g, "-")}`;
|
|
17021
17245
|
async function discoverSeats(st) {
|
|
17022
17246
|
if (st.daemon.state !== "running") return;
|
|
17023
|
-
const followed = new
|
|
17247
|
+
const followed = new Map(store.all().filter((x) => x.rig && x.state !== "exited").map((x) => [x.rig.seat, x.id]));
|
|
17024
17248
|
for (const r of st.rigs) for (const n of r.nodes) {
|
|
17025
|
-
|
|
17249
|
+
const tool = SEAT_TOOLS[n.runtime];
|
|
17250
|
+
if (!tool || n.sessionStatus !== "running") continue;
|
|
17251
|
+
const live3 = followed.get(n.session);
|
|
17252
|
+
if (live3 !== void 0) {
|
|
17253
|
+
const s = store.get(live3);
|
|
17254
|
+
if (s && s.tool !== tool && (s.source === "rig" || s.source === "hook_only")) {
|
|
17255
|
+
if (s.source === "hook_only" && !await tmux.hasSession(n.session).catch(() => false)) continue;
|
|
17256
|
+
const cur = store.get(live3);
|
|
17257
|
+
if (!cur || cur.state === "exited" || cur.tool === tool) continue;
|
|
17258
|
+
store.upsert({ ...withoutHarness(cur), tool, state: "idle", source: "rig", tmuxSession: n.session, lastActivityAt: now2() });
|
|
17259
|
+
log(`openrig: seat ${n.session} now runs ${n.runtime}`);
|
|
17260
|
+
}
|
|
17261
|
+
continue;
|
|
17262
|
+
}
|
|
17026
17263
|
if (!await tmux.hasSession(n.session).catch(() => false)) continue;
|
|
17027
17264
|
const before2 = store.all().filter((x) => x.rig?.seat === n.session).sort((a, b3) => b3.lastActivityAt.localeCompare(a.lastActivityAt))[0];
|
|
17028
17265
|
const id = before2?.id ?? seatId(n.session), old = store.get(id), at = now2();
|
|
@@ -17031,13 +17268,14 @@ async function startServer(opts) {
|
|
|
17031
17268
|
if (old) {
|
|
17032
17269
|
if (old.archivedAt) store.unarchive(id, at);
|
|
17033
17270
|
const { exitedAt: _e, exitCode: _c, pending: _p, ...rest } = store.get(id);
|
|
17034
|
-
|
|
17271
|
+
const same2 = rest.tool === tool ? rest : { ...withoutHarness(rest), tool };
|
|
17272
|
+
store.upsert({ ...same2, state: "idle", tmuxSession: n.session, source: "rig", rig, lastActivityAt: at });
|
|
17035
17273
|
} else {
|
|
17036
17274
|
const name = pickName([...namesInUse(store.all()), ...heldNames(store.all())]);
|
|
17037
17275
|
store.upsert({
|
|
17038
17276
|
id,
|
|
17039
17277
|
name,
|
|
17040
|
-
tool
|
|
17278
|
+
tool,
|
|
17041
17279
|
cwd,
|
|
17042
17280
|
project: basename12(cwd) || r.name,
|
|
17043
17281
|
title: `${name} \xB7 ${n.logicalId}`,
|
|
@@ -17051,10 +17289,21 @@ async function startServer(opts) {
|
|
|
17051
17289
|
});
|
|
17052
17290
|
log(`openrig: seat ${n.session} followed as ${name}`);
|
|
17053
17291
|
}
|
|
17054
|
-
followed.
|
|
17292
|
+
followed.set(n.session, id);
|
|
17293
|
+
}
|
|
17294
|
+
if (!st.rigs.some((r) => r.nodes.length > 0)) return;
|
|
17295
|
+
const listed2 = new Set(st.rigs.flatMap((r) => r.nodes.map((n) => n.session)));
|
|
17296
|
+
const unsure = new Set(st.rigs.filter((r) => r.seats > 0 && r.nodes.length === 0).map((r) => r.name));
|
|
17297
|
+
for (const s of store.all()) {
|
|
17298
|
+
if (isOmpSeat2(s) && s.rig && s.state === "exited" && !isArchived(s) && !listed2.has(s.rig.seat) && !unsure.has(s.rig.name)) {
|
|
17299
|
+
store.archive(s.id, now2());
|
|
17300
|
+
log(`openrig: seat ${s.rig.seat} is gone from OpenRig`);
|
|
17301
|
+
}
|
|
17055
17302
|
}
|
|
17056
17303
|
}
|
|
17057
17304
|
const SEATS_EVERY_MS = 3e4;
|
|
17305
|
+
const ompSeats = opts.ompSeats ?? createOmpSeats({ store });
|
|
17306
|
+
ompSeats.start();
|
|
17058
17307
|
const seatTimer = setInterval(() => {
|
|
17059
17308
|
void openrig.state().then(discoverSeats).catch((e) => log(`openrig: seats not read: ${e.message}`));
|
|
17060
17309
|
}, SEATS_EVERY_MS);
|
|
@@ -17100,7 +17349,7 @@ async function startServer(opts) {
|
|
|
17100
17349
|
}).catch((e) => log(`openrig: seat ${seat2} not read: ${e.message}`));
|
|
17101
17350
|
};
|
|
17102
17351
|
const commands = opts.commands ?? createCommands({ env: agentEnv2, ...opts.claudeBin ? { claudeBin: opts.claudeBin } : {} });
|
|
17103
|
-
const models = opts.models ?? createModels({ env: agentEnv2, omp: async () => ompChoices(await omp2.catalog(opts.home ??
|
|
17352
|
+
const models = opts.models ?? createModels({ env: agentEnv2, omp: async () => ompChoices(await omp2.catalog(opts.home ?? homedir14())) });
|
|
17104
17353
|
const token = await ensureDaemonToken();
|
|
17105
17354
|
const httpServer = createServer(unauthorized);
|
|
17106
17355
|
const sockets = /* @__PURE__ */ new Set();
|
|
@@ -17140,7 +17389,7 @@ async function startServer(opts) {
|
|
|
17140
17389
|
const islandFile = opts.islandFile ?? paths().island;
|
|
17141
17390
|
let island = readIsland(islandFile);
|
|
17142
17391
|
const islandMsg = () => ({ type: "island", prefs: island });
|
|
17143
|
-
const contextFile = opts.contextFile ??
|
|
17392
|
+
const contextFile = opts.contextFile ?? join29(paths().dir, "context.json");
|
|
17144
17393
|
let contextPrefs = readContextPrefs(contextFile);
|
|
17145
17394
|
const contextMsg = () => ({ type: "context.prefs", prefs: contextPrefs });
|
|
17146
17395
|
const mobile = opts.mobile;
|
|
@@ -17239,7 +17488,7 @@ async function startServer(opts) {
|
|
|
17239
17488
|
tasks,
|
|
17240
17489
|
launch: (req) => launch3(req),
|
|
17241
17490
|
close: (s) => closeSession(s),
|
|
17242
|
-
dir:
|
|
17491
|
+
dir: join29(paths().dir, "handovers"),
|
|
17243
17492
|
now: now2,
|
|
17244
17493
|
...opts.handoverBriefMs !== void 0 ? { briefMs: opts.handoverBriefMs } : {}
|
|
17245
17494
|
});
|
|
@@ -17515,6 +17764,7 @@ async function startServer(opts) {
|
|
|
17515
17764
|
const s = store.get(id);
|
|
17516
17765
|
if (!s) return unknownSession();
|
|
17517
17766
|
if (s.source === "hook_only") return readOnly();
|
|
17767
|
+
if (isOmpSeat2(s)) return ompSeatReadOnly(s);
|
|
17518
17768
|
if (closing.has(id)) return new Refusal("the session is being closed", "busy");
|
|
17519
17769
|
const ids = how.attachments ?? [];
|
|
17520
17770
|
const refs = [];
|
|
@@ -17848,7 +18098,7 @@ async function startServer(opts) {
|
|
|
17848
18098
|
let scanning = null;
|
|
17849
18099
|
function sharedScan() {
|
|
17850
18100
|
if (scanning) return scanning;
|
|
17851
|
-
const home2 = opts.home ??
|
|
18101
|
+
const home2 = opts.home ?? homedir14();
|
|
17852
18102
|
const extra = extraRoots(home2, [...store.recents().map((r) => r.cwd), ...store.all().filter((s) => s.state !== "exited").map((s) => s.cwd)]);
|
|
17853
18103
|
const walk = (opts.scan ?? scanRepos)({ home: home2, extra }).finally(() => {
|
|
17854
18104
|
if (scanning === walk) scanning = null;
|
|
@@ -18127,6 +18377,7 @@ async function startServer(opts) {
|
|
|
18127
18377
|
return void await omp2.interruptAndRestore(s.id).then(({ entries, imagesDropped }) => reply({ type: "session.queue.restored", id: s.id, texts: entries.map((e) => e.text), entries, ...imagesDropped ? { imagesDropped } : {} }), (e) => refuse(e.message, msg.id));
|
|
18128
18378
|
}
|
|
18129
18379
|
if (!s?.tmuxSession) return;
|
|
18380
|
+
if (isOmpSeat2(s)) return refuse(ompSeatReadOnly(s), msg.id);
|
|
18130
18381
|
await tmux.sendKeys(s.tmuxSession, adapterFor(s.tool).interruptKeys());
|
|
18131
18382
|
return;
|
|
18132
18383
|
}
|
|
@@ -18357,7 +18608,7 @@ async function startServer(opts) {
|
|
|
18357
18608
|
relay,
|
|
18358
18609
|
launchChat: (thread, qid, rows) => {
|
|
18359
18610
|
const c = thread === "desktop" ? threads.desktop : threads.device(thread.slice("device:".length));
|
|
18360
|
-
const userHome = resolve12(opts.home ??
|
|
18611
|
+
const userHome = resolve12(opts.home ?? homedir14());
|
|
18361
18612
|
return launchFromChat({
|
|
18362
18613
|
chat: c,
|
|
18363
18614
|
emit: threads.emitterOf(thread) ?? (() => {
|
|
@@ -18501,6 +18752,7 @@ async function startServer(opts) {
|
|
|
18501
18752
|
close: () => new Promise((res) => {
|
|
18502
18753
|
clearInterval(sweepTimer);
|
|
18503
18754
|
clearInterval(seatTimer);
|
|
18755
|
+
ompSeats.stop();
|
|
18504
18756
|
human.stop();
|
|
18505
18757
|
if (goalsTimer) clearTimeout(goalsTimer);
|
|
18506
18758
|
void reducer.close();
|
|
@@ -18520,7 +18772,7 @@ async function startServer(opts) {
|
|
|
18520
18772
|
})
|
|
18521
18773
|
};
|
|
18522
18774
|
}
|
|
18523
|
-
var CONTINUE_ARGS, RESUME_ARGS, MULTI_DIR_ARGS, MODEL_ARGS, EFFORT_ARGS, NoteNotTyped, DELETED_TTL_MS, RESPAWN_HOOKS_MS, ALLOWED_ORIGINS;
|
|
18775
|
+
var SEAT_TOOLS, CONTINUE_ARGS, RESUME_ARGS, MULTI_DIR_ARGS, MODEL_ARGS, EFFORT_ARGS, NoteNotTyped, DELETED_TTL_MS, RESPAWN_HOOKS_MS, ALLOWED_ORIGINS;
|
|
18524
18776
|
var init_server = __esm({
|
|
18525
18777
|
"src/daemon/server.ts"() {
|
|
18526
18778
|
"use strict";
|
|
@@ -18540,6 +18792,7 @@ var init_server = __esm({
|
|
|
18540
18792
|
init_spawn();
|
|
18541
18793
|
init_host();
|
|
18542
18794
|
init_catalog();
|
|
18795
|
+
init_seats();
|
|
18543
18796
|
init_repos2();
|
|
18544
18797
|
init_scan2();
|
|
18545
18798
|
init_folders();
|
|
@@ -18578,6 +18831,7 @@ var init_server = __esm({
|
|
|
18578
18831
|
init_challenges();
|
|
18579
18832
|
init_webauthn();
|
|
18580
18833
|
init_frames();
|
|
18834
|
+
SEAT_TOOLS = { "claude-code": "claude", codex: "codex", omp: "omp" };
|
|
18581
18835
|
CONTINUE_ARGS = { claude: ["--continue"], codex: ["resume", "--last"], cursor: ["--continue"] };
|
|
18582
18836
|
RESUME_ARGS = { claude: (id) => ["--resume", id], codex: (id) => ["resume", id], cursor: (id) => ["--resume", id] };
|
|
18583
18837
|
MULTI_DIR_ARGS = { claude: (dirs) => ["--add-dir", ...dirs] };
|
|
@@ -18606,7 +18860,7 @@ var init_server = __esm({
|
|
|
18606
18860
|
// src/tmux.ts
|
|
18607
18861
|
import { execFile as execFile7 } from "child_process";
|
|
18608
18862
|
import { existsSync as existsSync3 } from "fs";
|
|
18609
|
-
import { join as
|
|
18863
|
+
import { join as join30 } from "path";
|
|
18610
18864
|
function runFile(file, args, env, opts) {
|
|
18611
18865
|
return new Promise((resolve13) => {
|
|
18612
18866
|
execFile7(file, args, { maxBuffer: 4 * 1024 * 1024, env, ...opts?.timeoutMs ? { timeout: opts.timeoutMs, killSignal: "SIGTERM" } : {} }, (err, stdout, stderr) => {
|
|
@@ -18616,7 +18870,7 @@ function runFile(file, args, env, opts) {
|
|
|
18616
18870
|
});
|
|
18617
18871
|
}
|
|
18618
18872
|
function systemdAvailable(env = process.env, exists = existsSync3) {
|
|
18619
|
-
return !!env.XDG_RUNTIME_DIR && exists(
|
|
18873
|
+
return !!env.XDG_RUNTIME_DIR && exists(join30(env.XDG_RUNTIME_DIR, "systemd", "private"));
|
|
18620
18874
|
}
|
|
18621
18875
|
function newSessionCommand(tmuxArgs, scoped, unit) {
|
|
18622
18876
|
if (!scoped) return { file: "tmux", args: tmuxArgs };
|
|
@@ -18749,10 +19003,10 @@ __export(setup_exports, {
|
|
|
18749
19003
|
systemdUnit: () => systemdUnit,
|
|
18750
19004
|
writeBin: () => writeBin
|
|
18751
19005
|
});
|
|
18752
|
-
import { readFile as
|
|
19006
|
+
import { readFile as readFile13, writeFile as writeFile14, mkdir as mkdir12, rename as rename5, realpath as realpath2, rm as rm6, stat as stat7, lstat, readlink } from "fs/promises";
|
|
18753
19007
|
import { execFile as execFile8 } from "child_process";
|
|
18754
|
-
import { homedir as
|
|
18755
|
-
import { join as
|
|
19008
|
+
import { homedir as homedir15, userInfo } from "os";
|
|
19009
|
+
import { join as join31, dirname as dirname10 } from "path";
|
|
18756
19010
|
function mergeHooks(settings, events, command, file) {
|
|
18757
19011
|
if (settings === void 0) settings = {};
|
|
18758
19012
|
if (!settings || typeof settings !== "object" || Array.isArray(settings)) throw new Error(`${file} root is not an object, not modified`);
|
|
@@ -18800,7 +19054,7 @@ function mergeCursorHooks(config, command = "ledge hook cursor") {
|
|
|
18800
19054
|
async function mergeJsonFile(path3, merge, name) {
|
|
18801
19055
|
let raw = null;
|
|
18802
19056
|
try {
|
|
18803
|
-
raw = await
|
|
19057
|
+
raw = await readFile13(path3, "utf8");
|
|
18804
19058
|
} catch (e) {
|
|
18805
19059
|
if (e.code !== "ENOENT") throw e;
|
|
18806
19060
|
}
|
|
@@ -18836,7 +19090,7 @@ WantedBy=default.target
|
|
|
18836
19090
|
async function writeIfChanged(path3, content3) {
|
|
18837
19091
|
let current2 = null;
|
|
18838
19092
|
try {
|
|
18839
|
-
current2 = await
|
|
19093
|
+
current2 = await readFile13(path3, "utf8");
|
|
18840
19094
|
} catch (e) {
|
|
18841
19095
|
if (e.code !== "ENOENT") throw e;
|
|
18842
19096
|
}
|
|
@@ -18850,7 +19104,7 @@ async function writeIfChanged(path3, content3) {
|
|
|
18850
19104
|
async function stopDetachedDaemon(pidFile) {
|
|
18851
19105
|
let pid;
|
|
18852
19106
|
try {
|
|
18853
|
-
pid = Number((await
|
|
19107
|
+
pid = Number((await readFile13(pidFile, "utf8")).trim());
|
|
18854
19108
|
} catch {
|
|
18855
19109
|
return null;
|
|
18856
19110
|
}
|
|
@@ -18880,10 +19134,10 @@ async function stopDetachedDaemon(pidFile) {
|
|
|
18880
19134
|
async function installService(opts = {}) {
|
|
18881
19135
|
const out = [];
|
|
18882
19136
|
const run4 = opts.run ?? execRunner;
|
|
18883
|
-
const unitDir = opts.unitDir ??
|
|
19137
|
+
const unitDir = opts.unitDir ?? join31(homedir15(), ".config", "systemd", "user");
|
|
18884
19138
|
const node2 = opts.node ?? await realpath2(process.execPath);
|
|
18885
19139
|
const script = opts.script ?? await realpath2(process.argv[1]);
|
|
18886
|
-
const changed = await writeIfChanged(
|
|
19140
|
+
const changed = await writeIfChanged(join31(unitDir, SERVICE), systemdUnit({ node: node2, script }));
|
|
18887
19141
|
const reload = await run4("systemctl", ["--user", "daemon-reload"]);
|
|
18888
19142
|
if (reload.code !== 0) throw new Error(`systemd user session unavailable (systemctl --user daemon-reload failed: ${reload.stderr.trim() || reload.code}); the daemon will still be started on demand by ledge claude`);
|
|
18889
19143
|
const active = (await run4("systemctl", ["--user", "is-active", SERVICE])).code === 0;
|
|
@@ -18912,7 +19166,7 @@ async function installService(opts = {}) {
|
|
|
18912
19166
|
}
|
|
18913
19167
|
async function isDir(path3) {
|
|
18914
19168
|
try {
|
|
18915
|
-
return (await
|
|
19169
|
+
return (await stat7(path3)).isDirectory();
|
|
18916
19170
|
} catch {
|
|
18917
19171
|
return false;
|
|
18918
19172
|
}
|
|
@@ -18921,7 +19175,7 @@ async function writeBin(opts) {
|
|
|
18921
19175
|
const st = await lstat(opts.link).catch(() => null);
|
|
18922
19176
|
const was = st?.isSymbolicLink() ? await readlink(opts.link) : null;
|
|
18923
19177
|
if (was !== null && !was.endsWith("/dist/cli/index.js")) return null;
|
|
18924
|
-
const current2 = st && was === null && st.isFile() ? await
|
|
19178
|
+
const current2 = st && was === null && st.isFile() ? await readFile13(opts.link, "utf8").catch(() => "") : "";
|
|
18925
19179
|
if (st && was === null && !current2.startsWith(BIN_MARK)) return null;
|
|
18926
19180
|
const script = `${BIN_MARK}: the hooks run \`ledge\` wherever node is not on the PATH.
|
|
18927
19181
|
exec ${shQuote(opts.node)} ${shQuote(opts.target)} "$@"
|
|
@@ -18937,24 +19191,24 @@ async function runSetup(opts = {}) {
|
|
|
18937
19191
|
const out = [];
|
|
18938
19192
|
await ensureLedgeDir();
|
|
18939
19193
|
out.push("~/.ledge ready (tmux.conf written if missing)");
|
|
18940
|
-
const settingsPath2 = opts.settingsPath ??
|
|
19194
|
+
const settingsPath2 = opts.settingsPath ?? join31(homedir15(), ".claude", "settings.json");
|
|
18941
19195
|
if (await mergeJsonFile(settingsPath2, mergeClaudeHooks, "settings.json")) out.push(`Claude Code hooks added in ${settingsPath2}`);
|
|
18942
19196
|
else out.push("Claude Code hooks already present");
|
|
18943
|
-
const codexDir = opts.codexDir ?? process.env.CODEX_HOME ??
|
|
19197
|
+
const codexDir = opts.codexDir ?? process.env.CODEX_HOME ?? join31(homedir15(), ".codex");
|
|
18944
19198
|
if (!await isDir(codexDir)) out.push(`Codex not found (${codexDir} missing), Codex hooks skipped`);
|
|
18945
|
-
else if (await mergeJsonFile(
|
|
18946
|
-
out.push(`Codex hooks added in ${
|
|
19199
|
+
else if (await mergeJsonFile(join31(codexDir, "hooks.json"), mergeCodexHooks, "hooks.json")) {
|
|
19200
|
+
out.push(`Codex hooks added in ${join31(codexDir, "hooks.json")}; Codex asks to review them on its next start: trust them there or from Ledge`);
|
|
18947
19201
|
} else out.push("Codex hooks already present");
|
|
18948
|
-
const cursorDir = opts.cursorDir ??
|
|
19202
|
+
const cursorDir = opts.cursorDir ?? join31(homedir15(), ".cursor");
|
|
18949
19203
|
if (!await isDir(cursorDir)) out.push(`Cursor Agent not found (${cursorDir} missing), Cursor Agent hooks skipped`);
|
|
18950
|
-
else if (await mergeJsonFile(
|
|
19204
|
+
else if (await mergeJsonFile(join31(cursorDir, "hooks.json"), mergeCursorHooks, "hooks.json")) out.push(`Cursor Agent hooks added in ${join31(cursorDir, "hooks.json")}`);
|
|
18951
19205
|
else out.push("Cursor Agent hooks already present");
|
|
18952
19206
|
if (opts.service ?? true) {
|
|
18953
19207
|
const cli = opts.cli ?? process.argv[1] ?? "";
|
|
18954
19208
|
if (cli.endsWith(".ts")) out.push("systemd service skipped: run setup from the built CLI (pnpm --filter @paradow/ledge build, then ledge setup)");
|
|
18955
19209
|
else {
|
|
18956
19210
|
const script = await realpath2(cli);
|
|
18957
|
-
const line2 = await writeBin({ link: opts.link ??
|
|
19211
|
+
const line2 = await writeBin({ link: opts.link ?? join31(homedir15(), ".local", "bin", "ledge"), node: process.execPath, target: script });
|
|
18958
19212
|
if (line2) out.push(line2);
|
|
18959
19213
|
out.push(...await installService({ script, unitDir: opts.unitDir, run: opts.run }));
|
|
18960
19214
|
}
|
|
@@ -19016,10 +19270,10 @@ var init_setup = __esm({
|
|
|
19016
19270
|
});
|
|
19017
19271
|
|
|
19018
19272
|
// src/update/guard.ts
|
|
19019
|
-
import { readFile as
|
|
19273
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
19020
19274
|
async function tmuxServerAtRisk(opts = {}) {
|
|
19021
19275
|
const runTmux = opts.runTmux ?? run2;
|
|
19022
|
-
const readCgroup = opts.readCgroup ?? ((pid2) =>
|
|
19276
|
+
const readCgroup = opts.readCgroup ?? ((pid2) => readFile14(`/proc/${pid2}/cgroup`, "utf8"));
|
|
19023
19277
|
const r = await runTmux(["-L", opts.socket ?? "ledge", "list-sessions", "-F", "#{pid}"]);
|
|
19024
19278
|
if (r.code !== 0) return false;
|
|
19025
19279
|
const pid = r.stdout.split("\n").map((s) => s.trim()).find(Boolean);
|
|
@@ -19042,12 +19296,12 @@ var init_guard = __esm({
|
|
|
19042
19296
|
|
|
19043
19297
|
// src/update/self.ts
|
|
19044
19298
|
import { existsSync as existsSync4 } from "fs";
|
|
19045
|
-
import { readFile as
|
|
19046
|
-
import { homedir as
|
|
19047
|
-
import { dirname as dirname11, join as
|
|
19299
|
+
import { readFile as readFile15, realpath as realpath3 } from "fs/promises";
|
|
19300
|
+
import { homedir as homedir16 } from "os";
|
|
19301
|
+
import { dirname as dirname11, join as join32 } from "path";
|
|
19048
19302
|
function gitRoot(script, exists = existsSync4) {
|
|
19049
19303
|
for (let dir = dirname11(script); ; dir = dirname11(dir)) {
|
|
19050
|
-
if (exists(
|
|
19304
|
+
if (exists(join32(dir, ".git"))) return dir;
|
|
19051
19305
|
if (dirname11(dir) === dir) return null;
|
|
19052
19306
|
}
|
|
19053
19307
|
}
|
|
@@ -19057,10 +19311,10 @@ function installKind(script, exists = existsSync4) {
|
|
|
19057
19311
|
}
|
|
19058
19312
|
async function daemonInfo() {
|
|
19059
19313
|
const script = await realpath3(process.argv[1] ?? "").catch(() => process.argv[1] ?? "");
|
|
19060
|
-
const cgroup = await
|
|
19314
|
+
const cgroup = await readFile15("/proc/self/cgroup", "utf8").catch(() => "");
|
|
19061
19315
|
const install = installKind(script);
|
|
19062
19316
|
const root2 = install === "git" ? gitRoot(script) : null;
|
|
19063
|
-
return { version: LEDGE_VERSION, install, systemd: underSystemd(process.env, cgroup), home:
|
|
19317
|
+
return { version: LEDGE_VERSION, install, systemd: underSystemd(process.env, cgroup), home: homedir16(), ...root2 ? { manual: manualCommand(root2) } : {} };
|
|
19064
19318
|
}
|
|
19065
19319
|
var underSystemd, manualCommand;
|
|
19066
19320
|
var init_self = __esm({
|
|
@@ -19074,7 +19328,7 @@ var init_self = __esm({
|
|
|
19074
19328
|
});
|
|
19075
19329
|
|
|
19076
19330
|
// src/update/run-update.ts
|
|
19077
|
-
import { dirname as dirname12, join as
|
|
19331
|
+
import { dirname as dirname12, join as join33 } from "path";
|
|
19078
19332
|
function createDaemonUpdater(deps) {
|
|
19079
19333
|
let busy = false;
|
|
19080
19334
|
let restarting = false;
|
|
@@ -19163,7 +19417,7 @@ var init_run_update = __esm({
|
|
|
19163
19417
|
PACKAGE = "@paradow/ledge";
|
|
19164
19418
|
NPM_TIMEOUT_MS = 3 * 6e4;
|
|
19165
19419
|
RESTART_COMMAND = "systemctl --user restart ledge-daemon";
|
|
19166
|
-
npmCommand = (execPath, version) => ({ file:
|
|
19420
|
+
npmCommand = (execPath, version) => ({ file: join33(dirname12(execPath), "npm"), args: ["i", "-g", `${PACKAGE}@${version}`] });
|
|
19167
19421
|
lastLines = (output, n = 3) => output.split("\n").map((l) => l.trimEnd()).filter(Boolean).slice(-n).join("\n");
|
|
19168
19422
|
npmEnv = (execPath, env) => ({ ...env, PATH: `${dirname12(execPath)}:${env.PATH ?? ""}` });
|
|
19169
19423
|
}
|
|
@@ -20677,7 +20931,7 @@ __export(daemon_exports, {
|
|
|
20677
20931
|
startDaemon: () => startDaemon
|
|
20678
20932
|
});
|
|
20679
20933
|
import { writeFile as writeFile15, rm as rm7 } from "fs/promises";
|
|
20680
|
-
import { join as
|
|
20934
|
+
import { join as join34 } from "path";
|
|
20681
20935
|
async function startDaemon(opts = {}) {
|
|
20682
20936
|
await ensureLedgeDir();
|
|
20683
20937
|
const store = new Store();
|
|
@@ -20694,7 +20948,7 @@ async function startDaemon(opts = {}) {
|
|
|
20694
20948
|
}
|
|
20695
20949
|
for (const s of store.all()) {
|
|
20696
20950
|
if (backendOf(s) !== "omp-rpc") continue;
|
|
20697
|
-
await reapOwner(
|
|
20951
|
+
await reapOwner(join34(paths().dir, "omp", s.id)).catch(() => false);
|
|
20698
20952
|
if (s.state === "exited") continue;
|
|
20699
20953
|
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
20700
20954
|
store.apply(s.id, { name: "StopFailure", at, source: "daemon", text: "Ledge restarted: the OMP process ended with it" });
|
|
@@ -20781,9 +21035,9 @@ __export(uninstall_exports, {
|
|
|
20781
21035
|
runUninstall: () => runUninstall,
|
|
20782
21036
|
uninstallArgs: () => uninstallArgs
|
|
20783
21037
|
});
|
|
20784
|
-
import { readFile as
|
|
20785
|
-
import { homedir as
|
|
20786
|
-
import { join as
|
|
21038
|
+
import { readFile as readFile16, writeFile as writeFile16, rename as rename6, rm as rm8, lstat as lstat2, realpath as realpath4 } from "fs/promises";
|
|
21039
|
+
import { homedir as homedir17 } from "os";
|
|
21040
|
+
import { join as join35 } from "path";
|
|
20787
21041
|
function prune(config, file, keep) {
|
|
20788
21042
|
if (!isObject(config)) throw new Error(`${file} root is not an object, not modified`);
|
|
20789
21043
|
if (config.hooks === void 0) return { settings: config, removed: 0 };
|
|
@@ -20820,7 +21074,7 @@ function removeCursorHooks(config) {
|
|
|
20820
21074
|
async function pruneJsonFile(path3, remove, name) {
|
|
20821
21075
|
let raw;
|
|
20822
21076
|
try {
|
|
20823
|
-
raw = await
|
|
21077
|
+
raw = await readFile16(path3, "utf8");
|
|
20824
21078
|
} catch (e) {
|
|
20825
21079
|
if (e.code === "ENOENT") return null;
|
|
20826
21080
|
throw e;
|
|
@@ -20841,7 +21095,7 @@ async function pruneJsonFile(path3, remove, name) {
|
|
|
20841
21095
|
async function removeService(opts = {}) {
|
|
20842
21096
|
const out = [];
|
|
20843
21097
|
const run4 = opts.run ?? execRunner;
|
|
20844
|
-
const unit =
|
|
21098
|
+
const unit = join35(opts.unitDir ?? join35(homedir17(), ".config", "systemd", "user"), SERVICE);
|
|
20845
21099
|
let present = true;
|
|
20846
21100
|
try {
|
|
20847
21101
|
await lstat2(unit);
|
|
@@ -20866,7 +21120,7 @@ async function runningSessions(run4, socket) {
|
|
|
20866
21120
|
async function removeLink(link3, script) {
|
|
20867
21121
|
try {
|
|
20868
21122
|
const st = await lstat2(link3);
|
|
20869
|
-
if (st.isFile() ? !(await
|
|
21123
|
+
if (st.isFile() ? !(await readFile16(link3, "utf8")).startsWith(BIN_MARK) : !st.isSymbolicLink() || await realpath4(link3) !== await realpath4(script)) return false;
|
|
20870
21124
|
} catch {
|
|
20871
21125
|
return false;
|
|
20872
21126
|
}
|
|
@@ -20889,9 +21143,9 @@ async function runUninstall(opts = {}) {
|
|
|
20889
21143
|
};
|
|
20890
21144
|
const run4 = opts.run ?? execRunner;
|
|
20891
21145
|
const files = [
|
|
20892
|
-
["Claude Code", opts.settingsPath ??
|
|
20893
|
-
["Codex",
|
|
20894
|
-
["Cursor Agent",
|
|
21146
|
+
["Claude Code", opts.settingsPath ?? join35(homedir17(), ".claude", "settings.json"), (c) => removeClaudeHooks(c, "settings.json")],
|
|
21147
|
+
["Codex", join35(opts.codexDir ?? process.env.CODEX_HOME ?? join35(homedir17(), ".codex"), "hooks.json"), (c) => removeClaudeHooks(c, "hooks.json")],
|
|
21148
|
+
["Cursor Agent", join35(opts.cursorDir ?? join35(homedir17(), ".cursor"), "hooks.json"), removeCursorHooks]
|
|
20895
21149
|
];
|
|
20896
21150
|
for (const [agent, path3, remove] of files) {
|
|
20897
21151
|
await step3(async () => {
|
|
@@ -20913,7 +21167,7 @@ async function runUninstall(opts = {}) {
|
|
|
20913
21167
|
});
|
|
20914
21168
|
else lines.push(`${dir} kept (session journal and log): \`ledge uninstall --purge\` removes it`);
|
|
20915
21169
|
const script = opts.script ?? process.argv[1];
|
|
20916
|
-
const link3 = opts.link ??
|
|
21170
|
+
const link3 = opts.link ?? join35(homedir17(), ".local", "bin", "ledge");
|
|
20917
21171
|
if (script) await step3(async () => {
|
|
20918
21172
|
if (await removeLink(link3, script)) lines.push(`${link3} removed`);
|
|
20919
21173
|
});
|
|
@@ -21171,10 +21425,10 @@ function createDaemonClient(opts) {
|
|
|
21171
21425
|
};
|
|
21172
21426
|
const schedule = () => {
|
|
21173
21427
|
if (closed) return;
|
|
21174
|
-
timer2 = setTimeout(
|
|
21428
|
+
timer2 = setTimeout(open6, backoff);
|
|
21175
21429
|
backoff = Math.min(max, backoff * 2);
|
|
21176
21430
|
};
|
|
21177
|
-
function
|
|
21431
|
+
function open6() {
|
|
21178
21432
|
if (closed) return;
|
|
21179
21433
|
setStatus(status === "open" ? "connecting" : status);
|
|
21180
21434
|
if (!token) {
|
|
@@ -21238,7 +21492,7 @@ function createDaemonClient(opts) {
|
|
|
21238
21492
|
ws = null;
|
|
21239
21493
|
old?.close();
|
|
21240
21494
|
setStatus("connecting");
|
|
21241
|
-
|
|
21495
|
+
open6();
|
|
21242
21496
|
},
|
|
21243
21497
|
close: () => {
|
|
21244
21498
|
closed = true;
|
|
@@ -23011,7 +23265,7 @@ __export(launch_exports, {
|
|
|
23011
23265
|
parseLaunchArgs: () => parseLaunchArgs
|
|
23012
23266
|
});
|
|
23013
23267
|
import { spawn as spawn3 } from "child_process";
|
|
23014
|
-
import { readFile as
|
|
23268
|
+
import { readFile as readFile17, rm as rm9 } from "fs/promises";
|
|
23015
23269
|
import { createConnection } from "net";
|
|
23016
23270
|
function parseLaunchArgs(argv) {
|
|
23017
23271
|
const args = [];
|
|
@@ -23124,7 +23378,7 @@ async function readExitCode(id) {
|
|
|
23124
23378
|
const file = exitFile(id);
|
|
23125
23379
|
let raw = null;
|
|
23126
23380
|
try {
|
|
23127
|
-
raw = await
|
|
23381
|
+
raw = await readFile17(file, "utf8");
|
|
23128
23382
|
} catch {
|
|
23129
23383
|
}
|
|
23130
23384
|
await rm9(file, { force: true });
|
|
@@ -23201,6 +23455,7 @@ var init_launch2 = __esm({
|
|
|
23201
23455
|
import { spawn as spawn4 } from "child_process";
|
|
23202
23456
|
function attachCommand(fleet, s) {
|
|
23203
23457
|
if (s.offline) return { why: "offline" };
|
|
23458
|
+
if (isStoppedOmpSeat(s)) return { why: "stopped" };
|
|
23204
23459
|
if (backendOf(s) === "omp-rpc") return { why: "omp" };
|
|
23205
23460
|
if (!s.tmuxSession) return { why: "none" };
|
|
23206
23461
|
const argv = fleet.terminal(s.id);
|
|
@@ -23223,9 +23478,9 @@ var init_attach = __esm({
|
|
|
23223
23478
|
|
|
23224
23479
|
// src/tui/clipboard.ts
|
|
23225
23480
|
import { execFile as execFile9 } from "child_process";
|
|
23226
|
-
import { mkdtemp as mkdtemp2, readFile as
|
|
23481
|
+
import { mkdtemp as mkdtemp2, readFile as readFile18, rm as rm10 } from "fs/promises";
|
|
23227
23482
|
import { tmpdir as tmpdir2 } from "os";
|
|
23228
|
-
import { join as
|
|
23483
|
+
import { join as join36 } from "path";
|
|
23229
23484
|
async function fromWindows(run4) {
|
|
23230
23485
|
const { stdout } = await run4(POWERSHELL, ["-NoProfile", "-STA", "-Command", SCRIPT], { cwd: "/mnt/c", maxBuffer: MAX_BUFFER, encoding: "buffer" });
|
|
23231
23486
|
const line2 = stdout.toString("utf8").trim();
|
|
@@ -23250,15 +23505,15 @@ async function fromLinux(run4) {
|
|
|
23250
23505
|
return null;
|
|
23251
23506
|
}
|
|
23252
23507
|
async function fromMac(run4) {
|
|
23253
|
-
const dir = await mkdtemp2(
|
|
23254
|
-
const file =
|
|
23508
|
+
const dir = await mkdtemp2(join36(tmpdir2(), "ledge-clip-"));
|
|
23509
|
+
const file = join36(dir, "clip.png");
|
|
23255
23510
|
try {
|
|
23256
23511
|
const script = `set f to open for access POSIX file "${file}" with write permission
|
|
23257
23512
|
set eof f to 0
|
|
23258
23513
|
write (the clipboard as \xABclass PNGf\xBB) to f
|
|
23259
23514
|
close access f`;
|
|
23260
23515
|
await run4("osascript", ["-e", script], { maxBuffer: MAX_BUFFER, encoding: "buffer" });
|
|
23261
|
-
return fromBytes(await
|
|
23516
|
+
return fromBytes(await readFile18(file));
|
|
23262
23517
|
} catch {
|
|
23263
23518
|
return null;
|
|
23264
23519
|
} finally {
|
|
@@ -23689,7 +23944,7 @@ var init_fr = __esm({
|
|
|
23689
23944
|
plural = (n, one2, many) => n > 1 ? many : one2;
|
|
23690
23945
|
fr3 = {
|
|
23691
23946
|
lang: { fr: "Fran\xE7ais", en: "English" },
|
|
23692
|
-
state: { approval: "Votre accord", question: "Une question", starting: "D\xE9marrage", idle: "Disponible", working: "Au travail", done: "Termin\xE9e", error: "Erreur", readonly: "Lecture seule" },
|
|
23947
|
+
state: { approval: "Votre accord", question: "Une question", starting: "D\xE9marrage", idle: "Disponible", working: "Au travail", done: "Termin\xE9e", error: "Erreur", readonly: "Lecture seule", stopped: "Arr\xEAt\xE9" },
|
|
23693
23948
|
time: {
|
|
23694
23949
|
now: "\xE0 l\u2019instant",
|
|
23695
23950
|
decimal: ",",
|
|
@@ -23712,6 +23967,7 @@ var init_fr = __esm({
|
|
|
23712
23967
|
openImage: "ouvrir l'image",
|
|
23713
23968
|
navigate: "naviguer",
|
|
23714
23969
|
open: "ouvrir",
|
|
23970
|
+
attachSeat: "attacher son terminal",
|
|
23715
23971
|
answer: "r\xE9pondre",
|
|
23716
23972
|
attach: "attacher (tmux)",
|
|
23717
23973
|
ask: "demander \xE0 Ledge",
|
|
@@ -23786,6 +24042,7 @@ var init_fr = __esm({
|
|
|
23786
24042
|
noPreview: "Pas d\u2019aper\xE7u.",
|
|
23787
24043
|
noExchange: "Aucun \xE9change.",
|
|
23788
24044
|
sessions: (n) => `${n} ${plural(n, "session", "sessions")}`,
|
|
24045
|
+
sessionsOf: (live3, all2) => `${live3} ${plural(live3, "session", "sessions")} sur ${all2}`,
|
|
23789
24046
|
outside: "Hors projet",
|
|
23790
24047
|
offline: "hors ligne",
|
|
23791
24048
|
readOnly: "lecture seule",
|
|
@@ -24009,6 +24266,7 @@ var init_fr = __esm({
|
|
|
24009
24266
|
noteTooLong: (max) => `Note trop longue : ${max} caract\xE8res au plus. Elle reste dans le champ.`,
|
|
24010
24267
|
noNote: (n) => `${n} ne prend pas de note ici.`,
|
|
24011
24268
|
noTerminalOmp: (n) => `${n} est pilot\xE9 par Ledge via le protocole d\u2019OMP : pas de terminal \xE0 attacher.`,
|
|
24269
|
+
seatStopped: (n) => `${n} est arr\xEAt\xE9 : son terminal n\u2019existe plus. 6 ouvre OpenRig, o\xF9 est son rig.`,
|
|
24012
24270
|
noTerminal: (n) => `Pas de terminal pour ${n}.`,
|
|
24013
24271
|
attachFailed: (code3) => `tmux s\u2019est arr\xEAt\xE9 avec le code ${code3}.`,
|
|
24014
24272
|
modelSwitch: "Ce daemon ne change pas le mod\xE8le d\u2019une session en cours.",
|
|
@@ -24257,7 +24515,7 @@ var init_en = __esm({
|
|
|
24257
24515
|
plural2 = (n, one2, many) => n > 1 ? many : one2;
|
|
24258
24516
|
en3 = {
|
|
24259
24517
|
lang: { fr: "Fran\xE7ais", en: "English" },
|
|
24260
|
-
state: { approval: "Needs you", question: "A question", starting: "Starting", idle: "Available", working: "Working", done: "Finished", error: "Error", readonly: "Read-only" },
|
|
24518
|
+
state: { approval: "Needs you", question: "A question", starting: "Starting", idle: "Available", working: "Working", done: "Finished", error: "Error", readonly: "Read-only", stopped: "Stopped" },
|
|
24261
24519
|
time: { now: "just now", decimal: ".", s: (n) => `${n}s`, min: (n) => `${n} min`, h: (n) => `${n} h`, d: (n) => `${n} d` },
|
|
24262
24520
|
tabs: { overview: "Overview", session: "Session", ask: "Ask Ledge", launch: "New session", settings: "Settings", openrig: "OpenRig" },
|
|
24263
24521
|
bar: {
|
|
@@ -24273,6 +24531,7 @@ var init_en = __esm({
|
|
|
24273
24531
|
openImage: "open image",
|
|
24274
24532
|
navigate: "move",
|
|
24275
24533
|
open: "open",
|
|
24534
|
+
attachSeat: "attach its terminal",
|
|
24276
24535
|
answer: "answer",
|
|
24277
24536
|
attach: "attach (tmux)",
|
|
24278
24537
|
ask: "ask Ledge",
|
|
@@ -24346,6 +24605,7 @@ var init_en = __esm({
|
|
|
24346
24605
|
noPreview: "No preview.",
|
|
24347
24606
|
noExchange: "No message yet.",
|
|
24348
24607
|
sessions: (n) => `${n} ${plural2(n, "session", "sessions")}`,
|
|
24608
|
+
sessionsOf: (live3, all2) => `${live3} ${live3 === 1 ? "session" : "sessions"} of ${all2}`,
|
|
24349
24609
|
outside: "No project",
|
|
24350
24610
|
offline: "offline",
|
|
24351
24611
|
readOnly: "read-only",
|
|
@@ -24565,6 +24825,7 @@ var init_en = __esm({
|
|
|
24565
24825
|
noteTooLong: (max) => `Note too long: ${max} characters at most. It stays in the field.`,
|
|
24566
24826
|
noNote: (n) => `${n} takes no note here.`,
|
|
24567
24827
|
noTerminalOmp: (n) => `${n} is driven by Ledge over OMP's protocol: there is no terminal to attach to.`,
|
|
24828
|
+
seatStopped: (n) => `${n} is stopped: its terminal is gone. 6 opens OpenRig, where its rig is.`,
|
|
24568
24829
|
noTerminal: (n) => `No terminal for ${n}.`,
|
|
24569
24830
|
attachFailed: (code3) => `tmux stopped with code ${code3}.`,
|
|
24570
24831
|
modelSwitch: "This daemon cannot change a running session\u2019s model.",
|
|
@@ -24829,15 +25090,19 @@ function overview(sessions, projects) {
|
|
|
24829
25090
|
const known2 = new Map((projects?.projects ?? []).map((p) => [p.id, p]));
|
|
24830
25091
|
for (const p of projects?.projects ?? []) nodes.set(`p:${p.id}`, { key: `p:${p.id}`, label: p.name, color: p.color, branches: [], count: 0 });
|
|
24831
25092
|
const rigNodes = /* @__PURE__ */ new Map();
|
|
25093
|
+
const rigNodeOf = (rig) => {
|
|
25094
|
+
const kind = rig === "kernel" ? "kernel" : "rig";
|
|
25095
|
+
const key = kind === "kernel" ? "g:kernel" : `g:rig:${rig}`;
|
|
25096
|
+
let node2 = rigNodes.get(key);
|
|
25097
|
+
if (!node2) {
|
|
25098
|
+
node2 = { key, label: kind === "kernel" ? "Kernel" : rig, kind, branches: [{ branch: "", sessions: [] }], count: 0 };
|
|
25099
|
+
rigNodes.set(key, node2);
|
|
25100
|
+
}
|
|
25101
|
+
return node2;
|
|
25102
|
+
};
|
|
24832
25103
|
for (const s of live3) {
|
|
24833
25104
|
if (s.rig) {
|
|
24834
|
-
const
|
|
24835
|
-
const key2 = kind === "kernel" ? "g:kernel" : `g:rig:${s.rig.name}`;
|
|
24836
|
-
let node3 = rigNodes.get(key2);
|
|
24837
|
-
if (!node3) {
|
|
24838
|
-
node3 = { key: key2, label: kind === "kernel" ? "Kernel" : s.rig.name, kind, branches: [{ branch: "", sessions: [] }], count: 0 };
|
|
24839
|
-
rigNodes.set(key2, node3);
|
|
24840
|
-
}
|
|
25105
|
+
const node3 = rigNodeOf(s.rig.name);
|
|
24841
25106
|
node3.branches[0].sessions.push(s);
|
|
24842
25107
|
node3.count += 1;
|
|
24843
25108
|
continue;
|
|
@@ -24858,6 +25123,12 @@ function overview(sessions, projects) {
|
|
|
24858
25123
|
row3.sessions.push(s);
|
|
24859
25124
|
node2.count += 1;
|
|
24860
25125
|
}
|
|
25126
|
+
for (const s of sessions) {
|
|
25127
|
+
if (!isStoppedOmpSeat(s) || !s.rig) continue;
|
|
25128
|
+
const node2 = rigNodeOf(s.rig.name);
|
|
25129
|
+
node2.branches[0].sessions.push(s);
|
|
25130
|
+
node2.shown = (node2.shown ?? node2.count) + 1;
|
|
25131
|
+
}
|
|
24861
25132
|
const groups = [...rigNodes.values()].sort((a, b3) => a.kind === b3.kind ? a.label.localeCompare(b3.label) : a.kind === "kernel" ? 1 : -1);
|
|
24862
25133
|
const tree2 = [...[...nodes.values()].filter((n) => n.count > 0), ...groups];
|
|
24863
25134
|
const order2 = tree2.flatMap((n) => n.branches.flatMap((b3) => b3.sessions.map((s) => s.id)));
|
|
@@ -25118,7 +25389,7 @@ var init_theme = __esm({
|
|
|
25118
25389
|
|
|
25119
25390
|
// src/tui/model/cells.ts
|
|
25120
25391
|
import stringWidth from "string-width";
|
|
25121
|
-
function
|
|
25392
|
+
function join37(line2, a) {
|
|
25122
25393
|
const out = [];
|
|
25123
25394
|
for (const c of a) {
|
|
25124
25395
|
const last = out[out.length - 1];
|
|
@@ -25133,7 +25404,7 @@ function cut2(line2, width, ellipsis = "\u2026") {
|
|
|
25133
25404
|
const a = split2(line2), room = width - cells(ellipsis);
|
|
25134
25405
|
let n = 0, i = 0;
|
|
25135
25406
|
while (i < a.length && n + a[i].w <= room) n += a[i++].w;
|
|
25136
|
-
const kept =
|
|
25407
|
+
const kept = join37(line2, a.slice(0, i));
|
|
25137
25408
|
const color2 = line2[a[Math.max(0, i - 1)]?.seg ?? 0]?.color;
|
|
25138
25409
|
return [...kept, { text: ellipsis, ...color2 ? { color: color2 } : {} }];
|
|
25139
25410
|
}
|
|
@@ -25152,7 +25423,7 @@ function wrapSegs(line2, width, first = width) {
|
|
|
25152
25423
|
}
|
|
25153
25424
|
w = Math.max(4, width);
|
|
25154
25425
|
if (j >= a.length || a[j].g === "\n") {
|
|
25155
|
-
out.push(
|
|
25426
|
+
out.push(join37(line2, a.slice(i, j)));
|
|
25156
25427
|
i = j + 1;
|
|
25157
25428
|
if (j >= a.length) break;
|
|
25158
25429
|
if (i >= a.length) out.push([]);
|
|
@@ -25161,7 +25432,7 @@ function wrapSegs(line2, width, first = width) {
|
|
|
25161
25432
|
const end2 = a[j].g === " " ? j : space > i ? space : Math.max(j, i + 1);
|
|
25162
25433
|
let k = end2;
|
|
25163
25434
|
while (k > i && a[k - 1].g === " ") k--;
|
|
25164
|
-
out.push(
|
|
25435
|
+
out.push(join37(line2, a.slice(i, k)));
|
|
25165
25436
|
i = end2;
|
|
25166
25437
|
while (i < a.length && a[i].g === " ") i++;
|
|
25167
25438
|
if (a[i]?.g === "\n") {
|
|
@@ -30374,16 +30645,16 @@ function resolveAllAttention(events, context) {
|
|
|
30374
30645
|
let nextEvents;
|
|
30375
30646
|
while (++index2 < events.length) {
|
|
30376
30647
|
if (events[index2][0] === "enter" && events[index2][1].type === "attentionSequence" && events[index2][1]._close) {
|
|
30377
|
-
let
|
|
30378
|
-
while (
|
|
30379
|
-
if (events[
|
|
30380
|
-
context.sliceSerialize(events[
|
|
30381
|
-
if ((events[
|
|
30648
|
+
let open6 = index2;
|
|
30649
|
+
while (open6--) {
|
|
30650
|
+
if (events[open6][0] === "exit" && events[open6][1].type === "attentionSequence" && events[open6][1]._open && // If the markers are the same:
|
|
30651
|
+
context.sliceSerialize(events[open6][1]).charCodeAt(0) === context.sliceSerialize(events[index2][1]).charCodeAt(0)) {
|
|
30652
|
+
if ((events[open6][1]._close || events[index2][1]._open) && (events[index2][1].end.offset - events[index2][1].start.offset) % 3 && !((events[open6][1].end.offset - events[open6][1].start.offset + events[index2][1].end.offset - events[index2][1].start.offset) % 3)) {
|
|
30382
30653
|
continue;
|
|
30383
30654
|
}
|
|
30384
|
-
const use = events[
|
|
30655
|
+
const use = events[open6][1].end.offset - events[open6][1].start.offset > 1 && events[index2][1].end.offset - events[index2][1].start.offset > 1 ? 2 : 1;
|
|
30385
30656
|
const start = {
|
|
30386
|
-
...events[
|
|
30657
|
+
...events[open6][1].end
|
|
30387
30658
|
};
|
|
30388
30659
|
const end2 = {
|
|
30389
30660
|
...events[index2][1].start
|
|
@@ -30394,7 +30665,7 @@ function resolveAllAttention(events, context) {
|
|
|
30394
30665
|
type: use > 1 ? "strongSequence" : "emphasisSequence",
|
|
30395
30666
|
start,
|
|
30396
30667
|
end: {
|
|
30397
|
-
...events[
|
|
30668
|
+
...events[open6][1].end
|
|
30398
30669
|
}
|
|
30399
30670
|
};
|
|
30400
30671
|
const closingSequence = {
|
|
@@ -30407,7 +30678,7 @@ function resolveAllAttention(events, context) {
|
|
|
30407
30678
|
const text7 = {
|
|
30408
30679
|
type: use > 1 ? "strongText" : "emphasisText",
|
|
30409
30680
|
start: {
|
|
30410
|
-
...events[
|
|
30681
|
+
...events[open6][1].end
|
|
30411
30682
|
},
|
|
30412
30683
|
end: {
|
|
30413
30684
|
...events[index2][1].start
|
|
@@ -30422,26 +30693,26 @@ function resolveAllAttention(events, context) {
|
|
|
30422
30693
|
...closingSequence.end
|
|
30423
30694
|
}
|
|
30424
30695
|
};
|
|
30425
|
-
events[
|
|
30696
|
+
events[open6][1].end = {
|
|
30426
30697
|
...openingSequence.start
|
|
30427
30698
|
};
|
|
30428
30699
|
events[index2][1].start = {
|
|
30429
30700
|
...closingSequence.end
|
|
30430
30701
|
};
|
|
30431
30702
|
nextEvents = [];
|
|
30432
|
-
if (events[
|
|
30433
|
-
nextEvents = push(nextEvents, [["enter", events[
|
|
30703
|
+
if (events[open6][1].end.offset - events[open6][1].start.offset) {
|
|
30704
|
+
nextEvents = push(nextEvents, [["enter", events[open6][1], context], ["exit", events[open6][1], context]]);
|
|
30434
30705
|
}
|
|
30435
30706
|
nextEvents = push(nextEvents, [["enter", group, context], ["enter", openingSequence, context], ["exit", openingSequence, context], ["enter", text7, context]]);
|
|
30436
|
-
nextEvents = push(nextEvents, resolveAll(context.parser.constructs.insideSpan.null, events.slice(
|
|
30707
|
+
nextEvents = push(nextEvents, resolveAll(context.parser.constructs.insideSpan.null, events.slice(open6 + 1, index2), context));
|
|
30437
30708
|
nextEvents = push(nextEvents, [["exit", text7, context], ["enter", closingSequence, context], ["exit", closingSequence, context], ["exit", group, context]]);
|
|
30438
30709
|
let offset = 0;
|
|
30439
30710
|
if (events[index2][1].end.offset - events[index2][1].start.offset) {
|
|
30440
30711
|
offset = 2;
|
|
30441
30712
|
nextEvents = push(nextEvents, [["enter", events[index2][1], context], ["exit", events[index2][1], context]]);
|
|
30442
30713
|
}
|
|
30443
|
-
splice(events,
|
|
30444
|
-
index2 =
|
|
30714
|
+
splice(events, open6 - 1, index2 - open6 + 3, nextEvents);
|
|
30715
|
+
index2 = open6 + nextEvents.length - offset - 2;
|
|
30445
30716
|
break;
|
|
30446
30717
|
}
|
|
30447
30718
|
}
|
|
@@ -30473,10 +30744,10 @@ function tokenizeAttention(effects, ok4) {
|
|
|
30473
30744
|
}
|
|
30474
30745
|
const token = effects.exit("attentionSequence");
|
|
30475
30746
|
const after2 = classifyCharacter(code3);
|
|
30476
|
-
const
|
|
30747
|
+
const open6 = !after2 || after2 === 2 && before2 || attentionMarkers2.includes(code3) && code3 !== 42 && code3 !== 95;
|
|
30477
30748
|
const close = !before2 || before2 === 2 && after2 || attentionMarkers2.includes(previous3) && previous3 !== 42 && previous3 !== 95;
|
|
30478
|
-
token._open = Boolean(marker === 42 ?
|
|
30479
|
-
token._close = Boolean(marker === 42 ? close : close && (after2 || !
|
|
30749
|
+
token._open = Boolean(marker === 42 ? open6 : open6 && (before2 || !close));
|
|
30750
|
+
token._close = Boolean(marker === 42 ? close : close && (after2 || !open6));
|
|
30480
30751
|
return ok4(code3);
|
|
30481
30752
|
}
|
|
30482
30753
|
}
|
|
@@ -30510,9 +30781,9 @@ function tokenizeAutolink(effects, ok4, nok) {
|
|
|
30510
30781
|
effects.consume(code3);
|
|
30511
30782
|
effects.exit("autolinkMarker");
|
|
30512
30783
|
effects.enter("autolinkProtocol");
|
|
30513
|
-
return
|
|
30784
|
+
return open6;
|
|
30514
30785
|
}
|
|
30515
|
-
function
|
|
30786
|
+
function open6(code3) {
|
|
30516
30787
|
if (asciiAlpha(code3)) {
|
|
30517
30788
|
effects.consume(code3);
|
|
30518
30789
|
return schemeOrEmailAtext;
|
|
@@ -30793,9 +31064,9 @@ function tokenizeCharacterReference(effects, ok4, nok) {
|
|
|
30793
31064
|
effects.enter("characterReferenceMarker");
|
|
30794
31065
|
effects.consume(code3);
|
|
30795
31066
|
effects.exit("characterReferenceMarker");
|
|
30796
|
-
return
|
|
31067
|
+
return open6;
|
|
30797
31068
|
}
|
|
30798
|
-
function
|
|
31069
|
+
function open6(code3) {
|
|
30799
31070
|
if (code3 === 35) {
|
|
30800
31071
|
effects.enter("characterReferenceMarkerNumeric");
|
|
30801
31072
|
effects.consume(code3);
|
|
@@ -32196,9 +32467,9 @@ function tokenizeHtmlFlow(effects, ok4, nok) {
|
|
|
32196
32467
|
effects.enter("htmlFlow");
|
|
32197
32468
|
effects.enter("htmlFlowData");
|
|
32198
32469
|
effects.consume(code3);
|
|
32199
|
-
return
|
|
32470
|
+
return open6;
|
|
32200
32471
|
}
|
|
32201
|
-
function
|
|
32472
|
+
function open6(code3) {
|
|
32202
32473
|
if (code3 === 33) {
|
|
32203
32474
|
effects.consume(code3);
|
|
32204
32475
|
return declarationOpen;
|
|
@@ -32546,9 +32817,9 @@ function tokenizeHtmlText(effects, ok4, nok) {
|
|
|
32546
32817
|
effects.enter("htmlText");
|
|
32547
32818
|
effects.enter("htmlTextData");
|
|
32548
32819
|
effects.consume(code3);
|
|
32549
|
-
return
|
|
32820
|
+
return open6;
|
|
32550
32821
|
}
|
|
32551
|
-
function
|
|
32822
|
+
function open6(code3) {
|
|
32552
32823
|
if (code3 === 33) {
|
|
32553
32824
|
effects.consume(code3);
|
|
32554
32825
|
return declarationOpen;
|
|
@@ -32870,12 +33141,12 @@ function resolveAllLabelEnd(events) {
|
|
|
32870
33141
|
function resolveToLabelEnd(events, context) {
|
|
32871
33142
|
let index2 = events.length;
|
|
32872
33143
|
let offset = 0;
|
|
32873
|
-
let
|
|
33144
|
+
let open6;
|
|
32874
33145
|
let close;
|
|
32875
33146
|
let media;
|
|
32876
33147
|
while (index2--) {
|
|
32877
33148
|
const token = events[index2][1];
|
|
32878
|
-
if (
|
|
33149
|
+
if (open6) {
|
|
32879
33150
|
if (token.type === "link" || token.type === "labelLink" && token._inactive) {
|
|
32880
33151
|
break;
|
|
32881
33152
|
}
|
|
@@ -32884,7 +33155,7 @@ function resolveToLabelEnd(events, context) {
|
|
|
32884
33155
|
}
|
|
32885
33156
|
} else if (close) {
|
|
32886
33157
|
if (events[index2][0] === "enter" && (token.type === "labelImage" || token.type === "labelLink") && !token._balanced) {
|
|
32887
|
-
|
|
33158
|
+
open6 = index2;
|
|
32888
33159
|
if (token.type !== "labelLink") {
|
|
32889
33160
|
offset = 2;
|
|
32890
33161
|
break;
|
|
@@ -32895,9 +33166,9 @@ function resolveToLabelEnd(events, context) {
|
|
|
32895
33166
|
}
|
|
32896
33167
|
}
|
|
32897
33168
|
const group = {
|
|
32898
|
-
type: events[
|
|
33169
|
+
type: events[open6][1].type === "labelLink" ? "link" : "image",
|
|
32899
33170
|
start: {
|
|
32900
|
-
...events[
|
|
33171
|
+
...events[open6][1].start
|
|
32901
33172
|
},
|
|
32902
33173
|
end: {
|
|
32903
33174
|
...events[events.length - 1][1].end
|
|
@@ -32906,7 +33177,7 @@ function resolveToLabelEnd(events, context) {
|
|
|
32906
33177
|
const label2 = {
|
|
32907
33178
|
type: "label",
|
|
32908
33179
|
start: {
|
|
32909
|
-
...events[
|
|
33180
|
+
...events[open6][1].start
|
|
32910
33181
|
},
|
|
32911
33182
|
end: {
|
|
32912
33183
|
...events[close][1].end
|
|
@@ -32915,20 +33186,20 @@ function resolveToLabelEnd(events, context) {
|
|
|
32915
33186
|
const text7 = {
|
|
32916
33187
|
type: "labelText",
|
|
32917
33188
|
start: {
|
|
32918
|
-
...events[
|
|
33189
|
+
...events[open6 + offset + 2][1].end
|
|
32919
33190
|
},
|
|
32920
33191
|
end: {
|
|
32921
33192
|
...events[close - 2][1].start
|
|
32922
33193
|
}
|
|
32923
33194
|
};
|
|
32924
33195
|
media = [["enter", group, context], ["enter", label2, context]];
|
|
32925
|
-
media = push(media, events.slice(
|
|
33196
|
+
media = push(media, events.slice(open6 + 1, open6 + offset + 3));
|
|
32926
33197
|
media = push(media, [["enter", text7, context]]);
|
|
32927
|
-
media = push(media, resolveAll(context.parser.constructs.insideSpan.null, events.slice(
|
|
33198
|
+
media = push(media, resolveAll(context.parser.constructs.insideSpan.null, events.slice(open6 + offset + 4, close - 3), context));
|
|
32928
33199
|
media = push(media, [["exit", text7, context], events[close - 2], events[close - 1], ["exit", label2, context]]);
|
|
32929
33200
|
media = push(media, events.slice(close + 1));
|
|
32930
33201
|
media = push(media, [["exit", group, context]]);
|
|
32931
|
-
splice(events,
|
|
33202
|
+
splice(events, open6, events.length, media);
|
|
32932
33203
|
return events;
|
|
32933
33204
|
}
|
|
32934
33205
|
function tokenizeLabelEnd(effects, ok4, nok) {
|
|
@@ -33099,9 +33370,9 @@ function tokenizeLabelStartImage(effects, ok4, nok) {
|
|
|
33099
33370
|
effects.enter("labelImageMarker");
|
|
33100
33371
|
effects.consume(code3);
|
|
33101
33372
|
effects.exit("labelImageMarker");
|
|
33102
|
-
return
|
|
33373
|
+
return open6;
|
|
33103
33374
|
}
|
|
33104
|
-
function
|
|
33375
|
+
function open6(code3) {
|
|
33105
33376
|
if (code3 === 91) {
|
|
33106
33377
|
effects.enter("labelMarker");
|
|
33107
33378
|
effects.consume(code3);
|
|
@@ -33933,30 +34204,30 @@ function gfmStrikethrough(options) {
|
|
|
33933
34204
|
let index2 = -1;
|
|
33934
34205
|
while (++index2 < events.length) {
|
|
33935
34206
|
if (events[index2][0] === "enter" && events[index2][1].type === "strikethroughSequenceTemporary" && events[index2][1]._close) {
|
|
33936
|
-
let
|
|
33937
|
-
while (
|
|
33938
|
-
if (events[
|
|
33939
|
-
events[index2][1].end.offset - events[index2][1].start.offset === events[
|
|
34207
|
+
let open6 = index2;
|
|
34208
|
+
while (open6--) {
|
|
34209
|
+
if (events[open6][0] === "exit" && events[open6][1].type === "strikethroughSequenceTemporary" && events[open6][1]._open && // If the sizes are the same:
|
|
34210
|
+
events[index2][1].end.offset - events[index2][1].start.offset === events[open6][1].end.offset - events[open6][1].start.offset) {
|
|
33940
34211
|
events[index2][1].type = "strikethroughSequence";
|
|
33941
|
-
events[
|
|
34212
|
+
events[open6][1].type = "strikethroughSequence";
|
|
33942
34213
|
const strikethrough = {
|
|
33943
34214
|
type: "strikethrough",
|
|
33944
|
-
start: Object.assign({}, events[
|
|
34215
|
+
start: Object.assign({}, events[open6][1].start),
|
|
33945
34216
|
end: Object.assign({}, events[index2][1].end)
|
|
33946
34217
|
};
|
|
33947
34218
|
const text7 = {
|
|
33948
34219
|
type: "strikethroughText",
|
|
33949
|
-
start: Object.assign({}, events[
|
|
34220
|
+
start: Object.assign({}, events[open6][1].end),
|
|
33950
34221
|
end: Object.assign({}, events[index2][1].start)
|
|
33951
34222
|
};
|
|
33952
|
-
const nextEvents = [["enter", strikethrough, context], ["enter", events[
|
|
34223
|
+
const nextEvents = [["enter", strikethrough, context], ["enter", events[open6][1], context], ["exit", events[open6][1], context], ["enter", text7, context]];
|
|
33953
34224
|
const insideSpan2 = context.parser.constructs.insideSpan.null;
|
|
33954
34225
|
if (insideSpan2) {
|
|
33955
|
-
splice(nextEvents, nextEvents.length, 0, resolveAll(insideSpan2, events.slice(
|
|
34226
|
+
splice(nextEvents, nextEvents.length, 0, resolveAll(insideSpan2, events.slice(open6 + 1, index2), context));
|
|
33956
34227
|
}
|
|
33957
34228
|
splice(nextEvents, nextEvents.length, 0, [["exit", text7, context], ["enter", events[index2][1], context], ["exit", events[index2][1], context], ["exit", strikethrough, context]]);
|
|
33958
|
-
splice(events,
|
|
33959
|
-
index2 =
|
|
34229
|
+
splice(events, open6 - 1, index2 - open6 + 3, nextEvents);
|
|
34230
|
+
index2 = open6 + nextEvents.length - 2;
|
|
33960
34231
|
break;
|
|
33961
34232
|
}
|
|
33962
34233
|
}
|
|
@@ -34558,8 +34829,8 @@ function gfmTaskListItem() {
|
|
|
34558
34829
|
}
|
|
34559
34830
|
function tokenizeTasklistCheck(effects, ok4, nok) {
|
|
34560
34831
|
const self = this;
|
|
34561
|
-
return
|
|
34562
|
-
function
|
|
34832
|
+
return open6;
|
|
34833
|
+
function open6(code3) {
|
|
34563
34834
|
if (
|
|
34564
34835
|
// Exit if there’s stuff before.
|
|
34565
34836
|
self.previous !== null || // Exit if not in the first content that is the first child of a list
|
|
@@ -36048,8 +36319,8 @@ function compiler(options) {
|
|
|
36048
36319
|
events[start][1]._spread = listSpread;
|
|
36049
36320
|
}
|
|
36050
36321
|
function opener(create, and) {
|
|
36051
|
-
return
|
|
36052
|
-
function
|
|
36322
|
+
return open6;
|
|
36323
|
+
function open6(token) {
|
|
36053
36324
|
enter.call(this, create(token), token);
|
|
36054
36325
|
if (and) and.call(this, token);
|
|
36055
36326
|
}
|
|
@@ -36081,19 +36352,19 @@ function compiler(options) {
|
|
|
36081
36352
|
}
|
|
36082
36353
|
function exit3(token, onExitError) {
|
|
36083
36354
|
const node2 = this.stack.pop();
|
|
36084
|
-
const
|
|
36085
|
-
if (!
|
|
36355
|
+
const open6 = this.tokenStack.pop();
|
|
36356
|
+
if (!open6) {
|
|
36086
36357
|
throw new Error("Cannot close `" + token.type + "` (" + stringifyPosition({
|
|
36087
36358
|
start: token.start,
|
|
36088
36359
|
end: token.end
|
|
36089
36360
|
}) + "): it\u2019s not open");
|
|
36090
36361
|
}
|
|
36091
|
-
if (
|
|
36362
|
+
if (open6[0].type !== token.type) {
|
|
36092
36363
|
if (onExitError) {
|
|
36093
|
-
onExitError.call(this, token,
|
|
36364
|
+
onExitError.call(this, token, open6[0]);
|
|
36094
36365
|
} else {
|
|
36095
|
-
const handler =
|
|
36096
|
-
handler.call(this, token,
|
|
36366
|
+
const handler = open6[1] || defaultOnError;
|
|
36367
|
+
handler.call(this, token, open6[0]);
|
|
36097
36368
|
}
|
|
36098
36369
|
}
|
|
36099
36370
|
node2.position.end = point2(token.end);
|
|
@@ -39513,7 +39784,8 @@ function Overview() {
|
|
|
39513
39784
|
return true;
|
|
39514
39785
|
}
|
|
39515
39786
|
if (key.return) {
|
|
39516
|
-
if (selected)
|
|
39787
|
+
if (selected && isOmpSeat(selected)) attach2(selected);
|
|
39788
|
+
else if (selected) go("session");
|
|
39517
39789
|
return true;
|
|
39518
39790
|
}
|
|
39519
39791
|
if (!selected) return false;
|
|
@@ -39534,7 +39806,7 @@ function Overview() {
|
|
|
39534
39806
|
return false;
|
|
39535
39807
|
});
|
|
39536
39808
|
const groupRows = (kind) => view.tree.filter((n) => n.kind === kind).flatMap((n) => [
|
|
39537
|
-
...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) }] : [],
|
|
39809
|
+
...kind === "rig" ? [{ kind: "project", key: n.key, label: n.label, color: C.blue, count: n.count, ...n.shown !== void 0 && { shown: n.shown }, rig: true, folder: folderOf(n.branches[0]?.sessions[0]?.cwd) }] : [],
|
|
39538
39810
|
...n.branches.flatMap((b3) => b3.sessions.map((s) => ({ kind: "session", key: s.id, s, indent: kind === "rig" ? 2 : 0, group: kind })))
|
|
39539
39811
|
]);
|
|
39540
39812
|
const rigRows = groupRows("rig"), kernelRows = groupRows("kernel");
|
|
@@ -39556,6 +39828,7 @@ function Overview() {
|
|
|
39556
39828
|
const stateW = Math.max(...Object.values(t.state).map((x) => x.length)) + 1;
|
|
39557
39829
|
const topicW = Math.max(6, inner - 6 - nameW - stateW - 3);
|
|
39558
39830
|
const askW = Math.max(6, inner - 2 - nameW - 9 - 7);
|
|
39831
|
+
const roleW = Math.max(11, ...rigRows.map((r) => r.kind === "session" ? [...r.s.rig?.role ?? ""].length + 2 : 0));
|
|
39559
39832
|
const yoursBox = /* @__PURE__ */ jsx10(TitledBox, { title: t.overview.yours(yoursCount), color: yoursCount ? C.red : C.line, titleColor: yoursCount ? C.red : C.dim, height: yoursHeight + 2, children: yoursCount === 0 ? /* @__PURE__ */ jsx10(Text7, { color: C.faint, children: t.overview.nobodyWaits }) : [...view.yours.slice(0, yoursHeight).map((s) => {
|
|
39560
39833
|
const st = botState(s);
|
|
39561
39834
|
return /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", backgroundColor: s.id === sel ? C.sel : void 0, children: [
|
|
@@ -39621,16 +39894,18 @@ function Overview() {
|
|
|
39621
39894
|
] }) : null,
|
|
39622
39895
|
/* @__PURE__ */ jsxs6(Text7, { color: C.faint, children: [
|
|
39623
39896
|
" ",
|
|
39624
|
-
t.overview.sessions(r.count)
|
|
39897
|
+
r.shown !== void 0 ? t.overview.sessionsOf(r.count, r.shown) : t.overview.sessions(r.count)
|
|
39625
39898
|
] })
|
|
39626
|
-
] }, 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) });
|
|
39899
|
+
] }, 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, roleW }, r.key) : null) });
|
|
39627
39900
|
const rigsBox = groupBox(t.overview.rigsGroup, rigRows, rigsHeight);
|
|
39628
39901
|
const kernelBox = groupBox(t.overview.kernelGroup, kernelRows, kernelHeight);
|
|
39902
|
+
const stopped2 = !!selected && isStoppedOmpSeat(selected);
|
|
39629
39903
|
const keys = writing ? [["\u21B5", t.keys.sendOnly], ["alt+\u21B5", t.keys.newLine], ["esc", t.keys.cancel]] : 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]] : [
|
|
39904
|
+
// On an OMP seat ↵ attaches its terminal; on a stopped one, neither ↵ nor a has anything to attach.
|
|
39630
39905
|
["j k", t.keys.navigate],
|
|
39631
|
-
["\u21B5", t.keys.open],
|
|
39906
|
+
...stopped2 ? [] : [["\u21B5", selected && isOmpSeat(selected) ? t.keys.attachSeat : t.keys.open]],
|
|
39632
39907
|
...view.yours.length ? [["tab", t.keys.next], ["y n", t.keys.answer]] : [],
|
|
39633
|
-
["a", t.keys.attach],
|
|
39908
|
+
...stopped2 ? [] : [["a", t.keys.attach]],
|
|
39634
39909
|
...writable2 ? [["m", t.keys.writeProject]] : [],
|
|
39635
39910
|
...decisions.length ? [["D", t.keys.decide]] : [],
|
|
39636
39911
|
...near.length ? [["H", t.keys.handover]] : [],
|
|
@@ -39705,21 +39980,23 @@ function Overview() {
|
|
|
39705
39980
|
) : null
|
|
39706
39981
|
] });
|
|
39707
39982
|
}
|
|
39708
|
-
function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0, group }) {
|
|
39983
|
+
function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0, group, roleW = 11 }) {
|
|
39709
39984
|
const { t, g } = useTui();
|
|
39710
39985
|
const st = botState(s);
|
|
39711
39986
|
const n = helperCount(s);
|
|
39987
|
+
const stopped2 = isStoppedOmpSeat(s);
|
|
39988
|
+
const roleTool = group === "kernel" ? `${(s.rig?.role ?? "").replace(/\.(agent|lead|worker)$/, "").padEnd(11)}${s.tool}` : `${(s.rig?.role ?? "").padEnd(roleW)}${s.tool}`;
|
|
39712
39989
|
return /* @__PURE__ */ jsxs6(Text7, { wrap: "truncate", backgroundColor: on ? C.sel : void 0, children: [
|
|
39713
39990
|
/* @__PURE__ */ jsx10(Text7, { color: on ? C.coral : C.faint, children: on ? "\u258C" : " " }),
|
|
39714
39991
|
/* @__PURE__ */ jsx10(Text7, { children: " ".repeat(2 + indent2) }),
|
|
39715
|
-
/* @__PURE__ */ jsxs6(Text7, { color: s.offline ? C.faint : STATE_COLOR[st], children: [
|
|
39992
|
+
/* @__PURE__ */ jsxs6(Text7, { color: s.offline || stopped2 ? C.faint : STATE_COLOR[st], children: [
|
|
39716
39993
|
g[st],
|
|
39717
39994
|
" "
|
|
39718
39995
|
] }),
|
|
39719
|
-
/* @__PURE__ */ jsx10(Text7, { color: s.offline ? C.dim : C.fg, bold:
|
|
39720
|
-
group ? /* @__PURE__ */ jsxs6(Text7, { color: C.dim, children: [
|
|
39996
|
+
/* @__PURE__ */ jsx10(Text7, { color: stopped2 ? C.faint : s.offline ? C.dim : C.fg, bold: !stopped2, children: fit3(s.name, nameW) }),
|
|
39997
|
+
group ? /* @__PURE__ */ jsxs6(Text7, { color: stopped2 ? C.faint : C.dim, children: [
|
|
39721
39998
|
" ",
|
|
39722
|
-
fit3(
|
|
39999
|
+
fit3(roleTool, topicW - 1),
|
|
39723
40000
|
" "
|
|
39724
40001
|
] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
39725
40002
|
s.rig ? /* @__PURE__ */ jsxs6(Text7, { color: C.blue, children: [
|
|
@@ -39731,7 +40008,7 @@ function SessionRow({ s, on, nameW, topicW, stateW, indent: indent2 = 0, group }
|
|
|
39731
40008
|
" "
|
|
39732
40009
|
] })
|
|
39733
40010
|
] }),
|
|
39734
|
-
/* @__PURE__ */ jsx10(Text7, { color: s.offline ? C.faint : STATE_COLOR[st], children: fit3(s.offline ? t.overview.offline : t.state[st], stateW).trimEnd() }),
|
|
40011
|
+
/* @__PURE__ */ jsx10(Text7, { color: s.offline || stopped2 ? C.faint : STATE_COLOR[st], children: fit3(s.offline ? t.overview.offline : stopped2 ? t.state.stopped : t.state[st], stateW).trimEnd() }),
|
|
39735
40012
|
n > 0 ? /* @__PURE__ */ jsxs6(Text7, { color: C.violet, children: [
|
|
39736
40013
|
" +",
|
|
39737
40014
|
n
|
|
@@ -39770,7 +40047,7 @@ var init_Overview = __esm({
|
|
|
39770
40047
|
// src/tui/images.tsx
|
|
39771
40048
|
import { mkdir as mkdir13, writeFile as writeFile17 } from "fs/promises";
|
|
39772
40049
|
import { tmpdir as tmpdir3 } from "os";
|
|
39773
|
-
import { join as
|
|
40050
|
+
import { join as join38 } from "path";
|
|
39774
40051
|
import { useRef as useRef8, useState as useState4 } from "react";
|
|
39775
40052
|
import { Text as Text8 } from "ink";
|
|
39776
40053
|
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
@@ -39873,9 +40150,9 @@ function useOpenImage() {
|
|
|
39873
40150
|
const { ref, route } = item;
|
|
39874
40151
|
void (async () => {
|
|
39875
40152
|
const { mime, data } = await getImage(client, ref.id, route);
|
|
39876
|
-
const dir =
|
|
40153
|
+
const dir = join38(tmpdir3(), "ledge-images");
|
|
39877
40154
|
await mkdir13(dir, { recursive: true, mode: 448 });
|
|
39878
|
-
const file =
|
|
40155
|
+
const file = join38(dir, `${ref.id}.${EXT2[mime]}`);
|
|
39879
40156
|
await writeFile17(file, Buffer.from(data, "base64"), { mode: 384 });
|
|
39880
40157
|
await openFile2(file);
|
|
39881
40158
|
})().catch((e) => toast({ text: t.images.openFailed(e instanceof AttachmentFailure ? e.reason : e.message), tone: "error" }));
|
|
@@ -40660,11 +40937,11 @@ function cardPlan(actions, room) {
|
|
|
40660
40937
|
const raw = rows.map((r) => r.state ?? "proposed");
|
|
40661
40938
|
const stopAt = raw.findIndex((s) => s === "failed" || s === "refused" || s === "stale");
|
|
40662
40939
|
const shown = states.map((s, i) => s === "proposed" && stopAt >= 0 && i > stopAt ? "held" : s);
|
|
40663
|
-
const
|
|
40940
|
+
const open6 = shown.flatMap((s, i) => ["done", "running", "denied", "stale", "cut"].includes(s) ? [] : [i]);
|
|
40664
40941
|
const skip = stopAt >= 0 && raw[stopAt] !== "failed";
|
|
40665
|
-
const rowsAll = skip ?
|
|
40942
|
+
const rowsAll = skip ? open6.filter((i) => i !== stopAt) : stopAt >= 0 && states[stopAt] === "cut" ? [] : open6;
|
|
40666
40943
|
const all2 = { kind: stopAt < 0 ? "all" : skip ? "skip" : "resume", rows: rowsAll, k: stopAt + 1 };
|
|
40667
|
-
return { rows, shown, open:
|
|
40944
|
+
return { rows, shown, open: open6, stopAt, all: all2, cutLines };
|
|
40668
40945
|
}
|
|
40669
40946
|
function firstRow(p) {
|
|
40670
40947
|
const act = p.shown.findIndex((s) => s === "proposed" || s === "held" || s === "failed");
|
|
@@ -42054,8 +42331,8 @@ function listItems2(roles, query, builtinOpen) {
|
|
|
42054
42331
|
const by = (a, b3) => a.name.localeCompare(b3.name) || a.id.localeCompare(b3.id);
|
|
42055
42332
|
const kept = roles.filter((r) => matches(r, query)).sort(by);
|
|
42056
42333
|
const mine = kept.filter((r) => r.source === "user"), builtin = kept.filter((r) => r.source === "builtin");
|
|
42057
|
-
const
|
|
42058
|
-
return { mine, builtin, items: [...mine.map((role) => ({ kind: "role", role })), ...builtin.length ? [{ kind: "builtin" }] : [], ...
|
|
42334
|
+
const open6 = builtinOpen || query.trim() !== "";
|
|
42335
|
+
return { mine, builtin, items: [...mine.map((role) => ({ kind: "role", role })), ...builtin.length ? [{ kind: "builtin" }] : [], ...open6 ? builtin.map((role) => ({ kind: "role", role })) : []] };
|
|
42059
42336
|
}
|
|
42060
42337
|
function listLines(roles, o, t, g) {
|
|
42061
42338
|
const r = t.roles, w = o.width;
|
|
@@ -42087,11 +42364,11 @@ function listLines(roles, o, t, g) {
|
|
|
42087
42364
|
if (mine.length) lines.push([]);
|
|
42088
42365
|
const s = i === o.sel;
|
|
42089
42366
|
if (s) selLine = lines.length;
|
|
42090
|
-
const
|
|
42367
|
+
const open6 = o.builtinOpen || o.query.trim() !== "";
|
|
42091
42368
|
const bg = s ? C.sel : void 0;
|
|
42092
|
-
lines.push([{ text: s ? "\u258C" : " ", color: s && o.focused ? C.coral : C.faint, ...bg ? { bg } : {} }, { text: `${
|
|
42369
|
+
lines.push([{ text: s ? "\u258C" : " ", color: s && o.focused ? C.coral : C.faint, ...bg ? { bg } : {} }, { text: `${open6 ? g.unfolded : g.folded} ${r.builtin}`, color: C.dim, ...bg ? { bg } : {} }, { text: ` \xB7 ${builtin.length}`, color: C.faint, ...bg ? { bg } : {} }]);
|
|
42093
42370
|
i++;
|
|
42094
|
-
if (
|
|
42371
|
+
if (open6) builtin.forEach(roleLine);
|
|
42095
42372
|
}
|
|
42096
42373
|
return { lines, selLine };
|
|
42097
42374
|
}
|
|
@@ -42187,7 +42464,7 @@ function param(label2, value, o, t, g, w, narrow, extra = {}) {
|
|
|
42187
42464
|
const usedL = cells(lab.map((x) => x.text).join("")), usedV = cells(val.map((x) => x.text).join(""));
|
|
42188
42465
|
return { line: [...lab, { text: " ".repeat(lw - usedL) }, ...val, { text: " ".repeat(Math.max(1, w - lw - usedV - cells(p))) }, { text: p, color: provColor(k) }], rail: k, ...extra };
|
|
42189
42466
|
}
|
|
42190
|
-
function paramRows(d, seat2, files,
|
|
42467
|
+
function paramRows(d, seat2, files, open6, o, t) {
|
|
42191
42468
|
const r = t.roles, w = o.width, g = o.g, n = o.narrow;
|
|
42192
42469
|
const P = (label2, value, origin, extra = {}) => param(label2, value, origin, t, g, w, n, extra);
|
|
42193
42470
|
const out = [];
|
|
@@ -42228,8 +42505,8 @@ function paramRows(d, seat2, files, open5, o, t) {
|
|
|
42228
42505
|
const u = prof.uses;
|
|
42229
42506
|
const loadout = seat2?.live?.skills;
|
|
42230
42507
|
if (loadout) {
|
|
42231
|
-
out.push(P(r.p.skills, v(`${r.skillsProjected(loadout.length)} ${
|
|
42232
|
-
if (
|
|
42508
|
+
out.push(P(r.p.skills, v(`${r.skillsProjected(loadout.length)} ${open6.has("loadout") ? g.unfolded : g.folded}`), { kind: "inherited", from: "launch" }, { fold: "loadout" }));
|
|
42509
|
+
if (open6.has("loadout")) for (const s of loadout) out.push({ line: [{ text: " ".repeat(n ? 16 : 19) }, { text: s.id, color: C.dim }], rail: "inh" });
|
|
42233
42510
|
}
|
|
42234
42511
|
const list3 = (label2, l, what, fold) => {
|
|
42235
42512
|
if (!l.declared) {
|
|
@@ -42243,9 +42520,9 @@ function paramRows(d, seat2, files, open5, o, t) {
|
|
|
42243
42520
|
l.items.forEach((x, i) => {
|
|
42244
42521
|
const na = !!(seat2 && x.runtime && seat2.runtime.value && x.runtime !== seat2.runtime.value);
|
|
42245
42522
|
const key = fold?.(x);
|
|
42246
|
-
const row3 = P(i === 0 ? label2 : "", v(`${what(x)}${na ? ` \xB7 ${r.na(x.runtime)}` : ""}${key ? ` ${
|
|
42523
|
+
const row3 = P(i === 0 ? label2 : "", v(`${what(x)}${na ? ` \xB7 ${r.na(x.runtime)}` : ""}${key ? ` ${open6.has(key) ? g.unfolded : g.folded}` : ""}`, na ? C.faint : C.fg), x.origin, key ? { fold: key } : {});
|
|
42247
42524
|
out.push(na ? { ...row3, line: row3.line.map((s) => ({ ...s, color: C.faint })) } : row3);
|
|
42248
|
-
if (key &&
|
|
42525
|
+
if (key && open6.has(key)) {
|
|
42249
42526
|
const body = x.plugin ? x.plugin.skills.join(", ") : (x.absolutePath && files[x.absolutePath]?.content) ?? t.roles.reading;
|
|
42250
42527
|
for (const bl of body.split("\n")) out.push({ line: cut2([{ text: " ".repeat(n ? 16 : 19) }, { text: bl, color: C.dim }], w), rail: "inh" });
|
|
42251
42528
|
}
|
|
@@ -42333,9 +42610,9 @@ function yamlRows(d, seat2, files, o, t) {
|
|
|
42333
42610
|
}
|
|
42334
42611
|
return out;
|
|
42335
42612
|
}
|
|
42336
|
-
function filesFor(d, seat2, tab, at,
|
|
42613
|
+
function filesFor(d, seat2, tab, at, open6) {
|
|
42337
42614
|
if (tab === 0) return roleDocs(d, seat2).map((e) => e.absolutePath).filter((x) => !!x);
|
|
42338
|
-
if (tab === 1) return (profileOf(d, seat2)?.uses.runtimeResources.items ?? []).filter((x) => x.absolutePath &&
|
|
42615
|
+
if (tab === 1) return (profileOf(d, seat2)?.uses.runtimeResources.items ?? []).filter((x) => x.absolutePath && open6.has(`rr:${x.id}`)).map((x) => x.absolutePath);
|
|
42339
42616
|
if (tab === 2) {
|
|
42340
42617
|
const p = pieces(d, seat2)[at];
|
|
42341
42618
|
return p?.kind === "entry" && p.entry.absolutePath && !isMissing(p.entry) ? [p.entry.absolutePath] : [];
|
|
@@ -42412,7 +42689,7 @@ function RolesScreen({ onRigs, machineId, onMachine }) {
|
|
|
42412
42689
|
const [scroll, setScroll] = useState14(0);
|
|
42413
42690
|
const [at, setAt] = useState14(0);
|
|
42414
42691
|
const [reading, setReading] = useState14(false);
|
|
42415
|
-
const [
|
|
42692
|
+
const [open6, setOpen] = useState14(/* @__PURE__ */ new Set());
|
|
42416
42693
|
const [files, setFiles] = useState14({});
|
|
42417
42694
|
const { items } = listItems2(roles.roles, query, builtinOpen);
|
|
42418
42695
|
const firstRole = items.find((i) => i.kind === "role");
|
|
@@ -42438,7 +42715,7 @@ function RolesScreen({ onRigs, machineId, onMachine }) {
|
|
|
42438
42715
|
asks.current.reset();
|
|
42439
42716
|
setFiles({});
|
|
42440
42717
|
}, [currentId, machine?.id]);
|
|
42441
|
-
const wanted = (d ? filesFor(d, seat2, shownTab, at,
|
|
42718
|
+
const wanted = (d ? filesFor(d, seat2, shownTab, at, open6) : []).join("\n");
|
|
42442
42719
|
useEffect13(() => {
|
|
42443
42720
|
if (!wanted || !machine || !currentId) return;
|
|
42444
42721
|
const id = currentId, mid = machine.id;
|
|
@@ -42451,7 +42728,7 @@ function RolesScreen({ onRigs, machineId, onMachine }) {
|
|
|
42451
42728
|
const bodyH = Math.max(3, rows - 4);
|
|
42452
42729
|
const head2 = d && summary ? headRows(d, summary, { seat: seat2, tab: shownTab, width: w, narrow: !wide, seats }, t) : [];
|
|
42453
42730
|
const ctx = d && shownTab === 2 ? contextRows(d, seat2, files, at, { width: w, raw, narrow: !wide, g, lang }, t) : null;
|
|
42454
|
-
const body = !d ? [] : shownTab === 0 ? roleRows(d, seat2, files, { width: w, raw, narrow: !wide, g, lang }, t) : shownTab === 1 ? paramRows(d, seat2, files,
|
|
42731
|
+
const body = !d ? [] : shownTab === 0 ? roleRows(d, seat2, files, { width: w, raw, narrow: !wide, g, lang }, t) : shownTab === 1 ? paramRows(d, seat2, files, open6, { width: w, narrow: !wide, g }, t) : shownTab === 2 ? ctx.rows : yamlRows(d, seat2, files, { width: w }, t);
|
|
42455
42732
|
const room = Math.max(1, bodyH - head2.length);
|
|
42456
42733
|
const maxScroll = Math.max(0, body.length - room);
|
|
42457
42734
|
const params = shownTab === 1 ? body.map((x, i) => x.rail ? i : -1).filter((i) => i >= 0) : [];
|
|
@@ -42709,7 +42986,7 @@ function RigsView({ initialMachine, onRoles }) {
|
|
|
42709
42986
|
const rigs = listedRigs(state2);
|
|
42710
42987
|
const [at, setAt] = useState15(0);
|
|
42711
42988
|
const selectedId = useRef13(null);
|
|
42712
|
-
const [
|
|
42989
|
+
const [open6, setOpen] = useState15(/* @__PURE__ */ new Set());
|
|
42713
42990
|
const [seatAt, setSeatAt] = useState15(null);
|
|
42714
42991
|
const [confirm, setConfirm] = useState15(null);
|
|
42715
42992
|
const [seats, setSeats] = useState15(null);
|
|
@@ -42719,7 +42996,7 @@ function RigsView({ initialMachine, onRoles }) {
|
|
|
42719
42996
|
}, [ids]);
|
|
42720
42997
|
const current2 = rigs[Math.min(at, rigs.length - 1)];
|
|
42721
42998
|
selectedId.current = current2?.id ?? null;
|
|
42722
|
-
const seatNodes = current2 &&
|
|
42999
|
+
const seatNodes = current2 && open6.has(current2.id) ? current2.nodes : [];
|
|
42723
43000
|
const seatSel = seatAt !== null && seatAt < seatNodes.length ? seatAt : null;
|
|
42724
43001
|
const down = () => {
|
|
42725
43002
|
if (seatSel !== null ? seatSel + 1 < seatNodes.length : seatNodes.length > 0) {
|
|
@@ -42737,7 +43014,7 @@ function RigsView({ initialMachine, onRoles }) {
|
|
|
42737
43014
|
}
|
|
42738
43015
|
const n = step2(at, -1, rigs.length), prev = rigs[n];
|
|
42739
43016
|
setAt(n);
|
|
42740
|
-
setSeatAt(prev &&
|
|
43017
|
+
setSeatAt(prev && open6.has(prev.id) && prev.nodes.length ? prev.nodes.length - 1 : null);
|
|
42741
43018
|
};
|
|
42742
43019
|
const run4 = (a) => {
|
|
42743
43020
|
void rig.act(a).then((d) => {
|
|
@@ -42897,12 +43174,12 @@ function RigsView({ initialMachine, onRoles }) {
|
|
|
42897
43174
|
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], ["v", t.roles.k.view], ["j k", t.keys.navigate], ["\u21B5", o.unfold], ...seatSel !== null ? [["i", t.roles.k.role]] : [], ["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]];
|
|
42898
43175
|
const crumb = [state2?.version ? o.version(state2.version) : o.title, machine?.label, t.roles.rigs].filter(Boolean).join(" \xB7 ");
|
|
42899
43176
|
return /* @__PURE__ */ jsxs17(Frame, { crumb, crumbShort: o.title, keys, children: [
|
|
42900
|
-
!machine ? null : rig.error ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.yellow, children: rig.error === "offline" ? o.offline : o.outdated }) }) : !state2 ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.loading }) }) : !state2.installed ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.dim, children: o.notInstalled }) }) : seats && seatRig ? /* @__PURE__ */ jsx22(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__ */ jsx22(Body, { state: state2, rigs, at, seatAt: seatSel, open:
|
|
43177
|
+
!machine ? null : rig.error ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.yellow, children: rig.error === "offline" ? o.offline : o.outdated }) }) : !state2 ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.loading }) }) : !state2.installed ? /* @__PURE__ */ jsx22(TitledBox, { title: o.title, mark: { text: machine.label, color: C.dim }, flexGrow: 1, children: /* @__PURE__ */ jsx22(Text18, { color: C.dim, children: o.notInstalled }) }) : seats && seatRig ? /* @__PURE__ */ jsx22(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__ */ jsx22(Body, { state: state2, rigs, at, seatAt: seatSel, open: open6, machineLabel: machine.label, roleOf: roleOf4 }),
|
|
42901
43178
|
confirm ? /* @__PURE__ */ jsx22(ConfirmBox, { confirm }) : null,
|
|
42902
43179
|
rig.pending ? /* @__PURE__ */ jsx22(Box17, { paddingX: 1, height: 1, children: /* @__PURE__ */ jsx22(Text18, { wrap: "truncate", color: C.blue, children: o.running(confirmOf(state2 ?? EMPTY2, rig.pending).commands.join(" && ")) }) }) : null
|
|
42903
43180
|
] });
|
|
42904
43181
|
}
|
|
42905
|
-
function Body({ state: state2, rigs, at, seatAt, open:
|
|
43182
|
+
function Body({ state: state2, rigs, at, seatAt, open: open6, machineLabel: machineLabel2, roleOf: roleOf4 }) {
|
|
42906
43183
|
const { t } = useTui();
|
|
42907
43184
|
const o = t.openrig;
|
|
42908
43185
|
const up = daemonUp(state2);
|
|
@@ -42940,10 +43217,10 @@ function Body({ state: state2, rigs, at, seatAt, open: open5, machineLabel: mach
|
|
|
42940
43217
|
] }, n.session))
|
|
42941
43218
|
] })
|
|
42942
43219
|
] }),
|
|
42943
|
-
/* @__PURE__ */ jsx22(TitledBox, { title: `${o.rigs} \xB7 ${rigs.length}`, flexGrow: 1, children: !up ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.stoppedDaemon }) : !rigs.length ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.noRigs }) : rigs.map((r, i) => /* @__PURE__ */ jsx22(RigRow, { rig: r, selected: i === at && seatAt === null, seatAt: i === at ? seatAt : null, open:
|
|
43220
|
+
/* @__PURE__ */ jsx22(TitledBox, { title: `${o.rigs} \xB7 ${rigs.length}`, flexGrow: 1, children: !up ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.stoppedDaemon }) : !rigs.length ? /* @__PURE__ */ jsx22(Text18, { color: C.faint, children: o.noRigs }) : rigs.map((r, i) => /* @__PURE__ */ jsx22(RigRow, { rig: r, selected: i === at && seatAt === null, seatAt: i === at ? seatAt : null, open: open6.has(r.id), roleOf: roleOf4 }, r.id)) })
|
|
42944
43221
|
] });
|
|
42945
43222
|
}
|
|
42946
|
-
function RigRow({ rig, selected, seatAt, open:
|
|
43223
|
+
function RigRow({ rig, selected, seatAt, open: open6, roleOf: roleOf4 }) {
|
|
42947
43224
|
const { t } = useTui();
|
|
42948
43225
|
const o = t.openrig;
|
|
42949
43226
|
const look = rigLook(rig), l = LOOK[look];
|
|
@@ -42953,14 +43230,14 @@ function RigRow({ rig, selected, seatAt, open: open5, roleOf: roleOf4 }) {
|
|
|
42953
43230
|
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
|
|
42954
43231
|
/* @__PURE__ */ jsx22(Box17, { backgroundColor: selected ? C.sel : void 0, children: /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
42955
43232
|
/* @__PURE__ */ jsx22(Text18, { color: selected ? C.coral : C.faint, children: selected ? "\u258C" : " " }),
|
|
42956
|
-
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children:
|
|
43233
|
+
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: open6 ? "\u25BE " : "\u25B8 " }),
|
|
42957
43234
|
/* @__PURE__ */ jsx22(Text18, { color: C.fg, bold: true, children: rig.name.padEnd(16) }),
|
|
42958
43235
|
/* @__PURE__ */ jsx22(Text18, { color: l.color(), children: ` ${l.glyph} ${o.look[look]}`.padEnd(18) }),
|
|
42959
43236
|
/* @__PURE__ */ jsx22(Text18, { color: C.fg, children: o.seats(rig.running, rig.seats).padEnd(7) }),
|
|
42960
43237
|
note ? /* @__PURE__ */ jsx22(Text18, { color: note.color, children: note.text.padEnd(34) }) : /* @__PURE__ */ jsx22(Text18, { children: "".padEnd(34) }),
|
|
42961
43238
|
/* @__PURE__ */ jsx22(Text18, { color: C.dim, children: when })
|
|
42962
43239
|
] }) }),
|
|
42963
|
-
|
|
43240
|
+
open6 ? rig.nodes.map((n, i) => {
|
|
42964
43241
|
const s = i === seatAt, bg = s ? C.sel : void 0, role = roleOf4(rig.name, n.logicalId);
|
|
42965
43242
|
return /* @__PURE__ */ jsx22(Box17, { backgroundColor: bg, children: /* @__PURE__ */ jsxs17(Text18, { wrap: "truncate", children: [
|
|
42966
43243
|
/* @__PURE__ */ jsx22(Text18, { color: C.coral, children: s ? "\u258C" : " " }),
|
|
@@ -43472,7 +43749,7 @@ function Shell({ client, lang, setLang: setLangState, saveLang, theme, setThemeS
|
|
|
43472
43749
|
const attach2 = useCallback3((s) => {
|
|
43473
43750
|
const cmd = attachCommand(fleet, s);
|
|
43474
43751
|
if ("why" in cmd) {
|
|
43475
|
-
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" });
|
|
43752
|
+
toast({ text: cmd.why === "offline" ? t.toast.offline(s.name) : cmd.why === "omp" ? t.toast.noTerminalOmp(s.name) : cmd.why === "stopped" ? t.toast.seatStopped(s.name) : t.toast.noTerminal(s.name), tone: "info" });
|
|
43476
43753
|
return;
|
|
43477
43754
|
}
|
|
43478
43755
|
void suspendTerminal(async () => {
|
|
@@ -43772,7 +44049,7 @@ var init_glyphs = __esm({
|
|
|
43772
44049
|
|
|
43773
44050
|
// src/tui/settings.ts
|
|
43774
44051
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync13, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
43775
|
-
import { join as
|
|
44052
|
+
import { join as join39 } from "path";
|
|
43776
44053
|
import { z as z32 } from "zod";
|
|
43777
44054
|
function defaultLang(env) {
|
|
43778
44055
|
const locale = env.LC_ALL || env.LC_MESSAGES || env.LANG || "";
|
|
@@ -43798,14 +44075,14 @@ var init_settings = __esm({
|
|
|
43798
44075
|
"use strict";
|
|
43799
44076
|
init_paths();
|
|
43800
44077
|
SettingsSchema = z32.object({ lang: z32.enum(["fr", "en"]).optional(), theme: z32.enum(["auto", "dark", "light"]).optional() }).passthrough();
|
|
43801
|
-
settingsPath = () =>
|
|
44078
|
+
settingsPath = () => join39(ledgeDir(), "tui.json");
|
|
43802
44079
|
}
|
|
43803
44080
|
});
|
|
43804
44081
|
|
|
43805
44082
|
// src/tui/terminalProfile.ts
|
|
43806
44083
|
import { execFile as execFile10, spawn as spawn6 } from "child_process";
|
|
43807
|
-
import { mkdir as mkdir14, readFile as
|
|
43808
|
-
import { dirname as dirname13, join as
|
|
44084
|
+
import { mkdir as mkdir14, readFile as readFile19, realpath as realpath5, writeFile as writeFile18 } from "fs/promises";
|
|
44085
|
+
import { dirname as dirname13, join as join40 } from "path";
|
|
43809
44086
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
43810
44087
|
import { promisify } from "util";
|
|
43811
44088
|
function movesToLedgeTab(env, here, script) {
|
|
@@ -43833,13 +44110,13 @@ function fragment(commandline, iconWin) {
|
|
|
43833
44110
|
}
|
|
43834
44111
|
async function profileLoaded(localAppData) {
|
|
43835
44112
|
for (const rel of SETTINGS) {
|
|
43836
|
-
const text7 = await
|
|
44113
|
+
const text7 = await readFile19(join40(localAppData, rel), "utf8").catch(() => "");
|
|
43837
44114
|
if (new RegExp(`"source"\\s*:\\s*"${PROFILE}"`).test(text7)) return true;
|
|
43838
44115
|
}
|
|
43839
44116
|
return false;
|
|
43840
44117
|
}
|
|
43841
44118
|
async function writeIfChanged2(path3, content3) {
|
|
43842
|
-
const current2 = await
|
|
44119
|
+
const current2 = await readFile19(path3).catch(() => null);
|
|
43843
44120
|
if (current2 && current2.equals(Buffer.from(content3))) return false;
|
|
43844
44121
|
await writeFile18(path3, content3);
|
|
43845
44122
|
return true;
|
|
@@ -43851,9 +44128,9 @@ async function openInLedgeTab(o) {
|
|
|
43851
44128
|
await writeIfChanged2(o.launcher, launcherScript(o.node, o.script, o.ledgeHome));
|
|
43852
44129
|
const dir = fragmentDir(o.localAppData.linux);
|
|
43853
44130
|
await mkdir14(dir, { recursive: true });
|
|
43854
|
-
await writeIfChanged2(
|
|
44131
|
+
await writeIfChanged2(join40(dir, "ledge.ico"), await readFile19(o.icon ?? ICON));
|
|
43855
44132
|
const iconWin = `${o.localAppData.win}\\Microsoft\\Windows Terminal\\Fragments\\${PROFILE}\\ledge.ico`;
|
|
43856
|
-
await writeIfChanged2(
|
|
44133
|
+
await writeIfChanged2(join40(dir, "ledge.json"), fragment(commandline, iconWin));
|
|
43857
44134
|
const deadline = Date.now() + (o.waitMs ?? 15e3);
|
|
43858
44135
|
for (let first = true; !await profileLoaded(o.localAppData.linux); first = false) {
|
|
43859
44136
|
if (Date.now() > deadline) return false;
|
|
@@ -43874,11 +44151,11 @@ async function openTuiInLedgeTab(env, onWait) {
|
|
|
43874
44151
|
distro: env.WSL_DISTRO_NAME,
|
|
43875
44152
|
node: await realpath5(process.execPath),
|
|
43876
44153
|
script: await realpath5(process.argv[1]),
|
|
43877
|
-
launcher:
|
|
44154
|
+
launcher: join40(ledgeDir(), "tui.sh"),
|
|
43878
44155
|
ledgeHome: env.LEDGE_HOME,
|
|
43879
44156
|
onWait,
|
|
43880
44157
|
wt: (args) => new Promise((resolve13, reject) => {
|
|
43881
|
-
const child = spawn6(
|
|
44158
|
+
const child = spawn6(join40(linux, "Microsoft", "WindowsApps", "wt.exe"), args, { cwd: "/mnt/c", stdio: "ignore", detached: true });
|
|
43882
44159
|
child.once("error", reject);
|
|
43883
44160
|
child.once("spawn", () => {
|
|
43884
44161
|
child.unref();
|
|
@@ -43902,7 +44179,7 @@ var init_terminalProfile = __esm({
|
|
|
43902
44179
|
"Packages/Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe/LocalState/settings.json",
|
|
43903
44180
|
"Microsoft/Windows Terminal/settings.json"
|
|
43904
44181
|
];
|
|
43905
|
-
fragmentDir = (localAppData) =>
|
|
44182
|
+
fragmentDir = (localAppData) => join40(localAppData, "Microsoft", "Windows Terminal", "Fragments", PROFILE);
|
|
43906
44183
|
PROFILE_ID = "{d10fee13-0978-595f-a851-b60ec80f11c9}";
|
|
43907
44184
|
shQuote2 = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
43908
44185
|
run3 = promisify(execFile10);
|