@paradow/ledge 0.10.0 → 0.12.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-2DEXQEC2.js → attach-UWADG6NX.js} +9 -9
- package/dist/cli/{bridge-ZOHP53DV.js → bridge-53ZTDSST.js} +1 -1
- package/dist/cli/chunk-A7YEHYLY.js +105 -0
- package/dist/cli/{who-WVYFPCII.js → chunk-FRGNPUDO.js} +3 -3
- package/dist/cli/chunk-HJTBQQIQ.js +6 -0
- package/dist/cli/{chunk-OHKQKXYM.js → chunk-QAEH5TJB.js} +73 -2
- package/dist/cli/{chunk-JOCNCNRP.js → chunk-VY45MACP.js} +394 -338
- package/dist/cli/{chunk-GMKS55KF.js → chunk-X34LPKG7.js} +16 -3
- package/dist/cli/{chunk-Q7RCYJ4X.js → chunk-XIO4OIHR.js} +1 -1
- package/dist/cli/{chunk-TC3XJUJA.js → chunk-XXFUYME7.js} +9 -1
- package/dist/cli/{chunk-TO4XO2ML.js → chunk-ZEHTNFPV.js} +4 -3
- package/dist/cli/{chunk-IC5RHOX6.js → chunk-ZNRXLDSH.js} +9 -9
- package/dist/cli/{daemon-RI47DJDX.js → daemon-Z7Z2R35O.js} +326 -91
- package/dist/cli/{hook-W46IWB7I.js → hook-OLZ2I4GM.js} +49 -8
- package/dist/cli/index.js +19 -12
- package/dist/cli/{launch-S6XFRSZA.js → launch-ZGICGFVU.js} +5 -5
- package/dist/cli/send-VV25P46X.js +14 -0
- package/dist/cli/{setup-7AEH5DC3.js → setup-TULNBDFB.js} +2 -2
- package/dist/cli/{status-QOXWNLLF.js → status-LLITXNOW.js} +2 -2
- package/dist/cli/{uninstall-7U7ENKOS.js → uninstall-OFSLCP4T.js} +2 -2
- package/dist/cli/{version-SO5OMPGD.js → version-XX2MWLAL.js} +1 -1
- package/dist/cli/who-K6VK7EXV.js +11 -0
- package/package.json +1 -1
- package/dist/cli/chunk-XOPH7YDV.js +0 -6
|
@@ -1,19 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseLedgeCommand,
|
|
3
|
+
sendOnClient
|
|
4
|
+
} from "./chunk-A7YEHYLY.js";
|
|
5
|
+
import {
|
|
6
|
+
formatWho
|
|
7
|
+
} from "./chunk-FRGNPUDO.js";
|
|
8
|
+
import {
|
|
9
|
+
connect,
|
|
10
|
+
sendMessageAndAwaitAck
|
|
11
|
+
} from "./chunk-XXFUYME7.js";
|
|
1
12
|
import {
|
|
2
13
|
QUESTION_TOOLS,
|
|
14
|
+
bareName,
|
|
3
15
|
gitInfo
|
|
4
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QAEH5TJB.js";
|
|
5
17
|
import {
|
|
6
18
|
CODEX_ENV_VAR,
|
|
7
19
|
CODEX_HOOK_VAR,
|
|
8
20
|
codexPlan
|
|
9
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-X34LPKG7.js";
|
|
22
|
+
import {
|
|
23
|
+
MESSAGE_MAX
|
|
24
|
+
} from "./chunk-VY45MACP.js";
|
|
10
25
|
import {
|
|
11
26
|
log
|
|
12
27
|
} from "./chunk-YUSY3E47.js";
|
|
13
|
-
import {
|
|
14
|
-
connect
|
|
15
|
-
} from "./chunk-TC3XJUJA.js";
|
|
16
|
-
import "./chunk-JOCNCNRP.js";
|
|
17
28
|
import "./chunk-FGOFRWIB.js";
|
|
18
29
|
|
|
19
30
|
// src/cli/hook.ts
|
|
@@ -307,7 +318,7 @@ function identityContext(s) {
|
|
|
307
318
|
return [
|
|
308
319
|
`Tu es ${s.name}, ${where} : une session lanc\xE9e par Ledge (${s.tool}). Les autres sessions Ledge te connaissent sous le nom ${s.name}.`,
|
|
309
320
|
"Pour voir les autres sessions (nom, outil, \xE9tat, projet, branche, sujet), lance `ledge who`.",
|
|
310
|
-
|
|
321
|
+
s.tool === "claude" ? "Pour \xE9crire \xE0 une autre session Ledge, Claude ou Codex, utilise son nom Ledge comme adresse SendMessage." : "Pour \xE9crire \xE0 une autre session Ledge, lance `ledge send <nom> \"<message>\"` (seul, sans && ni |). Ledge ex\xE9cute lui-m\xEAme `ledge send` 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."
|
|
311
322
|
].join("\n");
|
|
312
323
|
}
|
|
313
324
|
async function identity(agent, cwd, known, deadline) {
|
|
@@ -325,6 +336,29 @@ async function identity(agent, cwd, known, deadline) {
|
|
|
325
336
|
...known?.worktree ?? git?.worktree ? { worktree: true } : {}
|
|
326
337
|
};
|
|
327
338
|
}
|
|
339
|
+
var SEND_MESSAGE_MS = 1500;
|
|
340
|
+
async function relayMessage(client, from, toolUseId, input, deadline) {
|
|
341
|
+
if (!toolUseId) return void 0;
|
|
342
|
+
const left = () => Math.max(0, deadline - Date.now());
|
|
343
|
+
const to = input.to;
|
|
344
|
+
const snapshot = await client.next("snapshot", left());
|
|
345
|
+
const tool = snapshot.sessions.find((s) => s.name === bareName(to))?.tool;
|
|
346
|
+
if (tool !== "codex" && input.message.length > MESSAGE_MAX) return void 0;
|
|
347
|
+
const summary = str(input.summary);
|
|
348
|
+
const ack = await sendMessageAndAwaitAck(client, { type: "session.message", rid: toolUseId, from, to, text: input.message, ...summary ? { summary } : {}, intercept: true }, left());
|
|
349
|
+
const target = tool ? `${to} (${tool})` : to;
|
|
350
|
+
const reason = ack.outcome === "accepted" ? `Message transmis par Ledge \xE0 ${target} : il le re\xE7oit maintenant.` : ack.outcome === "queued" ? `Message transmis par Ledge \xE0 ${target} : il le recevra d\xE8s qu'il sera libre.` : ack.outcome === "refused" ? `Ledge n'a pas pu transmettre le message \xE0 ${to} : ${ack.reason ?? "raison inconnue"}` : void 0;
|
|
351
|
+
return reason ? JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: reason } }) : void 0;
|
|
352
|
+
}
|
|
353
|
+
async function runLedgeCommand(client, cmd, from, deadline) {
|
|
354
|
+
const left = () => Math.max(0, deadline - Date.now());
|
|
355
|
+
let line;
|
|
356
|
+
if (cmd.cmd === "who") line = formatWho((await client.next("snapshot", left())).sessions, from);
|
|
357
|
+
else {
|
|
358
|
+
line = (await sendOnClient(client, cmd.args, from, left())).line;
|
|
359
|
+
}
|
|
360
|
+
return JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: line } });
|
|
361
|
+
}
|
|
328
362
|
async function runHook(eventName, stdin, opts = {}) {
|
|
329
363
|
const agent = opts.tool ?? "claude";
|
|
330
364
|
const label = agent === "claude" ? eventName : `${agent} ${eventName}`;
|
|
@@ -336,6 +370,7 @@ async function runHook(eventName, stdin, opts = {}) {
|
|
|
336
370
|
let identify = false;
|
|
337
371
|
let known;
|
|
338
372
|
let deadline = Date.now() + (opts.timeoutMs ?? 100);
|
|
373
|
+
let relayed;
|
|
339
374
|
try {
|
|
340
375
|
const payload = JSON.parse(stdin || "{}");
|
|
341
376
|
mapped = agent === "cursor" ? mapCursorHook(eventName, payload, (/* @__PURE__ */ new Date()).toISOString()) : mapHook(agent, eventName, payload, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -345,15 +380,21 @@ async function runHook(eventName, stdin, opts = {}) {
|
|
|
345
380
|
}
|
|
346
381
|
const launchedId = agent === "codex" ? codexLedgeId() : agent === "claude" ? process.env.LEDGE_SESSION : void 0;
|
|
347
382
|
identify = eventName === "SessionStart" && !!launchedId && mapped.id === launchedId;
|
|
348
|
-
const
|
|
383
|
+
const input = payload.tool_input ?? {};
|
|
384
|
+
const intercept = agent === "claude" && eventName === "PreToolUse" && str(payload.tool_name) === "SendMessage" && typeof input.to === "string" && typeof input.message === "string" && !!input.message;
|
|
385
|
+
const command = agent === "codex" && eventName === "PreToolUse" && str(payload.tool_name) === "Bash" && typeof input.command === "string" ? parseLedgeCommand(input.command) : void 0;
|
|
386
|
+
const timeoutMs = opts.timeoutMs ?? (identify ? 1e3 : intercept || command ? SEND_MESSAGE_MS : 100);
|
|
349
387
|
deadline = Date.now() + timeoutMs;
|
|
350
388
|
const client = await connect({ port: opts.port, timeoutMs });
|
|
351
389
|
client.send({ type: "session.event", id: mapped.id, event: mapped.event, agent: mapped.agent, ...mapped.cwd ? { cwd: mapped.cwd } : {} });
|
|
352
390
|
if (identify) known = (await client.next("snapshot", Math.max(0, deadline - Date.now())).catch(() => void 0))?.sessions.find((s) => s.id === mapped.id);
|
|
391
|
+
if (intercept) relayed = await relayMessage(client, mapped.id, str(payload.tool_use_id), input, deadline);
|
|
392
|
+
if (command) relayed = await runLedgeCommand(client, command, mapped.id, deadline);
|
|
353
393
|
await Promise.race([client.close(), new Promise((r) => setTimeout(r, Math.max(0, deadline - Date.now())))]);
|
|
354
394
|
} catch (e) {
|
|
355
395
|
log(`hook ${label} dropped: ${e.message}`);
|
|
356
396
|
}
|
|
397
|
+
if (relayed) return relayed;
|
|
357
398
|
if (!identify || !mapped) return void 0;
|
|
358
399
|
const who = await identity(agent, mapped.cwd, known, deadline);
|
|
359
400
|
return who ? JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: identityContext(who) } }) : void 0;
|
package/dist/cli/index.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
var USAGE = `ledge <claude|codex|cursor> [--name <bot>] [-- agent args] start an agent in a tracked session
|
|
5
|
-
ledge attach <id>
|
|
5
|
+
ledge attach [--read-only] <id> put this terminal on a running session
|
|
6
6
|
ledge daemon run the daemon in the foreground
|
|
7
7
|
ledge hook [codex|cursor] <Event> receive a hook (reads JSON on stdin)
|
|
8
8
|
ledge setup install hooks and ~/.ledge
|
|
9
9
|
ledge uninstall [--purge] remove hooks, service and link (--purge: ~/.ledge too)
|
|
10
10
|
ledge status list sessions
|
|
11
11
|
ledge who list the live sessions (name, tool, state, project, branch, topic)
|
|
12
|
+
ledge send <nom> "<message>" [--summary <texte>] write to another Ledge session
|
|
12
13
|
ledge bridge exchange Ledge messages over SSH stdio
|
|
13
14
|
ledge --version print the installed version`;
|
|
14
15
|
async function hookMain(args) {
|
|
@@ -17,7 +18,7 @@ async function hookMain(args) {
|
|
|
17
18
|
try {
|
|
18
19
|
const chunks = [];
|
|
19
20
|
for await (const c of process.stdin) chunks.push(c);
|
|
20
|
-
const { runHook } = await import("./hook-
|
|
21
|
+
const { runHook } = await import("./hook-OLZ2I4GM.js");
|
|
21
22
|
const out = await runHook(event, Buffer.concat(chunks).toString("utf8"), { tool });
|
|
22
23
|
if (out) process.stdout.write(`${out}
|
|
23
24
|
`);
|
|
@@ -29,7 +30,7 @@ async function main(argv) {
|
|
|
29
30
|
const [cmd, ...rest] = argv;
|
|
30
31
|
switch (cmd) {
|
|
31
32
|
case "daemon": {
|
|
32
|
-
const { startDaemon } = await import("./daemon-
|
|
33
|
+
const { startDaemon } = await import("./daemon-Z7Z2R35O.js");
|
|
33
34
|
await startDaemon();
|
|
34
35
|
await new Promise(() => {
|
|
35
36
|
});
|
|
@@ -37,45 +38,51 @@ async function main(argv) {
|
|
|
37
38
|
}
|
|
38
39
|
case "--version":
|
|
39
40
|
case "version": {
|
|
40
|
-
const { LEDGE_VERSION } = await import("./version-
|
|
41
|
+
const { LEDGE_VERSION } = await import("./version-XX2MWLAL.js");
|
|
41
42
|
console.log(LEDGE_VERSION);
|
|
42
43
|
return 0;
|
|
43
44
|
}
|
|
44
45
|
case "setup": {
|
|
45
|
-
const { runSetup } = await import("./setup-
|
|
46
|
+
const { runSetup } = await import("./setup-TULNBDFB.js");
|
|
46
47
|
for (const l of await runSetup()) console.log(l);
|
|
47
48
|
return 0;
|
|
48
49
|
}
|
|
49
50
|
case "uninstall": {
|
|
50
|
-
const { runUninstall } = await import("./uninstall-
|
|
51
|
+
const { runUninstall } = await import("./uninstall-OFSLCP4T.js");
|
|
51
52
|
const r = await runUninstall({ purge: rest.includes("--purge") });
|
|
52
53
|
for (const l of r.lines) console.log(l);
|
|
53
54
|
return r.ok ? 0 : 1;
|
|
54
55
|
}
|
|
55
56
|
case "status": {
|
|
56
|
-
const { printStatus } = await import("./status-
|
|
57
|
+
const { printStatus } = await import("./status-LLITXNOW.js");
|
|
57
58
|
console.log(await printStatus());
|
|
58
59
|
return 0;
|
|
59
60
|
}
|
|
60
61
|
case "who": {
|
|
61
|
-
const { printWho } = await import("./who-
|
|
62
|
+
const { printWho } = await import("./who-K6VK7EXV.js");
|
|
62
63
|
console.log(await printWho());
|
|
63
64
|
return 0;
|
|
64
65
|
}
|
|
66
|
+
case "send": {
|
|
67
|
+
const { sendMessage } = await import("./send-VV25P46X.js");
|
|
68
|
+
const r = await sendMessage(rest);
|
|
69
|
+
console.log(r.line);
|
|
70
|
+
return r.code;
|
|
71
|
+
}
|
|
65
72
|
case "bridge": {
|
|
66
|
-
const { bridge } = await import("./bridge-
|
|
73
|
+
const { bridge } = await import("./bridge-53ZTDSST.js");
|
|
67
74
|
await bridge();
|
|
68
75
|
return 0;
|
|
69
76
|
}
|
|
70
77
|
case "claude":
|
|
71
78
|
case "codex":
|
|
72
79
|
case "cursor": {
|
|
73
|
-
const { launch } = await import("./launch-
|
|
80
|
+
const { launch } = await import("./launch-ZGICGFVU.js");
|
|
74
81
|
return launch(cmd, rest);
|
|
75
82
|
}
|
|
76
83
|
case "attach": {
|
|
77
|
-
const { attach } = await import("./attach-
|
|
78
|
-
return attach(rest
|
|
84
|
+
const { attach } = await import("./attach-UWADG6NX.js");
|
|
85
|
+
return attach(rest.find((a) => !a.startsWith("--")) ?? "", { readOnly: rest.includes("--read-only") });
|
|
79
86
|
}
|
|
80
87
|
default:
|
|
81
88
|
console.log(USAGE);
|
|
@@ -5,15 +5,15 @@ import {
|
|
|
5
5
|
ensureDaemon,
|
|
6
6
|
launch,
|
|
7
7
|
parseLaunchArgs
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZNRXLDSH.js";
|
|
9
|
+
import "./chunk-XXFUYME7.js";
|
|
9
10
|
import {
|
|
10
11
|
agentEnv,
|
|
11
12
|
exitFile
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-X34LPKG7.js";
|
|
14
|
+
import "./chunk-VY45MACP.js";
|
|
15
|
+
import "./chunk-ZEHTNFPV.js";
|
|
14
16
|
import "./chunk-YUSY3E47.js";
|
|
15
|
-
import "./chunk-TC3XJUJA.js";
|
|
16
|
-
import "./chunk-JOCNCNRP.js";
|
|
17
17
|
import "./chunk-FGOFRWIB.js";
|
|
18
18
|
export {
|
|
19
19
|
DaemonError,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseLedgeCommand,
|
|
3
|
+
sendMessage,
|
|
4
|
+
sendOnClient
|
|
5
|
+
} from "./chunk-A7YEHYLY.js";
|
|
6
|
+
import "./chunk-XXFUYME7.js";
|
|
7
|
+
import "./chunk-X34LPKG7.js";
|
|
8
|
+
import "./chunk-VY45MACP.js";
|
|
9
|
+
import "./chunk-FGOFRWIB.js";
|
|
10
|
+
export {
|
|
11
|
+
parseLedgeCommand,
|
|
12
|
+
sendMessage,
|
|
13
|
+
sendOnClient
|
|
14
|
+
};
|
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
runSetup,
|
|
14
14
|
stopDetachedDaemon,
|
|
15
15
|
systemdUnit
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-XIO4OIHR.js";
|
|
17
|
+
import "./chunk-ZEHTNFPV.js";
|
|
18
18
|
import "./chunk-YUSY3E47.js";
|
|
19
19
|
import "./chunk-FGOFRWIB.js";
|
|
20
20
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paradow/ledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Follow and answer your WSL agent sessions (Claude Code, Codex, Cursor Agent) from the Ledge island on Windows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "ledge": "dist/cli/index.js" },
|