@paradow/ledge 0.29.0 → 0.30.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.
Files changed (32) hide show
  1. package/dist/cli/{action-MAPPYLUM.js → action-IL5A2O4K.js} +4 -4
  2. package/dist/cli/{attach-OC64CLB2.js → attach-XFRWCGMD.js} +8 -8
  3. package/dist/cli/{bridge-TWX4V37E.js → bridge-KEDZGBEK.js} +1 -1
  4. package/dist/cli/{chunk-XZYQMKKO.js → chunk-2GSAJOLJ.js} +3 -3
  5. package/dist/cli/{chunk-WIUJNSAZ.js → chunk-4JQHF3HM.js} +5 -5
  6. package/dist/cli/{chunk-ETGOWBUL.js → chunk-D2EYVNJ6.js} +3 -3
  7. package/dist/cli/{chunk-73YNZ3BN.js → chunk-GOBUJGB6.js} +1 -1
  8. package/dist/cli/{chunk-TNYBWWRO.js → chunk-H563AKHN.js} +2 -2
  9. package/dist/cli/{chunk-WCBXS3EU.js → chunk-HH6LFLPR.js} +107 -15
  10. package/dist/cli/{chunk-RFFTWAAF.js → chunk-JBYVS2F4.js} +1 -1
  11. package/dist/cli/{chunk-353WRRGG.js → chunk-KESZUXUI.js} +3 -3
  12. package/dist/cli/{chunk-UWDE365N.js → chunk-LHWJBSLO.js} +47 -3
  13. package/dist/cli/{chunk-TREGH6WM.js → chunk-OOPOJK6Y.js} +206 -175
  14. package/dist/cli/chunk-P2X2M3TR.js +6 -0
  15. package/dist/cli/{chunk-MZVMW356.js → chunk-RGYQFRG5.js} +2 -2
  16. package/dist/cli/{chunk-7S7ZLGIY.js → chunk-U44NT4XJ.js} +35 -7
  17. package/dist/cli/{chunk-K3SDHHZF.js → chunk-XHC6EPZE.js} +1 -1
  18. package/dist/cli/{daemon-ZTZ7VMYA.js → daemon-A54MACKQ.js} +7 -7
  19. package/dist/cli/{decide-4BIYS3Y2.js → decide-2HKZF4VI.js} +8 -6
  20. package/dist/cli/{handover-IS7BJYGZ.js → handover-3PV3MDK3.js} +4 -4
  21. package/dist/cli/{hook-3VKVD4IP.js → hook-S5226MJF.js} +34 -13
  22. package/dist/cli/index.js +16 -16
  23. package/dist/cli/{launch-XAPN2M3Q.js → launch-NGWPGU6E.js} +8 -8
  24. package/dist/cli/{send-ZLF2ZXMJ.js → send-NYKZRELC.js} +4 -4
  25. package/dist/cli/{status-NONO6E2S.js → status-6USM7SJE.js} +2 -2
  26. package/dist/cli/{task-47MVWDCY.js → task-E5J6UT7S.js} +4 -4
  27. package/dist/cli/{team-EJ4YIXJH.js → team-AP7A5VMP.js} +6 -6
  28. package/dist/cli/{tui-CAP4O4YQ.js → tui-EK7VC7YP.js} +1273 -1176
  29. package/dist/cli/{version-EHBPJO7K.js → version-KORN5SQT.js} +1 -1
  30. package/dist/cli/{who-FHAXYCM2.js → who-RA4QBVUA.js} +3 -3
  31. package/package.json +1 -1
  32. package/dist/cli/chunk-JZEWCO6X.js +0 -6
@@ -8,10 +8,10 @@ import {
8
8
  resultLine,
9
9
  runClose,
10
10
  runOnClient
11
- } from "./chunk-353WRRGG.js";
12
- import "./chunk-K3SDHHZF.js";
13
- import "./chunk-RFFTWAAF.js";
14
- import "./chunk-7S7ZLGIY.js";
11
+ } from "./chunk-KESZUXUI.js";
12
+ import "./chunk-XHC6EPZE.js";
13
+ import "./chunk-JBYVS2F4.js";
14
+ import "./chunk-U44NT4XJ.js";
15
15
  import "./chunk-HOOHS3MX.js";
16
16
  import "./chunk-U67V476Y.js";
