@paradow/ledge 0.19.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{attach-3BKQSEWC.js → attach-IVICSJYB.js} +11 -11
- package/dist/cli/{bridge-APNFBPNE.js → bridge-H3ZPGIUY.js} +2 -2
- package/dist/cli/{chunk-3HCID6NW.js → chunk-24AHC55Y.js} +3 -3
- package/dist/cli/{chunk-3EIRKAX7.js → chunk-2VSEIOGA.js} +4 -4
- package/dist/cli/{chunk-TRTS24PF.js → chunk-35BPMR6P.js} +2 -2
- package/dist/cli/{chunk-43D6NMYH.js → chunk-6IYPRUQG.js} +1 -1
- package/dist/cli/{chunk-ZUYOA55W.js → chunk-AJFC33TH.js} +2 -2
- package/dist/cli/{chunk-LOOOHYZR.js → chunk-ALEZJFJ3.js} +8 -8
- package/dist/cli/{chunk-BVBX222F.js → chunk-EBBAOQ2Z.js} +7 -6
- package/dist/cli/{chunk-WP77O5LC.js → chunk-EKXZ45MQ.js} +1182 -621
- package/dist/cli/{chunk-HP3G2TYJ.js → chunk-EX66KH66.js} +730 -646
- package/dist/cli/{chunk-7ZAA75HG.js → chunk-HOOHS3MX.js} +1 -1
- package/dist/cli/{chunk-FQZ3IX6E.js → chunk-K7UEKSB2.js} +2 -2
- package/dist/cli/{chunk-GXFU4XAX.js → chunk-KACRWFN3.js} +1 -1
- package/dist/cli/chunk-NFXFY5CT.js +6 -0
- package/dist/cli/{chunk-WJ6YMZTT.js → chunk-NLL2EQJ2.js} +2 -2
- package/dist/cli/{chunk-KKNE7BFZ.js → chunk-WRE3PUTV.js} +35 -11
- package/dist/cli/{chunk-WCS24ICX.js → chunk-ZQON4EV7.js} +2 -2
- package/dist/cli/{chunk-Y5DJ5INP.js → chunk-ZZMZDAF6.js} +3 -3
- package/dist/cli/{daemon-YHRAZSRS.js → daemon-5FPZG5R3.js} +87 -25
- package/dist/cli/decide-2ZKSX7O5.js +56 -0
- package/dist/cli/{handover-UXISKYPS.js → handover-AZ35QZRK.js} +5 -5
- package/dist/cli/{hook-5UAARBWU.js → hook-KANGO46Y.js} +21 -14
- package/dist/cli/index.js +23 -16
- package/dist/cli/launch-DEKJ5HI4.js +34 -0
- package/dist/cli/{send-NLVR6PL2.js → send-BFPJBXXH.js} +5 -5
- package/dist/cli/{setup-EEIXRAMU.js → setup-47ODKJBM.js} +4 -4
- package/dist/cli/{status-2OCYHOWZ.js → status-JPF4NZNI.js} +3 -3
- package/dist/cli/{task-AOOWHPMN.js → task-UTRG4KA5.js} +5 -5
- package/dist/cli/{team-TVNSVYWW.js → team-SZJHGA7D.js} +6 -6
- package/dist/cli/{tui-5XPPX4GR.js → tui-GEJHBWP5.js} +817 -367
- package/dist/cli/{uninstall-UUN7LIIT.js → uninstall-QNWRD27D.js} +4 -4
- package/dist/cli/{version-HB3S4IVG.js → version-YUO6SLAF.js} +1 -1
- package/dist/cli/who-NYPVBO64.js +11 -0
- package/package.json +1 -1
- package/dist/cli/chunk-TVIAHOOD.js +0 -6
- package/dist/cli/launch-YQYCDZ7N.js +0 -34
- package/dist/cli/who-52MENZTT.js +0 -11
|
@@ -17,7 +17,7 @@ function ledgeDir() {
|
|
|
17
17
|
}
|
|
18
18
|
function paths() {
|
|
19
19
|
const dir = ledgeDir();
|
|
20
|
-
return { dir, tmuxConf: join(dir, "tmux.conf"), journal: join(dir, "sessions.json"), log: join(dir, "daemon.log"), pid: join(dir, "daemon.pid"), history: join(dir, "history"), mail: join(dir, "mail.json"), tasks: join(dir, "tasks.json"), teams: join(dir, "teams-live.json"), machines: join(dir, "machines.json"), projects: join(dir, "projects.json"), island: join(dir, "island.json"), token: join(dir, "token"), mobile: join(dir, "mobile.json"), mobileSession: join(dir, "mobile-session.json"), mobileKey: join(dir, "mobile-key"), devices: join(dir, "devices.json"), revocations: join(dir, "revocations.json") };
|
|
20
|
+
return { dir, tmuxConf: join(dir, "tmux.conf"), journal: join(dir, "sessions.json"), log: join(dir, "daemon.log"), pid: join(dir, "daemon.pid"), history: join(dir, "history"), mail: join(dir, "mail.json"), tasks: join(dir, "tasks.json"), teams: join(dir, "teams-live.json"), machines: join(dir, "machines.json"), projects: join(dir, "projects.json"), island: join(dir, "island.json"), token: join(dir, "token"), mobile: join(dir, "mobile.json"), mobileSession: join(dir, "mobile-session.json"), mobileKey: join(dir, "mobile-key"), devices: join(dir, "devices.json"), revocations: join(dir, "revocations.json"), attachments: join(dir, "attachments") };
|
|
21
21
|
}
|
|
22
22
|
async function ensureLedgeDir() {
|
|
23
23
|
const p = paths();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
run
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NLL2EQJ2.js";
|
|
4
4
|
import {
|
|
5
5
|
ensureLedgeDir,
|
|
6
6
|
paths
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HOOHS3MX.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/setup.ts
|
|
10
10
|
import { readFile as readFile2, writeFile, mkdir, rename, realpath, rm, stat, lstat, readlink } from "fs/promises";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ledgeTitleRest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-35BPMR6P.js";
|
|
4
4
|
import {
|
|
5
5
|
cleanTopic,
|
|
6
6
|
isArchived,
|
|
7
7
|
sessionTitle
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EX66KH66.js";
|
|
9
9
|
|
|
10
10
|
// src/daemon/seat.ts
|
|
11
11
|
function teammates(team, sessions) {
|
|
@@ -90,14 +90,19 @@ function formatLedgeMessage(m) {
|
|
|
90
90
|
return `${open}${head} \u2026 [message de ${m.text.length} caract\xE8res, ${lineCount(m.text)} lignes : lis-le en entier avec ledge read ${attr(m.id)}]${LEDGE_CLOSE}`;
|
|
91
91
|
}
|
|
92
92
|
function ledgeMessages(text) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
const out = [];
|
|
94
|
+
let rest = text.trimStart();
|
|
95
|
+
let m;
|
|
96
|
+
while (rest && (m = LEDGE_BLOCK.exec(rest))) {
|
|
97
|
+
const attrs = new Map([...m[1].matchAll(ATTR)].map((a) => [a[1], a[2]]));
|
|
98
|
+
const from = attrs.get("from");
|
|
99
|
+
const tool = attrs.get("tool");
|
|
100
|
+
const id = attrs.get("id");
|
|
101
|
+
if (!from) break;
|
|
102
|
+
out.push({ from, ...tool ? { tool } : {}, ...id ? { id } : {}, text: stripNote(m[2]).text.trim() });
|
|
103
|
+
rest = rest.slice(m[0].length).trimStart();
|
|
104
|
+
}
|
|
105
|
+
return out.length ? out : void 0;
|
|
101
106
|
}
|
|
102
107
|
var NOTICE_BLOCK = /^<ledge-notice\b([^>]*)>([\s\S]*?)(?:<\/ledge-notice>|$)/;
|
|
103
108
|
var NOTICE_QUOTE = 80;
|
|
@@ -609,6 +614,23 @@ function resolveTarget(to, sessions, peers) {
|
|
|
609
614
|
return address ? { outcome: "native", target: t, address } : { outcome: "refused", reason: `${t.name} n'est pas joignable` };
|
|
610
615
|
}
|
|
611
616
|
|
|
617
|
+
// src/attachmentText.ts
|
|
618
|
+
var imageBracket = (path) => `[Image attached: ${path}]`;
|
|
619
|
+
var withImages = (text, paths) => [text, ...paths.map(imageBracket)].join(" ").trim();
|
|
620
|
+
var BRACKET = /[ \t]*\[Image attached: ([^\]\n]*)\]/g;
|
|
621
|
+
function takeImages(text, dir) {
|
|
622
|
+
const prefix = dir.replace(/\/+$/, "") + "/";
|
|
623
|
+
const ids = [];
|
|
624
|
+
const rest = text.replace(BRACKET, (whole, path) => {
|
|
625
|
+
if (!path.startsWith(prefix)) return whole;
|
|
626
|
+
const m = /^([0-9a-f]{64})\.(?:webp|jpg|png|gif)$/.exec(path.slice(prefix.length));
|
|
627
|
+
if (!m) return whole;
|
|
628
|
+
ids.push(m[1]);
|
|
629
|
+
return "";
|
|
630
|
+
});
|
|
631
|
+
return { text: rest.trim(), ids };
|
|
632
|
+
}
|
|
633
|
+
|
|
612
634
|
export {
|
|
613
635
|
teammates,
|
|
614
636
|
seatContext,
|
|
@@ -647,5 +669,7 @@ export {
|
|
|
647
669
|
readPeers,
|
|
648
670
|
bareName,
|
|
649
671
|
ledgePeer,
|
|
650
|
-
resolveTarget
|
|
672
|
+
resolveTarget,
|
|
673
|
+
withImages,
|
|
674
|
+
takeImages
|
|
651
675
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CODEX_HOOK_VAR
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-35BPMR6P.js";
|
|
4
4
|
import {
|
|
5
5
|
connect
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KACRWFN3.js";
|
|
7
7
|
import {
|
|
8
8
|
BRIEF_MAX
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EX66KH66.js";
|
|
10
10
|
|
|
11
11
|
// src/cli/handover.ts
|
|
12
12
|
import { randomUUID } from "crypto";
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AttachmentStore,
|
|
2
3
|
fileJournal,
|
|
3
4
|
loginShellEnv,
|
|
5
|
+
quote,
|
|
4
6
|
reapOwner,
|
|
5
7
|
rpOf,
|
|
6
8
|
startPoller,
|
|
7
9
|
startServer,
|
|
8
10
|
tasksJournal,
|
|
9
11
|
teamsJournal
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-EKXZ45MQ.js";
|
|
13
|
+
import "./chunk-2VSEIOGA.js";
|
|
12
14
|
import "./chunk-OLLQBK6N.js";
|
|
13
15
|
import {
|
|
14
16
|
QUESTION_TOOLS,
|
|
@@ -24,11 +26,11 @@ import {
|
|
|
24
26
|
readPeers,
|
|
25
27
|
reduce,
|
|
26
28
|
stripNote
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
+
} from "./chunk-WRE3PUTV.js";
|
|
30
|
+
import "./chunk-24AHC55Y.js";
|
|
29
31
|
import {
|
|
30
32
|
agentMessages
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-35BPMR6P.js";
|
|
32
34
|
import {
|
|
33
35
|
DEFAULT_RELAY_URL,
|
|
34
36
|
DevicePollResponseSchema,
|
|
@@ -42,26 +44,26 @@ import {
|
|
|
42
44
|
SealedFrameSchema,
|
|
43
45
|
SessionSchema,
|
|
44
46
|
backendOf
|
|
45
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-EX66KH66.js";
|
|
46
48
|
import {
|
|
47
49
|
LEDGE_VERSION
|
|
48
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-NFXFY5CT.js";
|
|
49
51
|
import {
|
|
50
52
|
SERVICE,
|
|
51
53
|
inDaemonService,
|
|
52
54
|
tmuxServerAtRisk
|
|
53
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-K7UEKSB2.js";
|
|
54
56
|
import {
|
|
55
57
|
realTmux,
|
|
56
58
|
runFile
|
|
57
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-NLL2EQJ2.js";
|
|
58
60
|
import {
|
|
59
61
|
log
|
|
60
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-6IYPRUQG.js";
|
|
61
63
|
import {
|
|
62
64
|
ensureLedgeDir,
|
|
63
65
|
paths
|
|
64
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-HOOHS3MX.js";
|
|
65
67
|
|
|
66
68
|
// src/daemon/index.ts
|
|
67
69
|
import { writeFile as writeFile3, rm as rm2 } from "fs/promises";
|
|
@@ -367,9 +369,12 @@ var History = class {
|
|
|
367
369
|
dir;
|
|
368
370
|
/** The Ledge session a SendMessage address or a sender's name is, when it is one (peers.ts). */
|
|
369
371
|
peerOf;
|
|
372
|
+
/** The stored image an attachment id is, when the store still holds it. */
|
|
373
|
+
refOf;
|
|
370
374
|
constructor(opts = {}) {
|
|
371
375
|
this.dir = opts.dir ?? paths().history;
|
|
372
376
|
this.peerOf = opts.peerOf ?? (() => void 0);
|
|
377
|
+
this.refOf = opts.refOf ?? (() => null);
|
|
373
378
|
}
|
|
374
379
|
items(id) {
|
|
375
380
|
return this.threads.get(id) ?? [];
|
|
@@ -425,6 +430,35 @@ var History = class {
|
|
|
425
430
|
if (lines > items.length || lost) this.compact(id, items);
|
|
426
431
|
}
|
|
427
432
|
}
|
|
433
|
+
/** The ids of the images the journaled prompts refer to, read from every `<dir>/*.jsonl` once the pending writes landed. */
|
|
434
|
+
async attachmentIds() {
|
|
435
|
+
await this.writes;
|
|
436
|
+
const ids = /* @__PURE__ */ new Set();
|
|
437
|
+
let names;
|
|
438
|
+
try {
|
|
439
|
+
names = await readdir(this.dir);
|
|
440
|
+
} catch {
|
|
441
|
+
return ids;
|
|
442
|
+
}
|
|
443
|
+
for (const name of names) {
|
|
444
|
+
if (!name.endsWith(".jsonl")) continue;
|
|
445
|
+
let text;
|
|
446
|
+
try {
|
|
447
|
+
text = await readFile2(join(this.dir, name), "utf8");
|
|
448
|
+
} catch (e) {
|
|
449
|
+
log(`history not read for ${name}: ${e.message}`);
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
for (const line of text.split("\n")) {
|
|
453
|
+
if (!line.includes('"images"')) continue;
|
|
454
|
+
try {
|
|
455
|
+
for (const img of JSON.parse(line).images ?? []) if (typeof img?.id === "string") ids.add(img.id);
|
|
456
|
+
} catch {
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return ids;
|
|
461
|
+
}
|
|
428
462
|
/** The ids of the threads held, loaded or recorded. */
|
|
429
463
|
ids() {
|
|
430
464
|
return [...this.threads.keys()];
|
|
@@ -443,25 +477,27 @@ var History = class {
|
|
|
443
477
|
}
|
|
444
478
|
switch (ev.name) {
|
|
445
479
|
case "UserPromptSubmit": {
|
|
446
|
-
|
|
447
|
-
|
|
480
|
+
const images = (ev.attachments ?? []).flatMap((a) => this.refOf(a) ?? []);
|
|
481
|
+
if (!ev.text && images.length === 0) return void 0;
|
|
482
|
+
const text = ev.text ?? "";
|
|
483
|
+
const back = handBack(text);
|
|
448
484
|
if (back) {
|
|
449
485
|
const helper = this.items(id).find((i) => i.id === back.helperId);
|
|
450
486
|
if (helper?.kind === "helper" && helper.state !== "exited") this.put(id, { ...helper, state: "exited" });
|
|
451
487
|
if (helper?.kind === "helper") this.settle(id, (i) => i.helperId === back.helperId);
|
|
452
488
|
return back.report ? this.put(id, { kind: "reply", id: `report-${back.helperId}`, at: ev.at, turn: helper?.turn ?? turn, helperId: back.helperId, text: back.report }) : void 0;
|
|
453
489
|
}
|
|
454
|
-
const messages = crossSession(
|
|
490
|
+
const messages = crossSession(text);
|
|
455
491
|
if (messages) {
|
|
456
492
|
this.turns.set(id, turn + 1);
|
|
457
493
|
let last;
|
|
458
494
|
messages.forEach((m, i) => {
|
|
459
|
-
const { sender, text } = stripNote(m.text);
|
|
460
|
-
last = this.receive(id, { kind: "received", id: `recv-${turn + 1}-${i}`, at: ev.at, turn: turn + 1, from: sender ?? m.name ?? m.from, text }, { ...m, ...sender ? { sender } : {} });
|
|
495
|
+
const { sender, text: text2 } = stripNote(m.text);
|
|
496
|
+
last = this.receive(id, { kind: "received", id: `recv-${turn + 1}-${i}`, at: ev.at, turn: turn + 1, from: sender ?? m.name ?? m.from, text: text2 }, { ...m, ...sender ? { sender } : {} });
|
|
461
497
|
});
|
|
462
498
|
return last;
|
|
463
499
|
}
|
|
464
|
-
const ledge = ledgeMessages(
|
|
500
|
+
const ledge = ledgeMessages(text);
|
|
465
501
|
if (ledge) {
|
|
466
502
|
this.turns.set(id, turn + 1);
|
|
467
503
|
let last;
|
|
@@ -470,7 +506,7 @@ var History = class {
|
|
|
470
506
|
});
|
|
471
507
|
return last;
|
|
472
508
|
}
|
|
473
|
-
const notices = crossSessionNotices(
|
|
509
|
+
const notices = crossSessionNotices(text);
|
|
474
510
|
if (notices) {
|
|
475
511
|
this.turns.set(id, turn + 1);
|
|
476
512
|
let last;
|
|
@@ -479,7 +515,7 @@ var History = class {
|
|
|
479
515
|
});
|
|
480
516
|
return last;
|
|
481
517
|
}
|
|
482
|
-
const failed = ledgeNotice(
|
|
518
|
+
const failed = ledgeNotice(text);
|
|
483
519
|
if (failed) {
|
|
484
520
|
this.turns.set(id, turn + 1);
|
|
485
521
|
const peer = this.peerOf(failed.to);
|
|
@@ -498,7 +534,7 @@ var History = class {
|
|
|
498
534
|
text: failed.text
|
|
499
535
|
});
|
|
500
536
|
}
|
|
501
|
-
const task = ledgeTask(
|
|
537
|
+
const task = ledgeTask(text);
|
|
502
538
|
if (task) {
|
|
503
539
|
this.turns.set(id, turn + 1);
|
|
504
540
|
const peer = task.from ? this.peerOf(task.from) : void 0;
|
|
@@ -515,13 +551,13 @@ var History = class {
|
|
|
515
551
|
text: task.text
|
|
516
552
|
});
|
|
517
553
|
}
|
|
518
|
-
const joined = ledgeTeamNotice(
|
|
554
|
+
const joined = ledgeTeamNotice(text);
|
|
519
555
|
if (joined) {
|
|
520
556
|
this.turns.set(id, turn + 1);
|
|
521
557
|
return this.put(id, { kind: "notice", id: `notice-${turn + 1}-0`, at: ev.at, turn: turn + 1, notice: "other", team: joined.team, summary: joined.text.replaceAll(" \u23CE ", "\n"), text: joined.text });
|
|
522
558
|
}
|
|
523
559
|
this.turns.set(id, turn + 1);
|
|
524
|
-
return this.put(id, { kind: "prompt", id: `prompt-${turn + 1}`, at: ev.at, turn: turn + 1, text
|
|
560
|
+
return this.put(id, { kind: "prompt", id: `prompt-${turn + 1}`, at: ev.at, turn: turn + 1, text, ...images.length ? { images } : {} });
|
|
525
561
|
}
|
|
526
562
|
case "PreToolUse": {
|
|
527
563
|
if (!ev.tool) return void 0;
|
|
@@ -604,7 +640,7 @@ var History = class {
|
|
|
604
640
|
if (!opts.force && now - (this.synced.get(key) ?? 0) < SYNC_MS) return [];
|
|
605
641
|
this.synced.set(key, now);
|
|
606
642
|
const items = this.items(id);
|
|
607
|
-
const since = opts.helperId ? items.find((i) => i.id === opts.helperId)?.at : [...items].reverse().find((i) => i.kind === "prompt" || i.kind === "received" || i.kind === "notice")?.at;
|
|
643
|
+
const since = opts.helperId ? items.find((i) => i.id === opts.helperId)?.at : [...items].reverse().find((i) => i.kind === "prompt" || i.kind === "received" || i.kind === "notice" && !i.outgoing)?.at;
|
|
608
644
|
if (!since) return [];
|
|
609
645
|
const have = new Set(items.map((i) => i.id));
|
|
610
646
|
const turn = this.turns.get(id) ?? 0;
|
|
@@ -622,6 +658,30 @@ var History = class {
|
|
|
622
658
|
if (existing) return this.put(senderId, { ...existing, ...m.peer ? { peer: m.peer } : {}, via: "ledge" });
|
|
623
659
|
return this.put(senderId, { kind: "sent", id: m.rid, at: m.at, turn: this.turns.get(senderId) ?? 0, to: m.to, ...m.peer ? { peer: m.peer } : {}, ...m.summary ? { summary: m.summary } : {}, text: m.text, status: "sending", via: "ledge" });
|
|
624
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* A task the session handed over (issue #92): its card in the sender's thread, in the turn it is in (not a prompt).
|
|
663
|
+
* One card per transmission: the same one again replaces it.
|
|
664
|
+
*/
|
|
665
|
+
recordTask(senderId, n) {
|
|
666
|
+
const { task, tr } = n;
|
|
667
|
+
const what = { give: "confi\xE9e \xE0", pass: "pass\xE9e \xE0", done: "rendue \xE0", refuse: "refus\xE9e, rendue \xE0", cancel: "annul\xE9e pour" }[tr.op];
|
|
668
|
+
const said = tr.op === "pass" ? tr.note : task.result;
|
|
669
|
+
return this.put(senderId, {
|
|
670
|
+
kind: "notice",
|
|
671
|
+
id: `task-${task.id}-${tr.index}`,
|
|
672
|
+
at: tr.at,
|
|
673
|
+
turn: this.turns.get(senderId) ?? 0,
|
|
674
|
+
notice: "other",
|
|
675
|
+
task: task.id,
|
|
676
|
+
taskOp: tr.op,
|
|
677
|
+
outgoing: true,
|
|
678
|
+
name: tr.toName,
|
|
679
|
+
...n.peer ? { peer: n.peer } : {},
|
|
680
|
+
summary: said ? `${task.title}
|
|
681
|
+
${quote(said)}` : task.title,
|
|
682
|
+
text: `T\xE2che \xAB ${task.title} \xBB ${what} ${tr.toName}${tr.op === "done" ? " (termin\xE9e)" : ""}`
|
|
683
|
+
});
|
|
684
|
+
}
|
|
625
685
|
/** The mailbox's outcome for a card; a `read` card stays read. */
|
|
626
686
|
markSent(senderId, rid, status) {
|
|
627
687
|
const sent = this.items(senderId).find((i) => i.kind === "sent" && i.id === rid);
|
|
@@ -2188,7 +2248,9 @@ async function startDaemon(opts = {}) {
|
|
|
2188
2248
|
const daemon = await daemonInfo();
|
|
2189
2249
|
let ompLive = () => 0;
|
|
2190
2250
|
const updater = createDaemonUpdater(realUpdaterDeps({ info: daemon, save: () => store.save(), ownedLive: () => ompLive() }));
|
|
2191
|
-
const
|
|
2251
|
+
const attachments = new AttachmentStore(paths().attachments);
|
|
2252
|
+
await attachments.load().catch((e) => log(`attachments not loaded: ${e.message}`));
|
|
2253
|
+
const history = new History({ peerOf: (t) => ledgePeer(t, readPeers(), store.all())?.id, refOf: (id) => attachments.ref(id) });
|
|
2192
2254
|
try {
|
|
2193
2255
|
await history.load();
|
|
2194
2256
|
} catch (e) {
|
|
@@ -2208,7 +2270,7 @@ async function startDaemon(opts = {}) {
|
|
|
2208
2270
|
const mail = fileJournal(paths().mail);
|
|
2209
2271
|
const taskJournal = tasksJournal(paths().tasks);
|
|
2210
2272
|
const teamJournal = teamsJournal(paths().teams);
|
|
2211
|
-
const server = await startServer({ store, tmux, port: opts.port, daemon, updater, history, mobile, mobileUnavailable, mail, tasks: taskJournal, teams: teamJournal });
|
|
2273
|
+
const server = await startServer({ store, tmux, port: opts.port, daemon, updater, history, mobile, mobileUnavailable, mail, tasks: taskJournal, teams: teamJournal, attachments });
|
|
2212
2274
|
ompLive = () => server.omp.liveCount();
|
|
2213
2275
|
const poller = startPoller({ store, tmux, broadcastPreview: server.preview, labelExited: server.labelExited });
|
|
2214
2276
|
await writeFile3(paths().pid, String(process.pid));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CODEX_HOOK_VAR
|
|
3
|
+
} from "./chunk-35BPMR6P.js";
|
|
4
|
+
import {
|
|
5
|
+
connect
|
|
6
|
+
} from "./chunk-KACRWFN3.js";
|
|
7
|
+
import {
|
|
8
|
+
LEDGE_GIVER,
|
|
9
|
+
TASK_TEXT_MAX
|
|
10
|
+
} from "./chunk-EX66KH66.js";
|
|
11
|
+
import "./chunk-HOOHS3MX.js";
|
|
12
|
+
|
|
13
|
+
// src/cli/decide.ts
|
|
14
|
+
import { randomUUID } from "crypto";
|
|
15
|
+
var DECIDE_USAGE = `ledge decide les d\xE9cisions que les sessions attendent de toi
|
|
16
|
+
ledge decide <id> "<r\xE9ponse>" y r\xE9pondre : la session qui l'a demand\xE9e reprend`;
|
|
17
|
+
var ID = /^t[0-9a-f]{6}$/;
|
|
18
|
+
var DECIDE_MS = 4e3;
|
|
19
|
+
function decideArgs(args) {
|
|
20
|
+
if (!args.length) return { op: "list" };
|
|
21
|
+
const [id, text] = args;
|
|
22
|
+
return args.length === 2 && ID.test(id) && text.trim() && text.length <= TASK_TEXT_MAX ? { op: "done", task: id, text } : void 0;
|
|
23
|
+
}
|
|
24
|
+
async function runDecide(args, opts = {}) {
|
|
25
|
+
const op = decideArgs(args);
|
|
26
|
+
if (!op) return { line: DECIDE_USAGE, code: 1 };
|
|
27
|
+
const env = opts.env ?? process.env;
|
|
28
|
+
if (env.LEDGE_SESSION || env[CODEX_HOOK_VAR]) return { line: "refus\xE9 : ledge decide est la r\xE9ponse de l'utilisateur, pas celle d'une session", code: 1 };
|
|
29
|
+
let client;
|
|
30
|
+
try {
|
|
31
|
+
client = await connect({ port: opts.port, timeoutMs: DECIDE_MS });
|
|
32
|
+
} catch {
|
|
33
|
+
return { line: "daemon not running (start a session with `ledge claude`, or run `ledge daemon`)", code: 1 };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
if (op.op === "list") {
|
|
37
|
+
client.send({ type: "task.cmd", rid: randomUUID(), by: LEDGE_GIVER, op: "list" });
|
|
38
|
+
const asked = ((await client.next("task.result", DECIDE_MS)).tasks ?? []).filter((t) => t.owner === LEDGE_GIVER);
|
|
39
|
+
if (!asked.length) return { line: "aucune d\xE9cision en attente", code: 0 };
|
|
40
|
+
return { line: asked.map((t) => [`${t.id} de ${t.giverName} ${t.title}`, ...t.text ? t.text.split("\n").map((l) => ` ${l}`) : []].join("\n")).join("\n\n"), code: 0 };
|
|
41
|
+
}
|
|
42
|
+
client.send({ type: "task.cmd", rid: randomUUID(), by: LEDGE_GIVER, op: "done", task: op.task, text: op.text });
|
|
43
|
+
const r = await client.next("task.result", DECIDE_MS);
|
|
44
|
+
if (r.reason !== void 0) return { line: `refus\xE9 : ${r.reason}`, code: 1 };
|
|
45
|
+
return { line: `r\xE9ponse envoy\xE9e \xE0 ${r.task.giverName}`, code: 0 };
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return { line: `pas de r\xE9ponse de Ledge : ${e.message}`, code: 1 };
|
|
48
|
+
} finally {
|
|
49
|
+
await client.close();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
DECIDE_USAGE,
|
|
54
|
+
decideArgs,
|
|
55
|
+
runDecide
|
|
56
|
+
};
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
handoverArgs,
|
|
4
4
|
handoverOnClient,
|
|
5
5
|
runHandover
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-ZZMZDAF6.js";
|
|
7
|
+
import "./chunk-35BPMR6P.js";
|
|
8
|
+
import "./chunk-KACRWFN3.js";
|
|
9
|
+
import "./chunk-EX66KH66.js";
|
|
10
|
+
import "./chunk-HOOHS3MX.js";
|
|
11
11
|
export {
|
|
12
12
|
HANDOVER_USAGE,
|
|
13
13
|
handoverArgs,
|
|
@@ -6,41 +6,44 @@ import {
|
|
|
6
6
|
resolveRoleAddress,
|
|
7
7
|
resolveTarget,
|
|
8
8
|
seatContext,
|
|
9
|
+
takeImages,
|
|
9
10
|
teammates
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-WRE3PUTV.js";
|
|
11
12
|
import {
|
|
12
13
|
findRole
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-24AHC55Y.js";
|
|
14
15
|
import {
|
|
15
16
|
parseLedgeCommand,
|
|
16
17
|
readOnClient,
|
|
17
18
|
sendOnClient
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-AJFC33TH.js";
|
|
19
20
|
import {
|
|
20
21
|
taskOnClient
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-EBBAOQ2Z.js";
|
|
22
23
|
import {
|
|
23
24
|
handoverOnClient
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-ZZMZDAF6.js";
|
|
25
26
|
import {
|
|
26
27
|
CODEX_ENV_VAR,
|
|
27
28
|
CODEX_HOOK_VAR,
|
|
28
29
|
codexPlan
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-35BPMR6P.js";
|
|
30
31
|
import {
|
|
31
32
|
formatWho
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-ZQON4EV7.js";
|
|
33
34
|
import {
|
|
34
35
|
connect,
|
|
35
36
|
sendMessageAndAwaitAck
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-KACRWFN3.js";
|
|
37
38
|
import {
|
|
38
39
|
taskClosed
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-EX66KH66.js";
|
|
40
41
|
import {
|
|
41
42
|
log
|
|
42
|
-
} from "./chunk-
|
|
43
|
-
import
|
|
43
|
+
} from "./chunk-6IYPRUQG.js";
|
|
44
|
+
import {
|
|
45
|
+
paths
|
|
46
|
+
} from "./chunk-HOOHS3MX.js";
|
|
44
47
|
|
|
45
48
|
// src/cli/hook.ts
|
|
46
49
|
import { randomUUID } from "crypto";
|
|
@@ -50,8 +53,12 @@ var str = (v) => typeof v === "string" ? v : void 0;
|
|
|
50
53
|
var PROMPT_MAX = 500;
|
|
51
54
|
var fromAgent = (t) => t.startsWith('<agent-message from="') || t.startsWith("<cross-session-message ") || t.startsWith("[Cross-session ");
|
|
52
55
|
var promptText = (p) => {
|
|
53
|
-
const
|
|
54
|
-
|
|
56
|
+
const raw = str(p.prompt)?.trim();
|
|
57
|
+
if (!raw) return {};
|
|
58
|
+
const taken = takeImages(raw, paths().attachments);
|
|
59
|
+
const ids = taken.ids;
|
|
60
|
+
const t = ids.length ? taken.text : raw;
|
|
61
|
+
return { ...t ? { text: t.slice(0, fromAgent(t) ? INPUT_MAX : PROMPT_MAX) } : {}, ...ids.length ? { attachments: ids } : {} };
|
|
55
62
|
};
|
|
56
63
|
function describeTool(tool, input) {
|
|
57
64
|
const i = input && typeof input === "object" ? input : {};
|
|
@@ -348,7 +355,7 @@ function identityContext(s) {
|
|
|
348
355
|
"Pour voir les autres sessions (nom, outil, \xE9tat, projet, branche, sujet), lance `ledge who`.",
|
|
349
356
|
s.tool === "claude" ? "Pour \xE9crire \xE0 une autre session Ledge, Claude ou Codex, utilise son nom Ledge (donn\xE9 par `ledge who`) comme adresse SendMessage : Ledge le transmet. `ListAgents` montre les noms internes de Claude, pas les noms Ledge." : "Pour \xE9crire \xE0 une autre session Ledge, lance `ledge send <nom> \"<message>\"` (seul, sans && ni |). Ledge ex\xE9cute lui-m\xEAme `ledge send`, `ledge read`, `ledge task` et `ledge who` : leur r\xE9sultat t'arrive comme \xAB Command blocked by PreToolUse hook: \u2026 \xBB, c'est la r\xE9ponse, pas une erreur.",
|
|
350
357
|
"Un long message d'une autre session t'arrive en aper\xE7u avec son id : lance `ledge read <id>` pour le lire en entier. Une `<ledge-notice>` te dit qu'un de tes messages n'a pas pu \xEAtre remis.",
|
|
351
|
-
'Un message sert \xE0 pr\xE9venir ; pour confier un travail qui ne doit pas se perdre, lance plut\xF4t `ledge task give <nom> "<titre>" "<d\xE9tail>"` (`ledge task` pour le reste). Une `<ledge-task>` t\'en confie une, ou te dit comment une des tiennes a fini : quand on t\'en confie une, prends-la (`ledge task take <id>`) et termine-la toujours (`ledge task done <id> "<r\xE9sultat>"`, ou `refuse`).',
|
|
358
|
+
'Un message sert \xE0 pr\xE9venir ; pour confier un travail qui ne doit pas se perdre, lance plut\xF4t `ledge task give <nom> "<titre>" "<d\xE9tail>"` (`ledge task` pour le reste). Une `<ledge-task>` t\'en confie une, ou te dit comment une des tiennes a fini : quand on t\'en confie une, prends-la (`ledge task take <id>`) et termine-la toujours (`ledge task done <id> "<r\xE9sultat>"`, ou `refuse`). Une d\xE9cision qui revient \xE0 l\'utilisateur se pose avec `ledge task give ledge "<question>" "<options, ta recommandation>"` : sa r\xE9ponse te r\xE9veille, inutile d\'attendre la fin pour la poser.',
|
|
352
359
|
...s.seat ? [s.seat] : [],
|
|
353
360
|
...s.relieves ? [`Tu as pris la rel\xE8ve de ${s.relieves.name}, dont le contexte \xE9tait plein : relis son bilan avec \`ledge handover show\`.`] : [],
|
|
354
361
|
...s.tasks ? [tasksContext(s.tasks) ?? ""].filter(Boolean) : []
|