17
17
  export {
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  attachEnv
3
- } from "./chunk-WIUJNSAZ.js";
4
- import "./chunk-TREGH6WM.js";
3
+ } from "./chunk-4JQHF3HM.js";
4
+ import "./chunk-OOPOJK6Y.js";
5
5
  import "./chunk-OLLQBK6N.js";
6
- import "./chunk-WCBXS3EU.js";
7
- import "./chunk-UWDE365N.js";
8
- import "./chunk-73YNZ3BN.js";
9
- import "./chunk-K3SDHHZF.js";
6
+ import "./chunk-HH6LFLPR.js";
7
+ import "./chunk-LHWJBSLO.js";
8
+ import "./chunk-GOBUJGB6.js";
9
+ import "./chunk-XHC6EPZE.js";
10
10
  import {
11
11
  connect
12
- } from "./chunk-RFFTWAAF.js";
12
+ } from "./chunk-JBYVS2F4.js";
13
13
  import {
14
14
  PROTOCOL_PORT,
15
15
  backendOf
16
- } from "./chunk-7S7ZLGIY.js";
16
+ } from "./chunk-U44NT4XJ.js";
17
17
  import {
18
18
  realTmux
19
19
  } from "./chunk-NLL2EQJ2.js";
@@ -7,7 +7,7 @@ import {
7
7
  parseClientMessage,
8
8
  parseServerMessage,
9
9
  readDaemonToken
10
- } from "./chunk-7S7ZLGIY.js";
10
+ } from "./chunk-U44NT4XJ.js";
11
11
  import "./chunk-HOOHS3MX.js";
12
12
  import "./chunk-U67V476Y.js";
13
13
 
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-XHC6EPZE.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-JBYVS2F4.js";
7
7
  import {
8
8
  BRIEF_MAX
9
- } from "./chunk-7S7ZLGIY.js";
9
+ } from "./chunk-U44NT4XJ.js";
10
10
 
11
11
  // src/cli/handover.ts
12
12
  import { randomUUID } from "crypto";
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  EFFORT_ARGS,
3
3
  MODEL_ARGS
4
- } from "./chunk-TREGH6WM.js";
4
+ } from "./chunk-OOPOJK6Y.js";
5
5
  import {
6
6
  findRole
7
- } from "./chunk-73YNZ3BN.js";
7
+ } from "./chunk-GOBUJGB6.js";
8
8
  import {
9
9
  exitFile,
10
10
  spawnSession
11
- } from "./chunk-K3SDHHZF.js";
11
+ } from "./chunk-XHC6EPZE.js";
12
12
  import {
13
13
  DaemonRefusedError,
14
14
  connect
15
- } from "./chunk-RFFTWAAF.js";
15
+ } from "./chunk-JBYVS2F4.js";
16
16
  import {
17
17
  PROTOCOL_PORT,
18
18
  autonomyArgs
19
- } from "./chunk-7S7ZLGIY.js";
19
+ } from "./chunk-U44NT4XJ.js";
20
20
  import {
21
21
  realTmux
22
22
  } from "./chunk-NLL2EQJ2.js";
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-XHC6EPZE.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-JBYVS2F4.js";
7
7
  import {
8
8
  LEDGE_GIVER,
9
9
  TASK_TEXT_MAX,
10
10
  TASK_TITLE_MAX
11
- } from "./chunk-7S7ZLGIY.js";
11
+ } from "./chunk-U44NT4XJ.js";
12
12
 
13
13
  // src/cli/task.ts
14
14
  import { randomUUID } from "crypto";
@@ -2,7 +2,7 @@ import {
2
2
  ROLE_LABEL_MAX,
3
3
  ROLE_PROMPT_MAX,
4
4
  RoleSchema
5
- } from "./chunk-7S7ZLGIY.js";
5
+ } from "./chunk-U44NT4XJ.js";
6
6
  import {
7
7
  log
8
8
  } from "./chunk-6IYPRUQG.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-RFFTWAAF.js";
3
+ } from "./chunk-JBYVS2F4.js";
4
4
  import {
5
5
  isArchived
6
- } from "./chunk-7S7ZLGIY.js";
6
+ } from "./chunk-U44NT4XJ.js";
7
7
 
8
8
  // src/cli/who.ts
9
9
  import { basename } from "path";
@@ -3,14 +3,17 @@ import {
3
3
  definitionFiles,
4
4
  definitionHash,
5
5
  listRoles,
6
+ loadRole,
6
7
  quoteScalar,
7
8
  readSmall,
9
+ repoRoot,
8
10
  scalarValue
9
- } from "./chunk-73YNZ3BN.js";
11
+ } from "./chunk-GOBUJGB6.js";
10
12
  import {
11
13
  SeatsSchema,
12
- TeamNameSchema
13
- } from "./chunk-7S7ZLGIY.js";
14
+ TeamNameSchema,
15
+ TemplateIdSchema
16
+ } from "./chunk-U44NT4XJ.js";
14
17
  import {
15
18
  log
16
19
  } from "./chunk-6IYPRUQG.js";
@@ -19,8 +22,87 @@ import {
19
22
  } from "./chunk-HOOHS3MX.js";
20
23
 
21
24
  // src/daemon/teams.ts
22
- import { existsSync, writeFileSync, mkdirSync, renameSync } from "fs";
23
- import { join } from "path";
25
+ import { readFileSync as readFileSync2 } from "fs";
26
+ import { join as join2 } from "path";
27
+
28
+ // src/daemon/definitions.ts
29
+ import { linkSync, mkdirSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync } from "fs";
30
+ import { basename, dirname, join } from "path";
31
+ function roleText(r) {
32
+ const lines = [];
33
+ for (const [key, value] of [["label", r.label], ["tool", r.tool], ["model", r.model], ["effort", r.effort], ["autonomy", r.autonomy]]) {
34
+ if (value === void 0) continue;
35
+ const q = quoteScalar(value);
36
+ if (q === null) return null;
37
+ lines.push(`${key}: ${q}`);
38
+ }
39
+ return `---
40
+ ${lines.join("\n")}
41
+ ---
42
+
43
+ ${r.prompt}
44
+ `;
45
+ }
46
+ function current(path) {
47
+ try {
48
+ return readFileSync(path, "utf8");
49
+ } catch (e) {
50
+ if (e.code === "ENOENT") return void 0;
51
+ throw e;
52
+ }
53
+ }
54
+ function writeDefinition(path, text, base) {
55
+ const now = current(path);
56
+ if (base === null) {
57
+ if (now !== void 0) return { code: "exists" };
58
+ } else if (now === void 0 || definitionHash(now) !== base) return { code: "changed" };
59
+ mkdirSync(dirname(path), { recursive: true });
60
+ const tmp = `${path}.${process.pid}.tmp`;
61
+ try {
62
+ writeFileSync(tmp, text);
63
+ if (base === null) linkSync(tmp, path);
64
+ else renameSync(tmp, path);
65
+ } catch (e) {
66
+ rmSync(tmp, { force: true });
67
+ if (base === null && e.code === "EEXIST") return { code: "exists" };
68
+ throw e;
69
+ }
70
+ rmSync(tmp, { force: true });
71
+ return { hash: definitionHash(readFileSync(path, "utf8")) };
72
+ }
73
+ function deleteDefinition(path, base) {
74
+ const now = current(path);
75
+ if (now === void 0) return { code: "missing" };
76
+ if (definitionHash(now) !== base) return { code: "changed" };
77
+ unlinkSync(path);
78
+ return { ok: true };
79
+ }
80
+ function scopeDir(kind, scope, repoFolder) {
81
+ if (scope === "home") return join(ledgeDir(), kind);
82
+ if (!repoFolder) throw new Error("the repository scope needs a folder");
83
+ return join(repoRoot(repoFolder), ".ledge", kind);
84
+ }
85
+ function scopeDefinitions(dir, scope) {
86
+ const problems = [];
87
+ const roles = [];
88
+ const templates = /* @__PURE__ */ new Map();
89
+ for (const path of definitionFiles(dir.roles, [".md"])) {
90
+ const r = loadRole(basename(path, ".md"), path, scope, problems);
91
+ if (r) roles.push(r);
92
+ }
93
+ for (const path of definitionFiles(dir.teams, [".yaml", ".yml"])) {
94
+ const id = basename(path).replace(/\.ya?ml$/, "");
95
+ if (templates.has(id)) continue;
96
+ const t = loadTemplate(id, path, scope, problems);
97
+ if (t) templates.set(id, t);
98
+ }
99
+ return { roles: roles.sort((a, b) => a.id.localeCompare(b.id)), templates: [...templates.values()].sort((a, b) => a.id.localeCompare(b.id)), problems };
100
+ }
101
+ function promptRecipients(roleId, path, sessions, resolve) {
102
+ return sessions.filter((s) => s.role === roleId && s.source === "launcher" && s.state !== "exited" && s.archivedAt === void 0 && resolve(roleId, s.cwd)?.path === path);
103
+ }
104
+
105
+ // src/daemon/teams.ts
24
106
  var scalar = scalarValue;
25
107
  function flowMap(raw) {
26
108
  const inner = raw.trim().replace(/^\{/, "").replace(/\}$/, "");
@@ -89,6 +171,7 @@ function parseTemplateText(text) {
89
171
  return out;
90
172
  }
91
173
  function parseTemplate(id, text, source, path) {
174
+ if (!TemplateIdSchema.safeParse(id).success) return "nom de fichier invalide : lettres, chiffres, - et _ seulement (64 au plus, sans point), puis .yaml";
92
175
  let raw;
93
176
  try {
94
177
  raw = parseTemplateText(text);
@@ -174,25 +257,34 @@ function templateText(name, seats) {
174
257
  return `${lines.join("\n")}
175
258
  `;
176
259
  }
177
- var templatePath = (name, dir) => join(dir, `${templateId(name)}.yaml`);
178
- var templateExists = (name, dir = join(ledgeDir(), "teams")) => existsSync(templatePath(name, dir));
179
- function saveTemplate(name, seats, dir = join(ledgeDir(), "teams")) {
260
+ var templatePath = (name, dir) => join2(dir, `${templateId(name)}.yaml`);
261
+ function templateHash(name, dir = join2(ledgeDir(), "teams")) {
262
+ try {
263
+ return definitionHash(readFileSync2(templatePath(name, dir), "utf8"));
264
+ } catch (e) {
265
+ if (e.code === "ENOENT") return void 0;
266
+ throw e;
267
+ }
268
+ }
269
+ function saveTemplate(name, seats, base, dir = join2(ledgeDir(), "teams")) {
180
270
  const path = templatePath(name, dir);
181
271
  const text = templateText(name, seats);
182
272
  if (text === null) throw new Error("a team name or seat value cannot be written as YAML");
183
- mkdirSync(dir, { recursive: true });
184
- const tmp = `${path}.tmp`;
185
- writeFileSync(tmp, text);
186
- renameSync(tmp, path);
187
- return path;
273
+ const r = writeDefinition(path, text, base ?? null);
274
+ return "code" in r ? { path, code: r.code } : { path };
188
275
  }
189
276
 
190
277
  export {
191
- loadTemplate,
278
+ roleText,
279
+ writeDefinition,
280
+ deleteDefinition,
281
+ scopeDir,
282
+ scopeDefinitions,
283
+ promptRecipients,
192
284
  resolveSeats,
193
285
  listDefinitions,
194
286
  templateId,
195
287
  templateText,
196
- templateExists,
288
+ templateHash,
197
289
  saveTemplate
198
290
  };
@@ -4,7 +4,7 @@ import {
4
4
  SUMMARY_MAX,
5
5
  parseServerMessage,
6
6
  readDaemonToken
7
- } from "./chunk-7S7ZLGIY.js";
7
+ } from "./chunk-U44NT4XJ.js";
8
8
 
9
9
  // src/client.ts
10
10
  import WebSocket from "ws";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-XHC6EPZE.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-JBYVS2F4.js";
7
7
  import {
8
8
  SESSION_KEY_VAR,
9
9
  actionById
10
- } from "./chunk-7S7ZLGIY.js";
10
+ } from "./chunk-U44NT4XJ.js";
11
11
 
12
12
  // src/cli/action.ts
13
13
  import { randomUUID } from "crypto";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  ledgeTitleRest
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-XHC6EPZE.js";
4
4
  import {
5
5
  cleanTopic,
6
6
  isArchived,
7
7
  sessionTitle
8
- } from "./chunk-7S7ZLGIY.js";
8
+ } from "./chunk-U44NT4XJ.js";
9
9
 
10
10
  // src/daemon/seat.ts
11
11
  function teammates(team, sessions) {
@@ -30,11 +30,51 @@ function seatContext(o) {
30
30
  }
31
31
  return lines.join("\n");
32
32
  }
33
+ function noTeamReason(to, sender) {
34
+ return sender?.teamLeft ? `tu n'es plus dans l'\xE9quipe ${sender.teamLeft} : ${to} ne te sert plus (ledge team list)` : `${to} n'existe que dans une \xE9quipe`;
35
+ }
36
+ function seatView(id, sessions, teams) {
37
+ const s = sessions.find((x) => x.id === id);
38
+ const team = s?.team ? teams.find((t) => t.id === s.team && t.state !== "dissolved") : void 0;
39
+ if (!s || !team) return null;
40
+ return { id: team.id, name: team.name, members: teammates(team, sessions).filter((m) => m.name !== s.name) };
41
+ }
42
+ var seatKey = (v) => v ? JSON.stringify({ t: v.id, n: v.name, m: v.members.map((m) => `${m.name}@${m.role}`) }) : "";
43
+ var parseKey = (k) => {
44
+ try {
45
+ return k ? JSON.parse(k) : null;
46
+ } catch {
47
+ return null;
48
+ }
49
+ };
50
+ var member = (m) => {
51
+ const at = m.lastIndexOf("@");
52
+ return { name: m.slice(0, at), role: m.slice(at + 1) };
53
+ };
54
+ var listOf = (k) => k.m.map(member).map((m) => `${m.name} (${m.role})`).join(", ") || "personne d'autre pour l'instant";
55
+ function teamChangeLine(seen, now) {
56
+ if (seen === void 0 || seen === now) return void 0;
57
+ const before = parseKey(seen);
58
+ const after = parseKey(now);
59
+ if (!after) return before ? `Ledge : tu n'es plus dans l'\xE9quipe ${before.n} ; les adresses @r\xF4le ne te servent plus (ledge team list).` : void 0;
60
+ const reach = '\xC9cris-leur par leur r\xF4le : ledge send @r\xF4le "\u2026".';
61
+ if (!before || before.t !== after.t) return `Ledge : tu es maintenant dans l'\xE9quipe ${after.n}. Ton \xE9quipe : ${listOf(after)}. ${reach}`;
62
+ const was = before.m.map(member);
63
+ const is = after.m.map(member);
64
+ const changes = [];
65
+ for (const m of is) {
66
+ if (was.some((w) => w.name === m.name && w.role === m.role)) continue;
67
+ const prior = was.find((w) => w.role === m.role && !is.some((x) => x.name === w.name && x.role === w.role));
68
+ changes.push(prior ? `${m.name} remplace ${prior.name} (${m.role})` : `${m.name} (${m.role}) arrive`);
69
+ }
70
+ for (const w of was) if (!is.some((m) => m.name === w.name && m.role === w.role) && !is.some((m) => m.role === w.role)) changes.push(`${w.name} (${w.role}) part`);
71
+ return `Ledge : ton \xE9quipe ${after.n} a chang\xE9${changes.length ? ` (${changes.join(", ")})` : ""}. Ton \xE9quipe : ${listOf(after)}. ${reach}`;
72
+ }
33
73
  function resolveRoleAddress(to, from, sessions, teams) {
34
74
  if (!to.startsWith("@")) return { to };
35
75
  const role = to.slice(1);
36
76
  const team = teams.find((t) => t.state !== "dissolved" && t.seats.some((s) => s.sessionId === from));
37
- if (!team) return { reason: `${to} n'existe que dans une \xE9quipe` };
77
+ if (!team) return { reason: noTeamReason(to, sessions.find((s) => s.id === from)) };
38
78
  const byId = new Map(sessions.map((s) => [s.id, s]));
39
79
  const held = team.seats.filter((s) => s.role === role && s.sessionId).map((s) => byId.get(s.sessionId)).filter((s) => !!s && s.state !== "exited" && !isArchived(s));
40
80
  if (held.length === 1) return { to: held[0].name };
@@ -637,6 +677,10 @@ function takeImages(text, dir) {
637
677
  export {
638
678
  teammates,
639
679
  seatContext,
680
+ noTeamReason,
681
+ seatView,
682
+ seatKey,
683
+ teamChangeLine,
640
684
  resolveRoleAddress,
641
685
  crossSession,
642
686
  messageNote,