@paradow/ledge 0.29.0 → 0.31.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 (33) hide show
  1. package/dist/cli/{action-MAPPYLUM.js → action-CFYJM2A2.js} +4 -4
  2. package/dist/cli/{attach-OC64CLB2.js → attach-23PTEIAA.js} +9 -8
  3. package/dist/cli/{bridge-TWX4V37E.js → bridge-UJKWEKA5.js} +1 -1
  4. package/dist/cli/{chunk-RFFTWAAF.js → chunk-6YBIZZQG.js} +1 -1
  5. package/dist/cli/{chunk-TREGH6WM.js → chunk-GMG3ROBU.js} +504 -302
  6. package/dist/cli/{chunk-MZVMW356.js → chunk-HEYHVOD6.js} +2 -2
  7. package/dist/cli/{chunk-XZYQMKKO.js → chunk-HNC5Q5PV.js} +3 -3
  8. package/dist/cli/{chunk-WCBXS3EU.js → chunk-HUY4CFMX.js} +107 -15
  9. package/dist/cli/{chunk-73YNZ3BN.js → chunk-MIPE2FWL.js} +2 -1
  10. package/dist/cli/{chunk-7S7ZLGIY.js → chunk-MYIBYAZC.js} +36 -8
  11. package/dist/cli/{chunk-WIUJNSAZ.js → chunk-NXNIRIGI.js} +5 -5
  12. package/dist/cli/{chunk-353WRRGG.js → chunk-QXH2L4UH.js} +3 -3
  13. package/dist/cli/{chunk-UWDE365N.js → chunk-TCJG3EHB.js} +47 -3
  14. package/dist/cli/{chunk-K3SDHHZF.js → chunk-TLFKLMBN.js} +1 -1
  15. package/dist/cli/{chunk-TNYBWWRO.js → chunk-WF27BASF.js} +2 -2
  16. package/dist/cli/chunk-WY5WSK2D.js +6 -0
  17. package/dist/cli/{chunk-ETGOWBUL.js → chunk-YI4V7YVW.js} +3 -3
  18. package/dist/cli/{daemon-ZTZ7VMYA.js → daemon-WW2P7RDV.js} +7 -7
  19. package/dist/cli/{decide-4BIYS3Y2.js → decide-HLRD37PW.js} +8 -6
  20. package/dist/cli/{handover-IS7BJYGZ.js → handover-56M4LIOP.js} +4 -4
  21. package/dist/cli/{hook-3VKVD4IP.js → hook-UJVKYSQ5.js} +34 -13
  22. package/dist/cli/index.js +16 -16
  23. package/dist/cli/{launch-XAPN2M3Q.js → launch-GIPQDPAC.js} +9 -8
  24. package/dist/cli/{send-ZLF2ZXMJ.js → send-HWZHE65N.js} +4 -4
  25. package/dist/cli/{status-NONO6E2S.js → status-V6ITP7VT.js} +2 -2
  26. package/dist/cli/{task-47MVWDCY.js → task-N53TM34B.js} +4 -4
  27. package/dist/cli/{team-EJ4YIXJH.js → team-CZFZ24P6.js} +6 -6
  28. package/dist/cli/{tui-CAP4O4YQ.js → tui-K32C34XI.js} +1274 -1176
  29. package/dist/cli/{version-EHBPJO7K.js → version-QIFJVKAQ.js} +1 -1
  30. package/dist/cli/{who-FHAXYCM2.js → who-NIOLHHB3.js} +3 -3
  31. package/dist/ledge-guide.md +268 -0
  32. package/package.json +1 -1
  33. package/dist/cli/chunk-JZEWCO6X.js +0 -6
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-TLFKLMBN.js";
4
4
  import {
5
5
  connect,
6
6
  sendMessageAndAwaitAck
7
- } from "./chunk-RFFTWAAF.js";
7
+ } from "./chunk-6YBIZZQG.js";
8
8
 
9
9
  // src/cli/send.ts
10
10
  import { randomUUID } from "crypto";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-TLFKLMBN.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-6YBIZZQG.js";
7
7
  import {
8
8
  BRIEF_MAX
9
- } from "./chunk-7S7ZLGIY.js";
9
+ } from "./chunk-MYIBYAZC.js";
10
10
 
11
11
  // src/cli/handover.ts
12
12
  import { randomUUID } from "crypto";
@@ -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-MIPE2FWL.js";
10
12
  import {
11
13
  SeatsSchema,
12
- TeamNameSchema
13
- } from "./chunk-7S7ZLGIY.js";
14
+ TeamNameSchema,
15
+ TemplateIdSchema
16
+ } from "./chunk-MYIBYAZC.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
  };
@@ -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-MYIBYAZC.js";
6
6
  import {
7
7
  log
8
8
  } from "./chunk-6IYPRUQG.js";
@@ -150,6 +150,7 @@ export {
150
150
  definitionDirs,
151
151
  definitionFiles,
152
152
  readSmall,
153
+ frontMatter,
153
154
  scalarValue,
154
155
  quoteScalar,
155
156
  definitionHash,
@@ -143,6 +143,10 @@ var SessionSchema = z2.object({
143
143
  roleLabel: z2.string().optional(),
144
144
  /** The live team it sits in (`team-…`); left out, the project's common table. */
145
145
  team: z2.string().optional(),
146
+ /** The name of the team it was last taken out of (a leave, a dissolution, a seat in another team): a refused `@role` says so. */
147
+ teamLeft: z2.string().optional(),
148
+ /** Its team as it was last told it (`seatKey`): its next turn is told again when the team has changed since. */
149
+ teamSeen: z2.string().optional(),
146
150
  /** Its role's autonomy, as launched (kept by a resume); left out, `ask`. */
147
151
  autonomy: AutonomySchema.optional(),
148
152
  /** Its context as its agent last reported it, after a turn (context handover spec §3.1); left out, not measured. */
@@ -340,14 +344,15 @@ var TeamSchema = z7.object({
340
344
  machine: z7.string(),
341
345
  cwd: z7.string(),
342
346
  state: TeamStateSchema,
343
- /** A live seat: `tool`, `model` and `effort` are what it was composed with over the role's defaults; `leaving` marks a seat removed
344
- * from the composition that finishes its turn and then is closed. */
347
+ /** A live seat: `tool`, `model` and `effort` are what it was composed with over the role's defaults, `name` the bot name it asks
348
+ * for (its template's or its composition's); `leaving` marks a seat removed from the composition that finishes its turn and then is closed. */
345
349
  seats: z7.array(z7.object({
346
350
  role: RoleIdSchema,
347
351
  sessionId: z7.string().nullable(),
348
352
  tool: ToolSchema.optional(),
349
353
  model: ModelIdSchema.optional(),
350
354
  effort: EffortSchema.optional(),
355
+ name: SeatSchema.shape.name,
351
356
  leaving: z7.literal(true).optional()
352
357
  })).max(TEAM_SEATS_MAX * 2),
353
358
  createdAt: z7.string(),
@@ -381,7 +386,7 @@ var TeamJoinSchema = z7.object({ type: z7.literal("team.join"), team: TeamIdSche
381
386
  var TeamLeaveSchema = z7.object({ type: z7.literal("team.leave"), team: TeamIdSchema, session: z7.string().min(1) });
382
387
  var TeamResumeSchema = z7.object({ type: z7.literal("team.resume"), team: TeamIdSchema });
383
388
  var TeamDissolveSchema = z7.object({ type: z7.literal("team.dissolve"), team: TeamIdSchema });
384
- var TeamSaveSchema = z7.object({ type: z7.literal("team.save"), rid: z7.string().min(1).max(100), name: TeamNameSchema, seats: SeatsSchema, qid: z7.string().min(1).optional() });
389
+ var TeamSaveSchema = z7.object({ type: z7.literal("team.save"), rid: z7.string().min(1).max(100), name: TeamNameSchema, seats: SeatsSchema, qid: z7.string().min(1).optional(), base: DefinitionHashSchema.optional() });
385
390
  var DefinitionScopeSchema = z7.enum(["home", "repo"]);
386
391
  var RoleDraftSchema = RoleSchema.pick({ id: true, label: true, prompt: true, tool: true, model: true, effort: true, autonomy: true });
387
392
  var DefinitionCodeSchema = z7.enum(["changed", "exists", "missing", "unknown_project", "invalid"]);
@@ -420,7 +425,7 @@ var TeamsMessageSchema = z7.object({ type: z7.literal("teams"), teams: z7.array(
420
425
  var TeamUpdatedSchema = z7.object({ type: z7.literal("team.updated"), team: TeamSchema });
421
426
  var TeamLaunchedSchema = z7.object({ type: z7.literal("team.launched"), rid: z7.string(), team: TeamSchema });
422
427
  var TeamFailedSchema = z7.object({ type: z7.literal("team.failed"), rid: z7.string(), reason: z7.string(), team: TeamSchema.optional() });
423
- var TeamSavedSchema = z7.object({ type: z7.literal("team.saved"), rid: z7.string(), path: z7.string().optional(), reason: z7.string().optional() });
428
+ var TeamSavedSchema = z7.object({ type: z7.literal("team.saved"), rid: z7.string(), path: z7.string().optional(), reason: z7.string().optional(), code: z7.enum(["exists", "changed"]).optional() });
424
429
  var isTeamLive = (t) => t.state !== "dissolved";
425
430
 
426
431
  // ../protocol/src/tasks.ts
@@ -465,6 +470,7 @@ function transmissions(t) {
465
470
  }
466
471
  var givenByLedge = (t) => t.giver === LEDGE_GIVER;
467
472
  var taskClosed = (t) => t.state === "done" || t.state === "refused" || t.state === "dropped";
473
+ var openDecision = (t) => t.owner === LEDGE_GIVER && !taskClosed(t);
468
474
  var TaskCmdSchema = z8.object({
469
475
  type: z8.literal("task.cmd"),
470
476
  rid: z8.string().min(1),
@@ -617,7 +623,8 @@ var ACTION_IDS = [
617
623
  "team.dissolve",
618
624
  "team.save",
619
625
  "task.cancel",
620
- "task.pass"
626
+ "task.pass",
627
+ "task.answer"
621
628
  ];
622
629
  var ActionIdSchema = z11.enum(ACTION_IDS);
623
630
  var def = (d) => d;
@@ -800,7 +807,7 @@ var ACTIONS = [
800
807
  card: "generic",
801
808
  phone: "act",
802
809
  risk: "destructive",
803
- max: 1,
810
+ max: 8,
804
811
  cli: "ledge team dissolve <\xE9quipe>",
805
812
  summary: "dissoudre une \xE9quipe : elle dispara\xEEt, ses sessions restent ; irr\xE9versible",
806
813
  when: "seulement quand l'utilisateur demande explicitement de dissoudre une \xE9quipe pr\xE9cise",
@@ -838,6 +845,17 @@ var ACTIONS = [
838
845
  summary: "passer une t\xE2che de tasks.md \xE0 une autre session (elle redevient ouverte)",
839
846
  when: "quand l'utilisateur demande de r\xE9assigner ou de passer une t\xE2che \xE0 une autre session",
840
847
  example: { task: "t91b0d4", to: "Bix" }
848
+ }),
849
+ def({
850
+ id: "task.answer",
851
+ args: z11.object({ task: TaskRef, answer: z11.string().trim().min(1).max(TASK_TEXT_MAX) }),
852
+ card: "generic",
853
+ phone: "act",
854
+ risk: "destructive",
855
+ max: 1,
856
+ summary: "r\xE9pondre, au nom de l'utilisateur, \xE0 une d\xE9cision qu'une session lui a pos\xE9e (tasks.md : owner Ledge) ; la session reprend avec cette r\xE9ponse ; irr\xE9versible",
857
+ when: "seulement quand l'utilisateur donne lui-m\xEAme sa r\xE9ponse \xE0 une d\xE9cision ouverte : answer reprend ses mots, ou l'option qu'il a choisie parmi celles de la session, sans rien inventer ni choisir \xE0 sa place ; si sa r\xE9ponse manque, cite les options et demande-la",
858
+ example: { task: "t91b0d4", answer: "Oui, fusionne feat/roles" }
841
859
  })
842
860
  ];
843
861
  var byId = new Map(ACTIONS.map((a) => [a.id, a]));
@@ -986,7 +1004,8 @@ var ChatTeamProposalSchema = z13.object({
986
1004
  teamId: z13.string().optional(),
987
1005
  launchedAt: z13.string().datetime().optional(),
988
1006
  error: z13.string().optional(),
989
- savedPath: z13.string().optional()
1007
+ savedPath: z13.string().optional(),
1008
+ saveError: z13.string().optional()
990
1009
  });
991
1010
  var ChatTaskProposalSchema = z13.object({
992
1011
  to: z13.string().min(1),
@@ -1026,6 +1045,7 @@ var ACTION_ERROR_CODES = [
1026
1045
  "holder",
1027
1046
  "changed",
1028
1047
  "cut",
1048
+ "not_decision",
1029
1049
  "failed"
1030
1050
  ];
1031
1051
  var ChatActionStateSchema = z13.enum(["running", "done", "denied", "failed", "refused"]);
@@ -1574,6 +1594,8 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
1574
1594
  z21.object({ type: z21.literal("session.delete"), id: z21.string() }),
1575
1595
  /** The user names the session's topic from the overlay (500 characters at most, the hook's prompt cap); an empty topic hands back to the automatic sources. */
1576
1596
  z21.object({ type: z21.literal("session.rename"), id: z21.string(), topic: z21.string().max(500) }),
1597
+ /** A seat's hook told it its team as `key` names it (`seatKey`): at its start, or at a turn after the team changed. */
1598
+ z21.object({ type: z21.literal("seat.seen"), id: z21.string(), key: z21.string().max(4e3) }),
1577
1599
  z21.object({ type: z21.literal("session.thread"), id: z21.string() }),
1578
1600
  z21.object({ type: z21.literal("session.register"), session: SessionSchema }),
1579
1601
  /** `agent` and `cwd` describe the session when the daemon does not know it yet (a hook from an agent started without ledge). */
@@ -1838,7 +1860,7 @@ var PushSubscriptionSchema = z24.object({
1838
1860
  });
1839
1861
  var PushPayloadSchema = z24.object({
1840
1862
  v: z24.literal(1),
1841
- kind: z24.enum(["request", "question", "finished", "chat"]),
1863
+ kind: z24.enum(["request", "question", "finished", "chat", "decision"]),
1842
1864
  title: z24.string().max(80),
1843
1865
  body: z24.string().max(120),
1844
1866
  url: z24.string().regex(/^\/#\/[A-Za-z0-9/%._~-]*$/).max(300),
@@ -2080,6 +2102,10 @@ var PhoneTaskSchema = z26.object({
2080
2102
  owner: z26.string().max(100),
2081
2103
  ownerName: z26.string().max(80),
2082
2104
  ownerRole: z26.string().max(40).optional(),
2105
+ /** Who gave it: `ledge` for Ledge's own; a session for a decision it put to the user (owner `ledge`), with its detail (the options). */
2106
+ giver: z26.string().max(100).optional(),
2107
+ giverName: z26.string().max(80).optional(),
2108
+ text: z26.string().max(TOOL_TEXT_MAX).optional(),
2083
2109
  team: z26.string().max(40).optional(),
2084
2110
  teamName: z26.string().max(60).optional(),
2085
2111
  state: z26.enum(["open", "taken", "done", "refused", "dropped"]),
@@ -2547,6 +2573,7 @@ export {
2547
2573
  ROLE_LABEL_MAX,
2548
2574
  ROLE_PROMPT_MAX,
2549
2575
  RoleSchema,
2576
+ TEAM_SEATS_MAX,
2550
2577
  SeatsSchema,
2551
2578
  TeamNameSchema,
2552
2579
  TemplateIdSchema,
@@ -2562,6 +2589,7 @@ export {
2562
2589
  transmissions,
2563
2590
  givenByLedge,
2564
2591
  taskClosed,
2592
+ openDecision,
2565
2593
  ACTIONS,
2566
2594
  actionById,
2567
2595
  riskOf,
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  EFFORT_ARGS,
3
3
  MODEL_ARGS
4
- } from "./chunk-TREGH6WM.js";
4
+ } from "./chunk-GMG3ROBU.js";
5
5
  import {
6
6
  findRole
7
- } from "./chunk-73YNZ3BN.js";
7
+ } from "./chunk-MIPE2FWL.js";
8
8
  import {
9
9
  exitFile,
10
10
  spawnSession
11
- } from "./chunk-K3SDHHZF.js";
11
+ } from "./chunk-TLFKLMBN.js";
12
12
  import {
13
13
  DaemonRefusedError,
14
14
  connect
15
- } from "./chunk-RFFTWAAF.js";
15
+ } from "./chunk-6YBIZZQG.js";
16
16
  import {
17
17
  PROTOCOL_PORT,
18
18
  autonomyArgs
19
- } from "./chunk-7S7ZLGIY.js";
19
+ } from "./chunk-MYIBYAZC.js";
20
20
  import {
21
21
  realTmux
22
22
  } from "./chunk-NLL2EQJ2.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-TLFKLMBN.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-6YBIZZQG.js";
7
7
  import {
8
8
  SESSION_KEY_VAR,
9
9
  actionById
10
- } from "./chunk-7S7ZLGIY.js";
10
+ } from "./chunk-MYIBYAZC.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-TLFKLMBN.js";
4
4
  import {
5
5
  cleanTopic,
6
6
  isArchived,
7
7
  sessionTitle
8
- } from "./chunk-7S7ZLGIY.js";
8
+ } from "./chunk-MYIBYAZC.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,
@@ -3,7 +3,7 @@ import {
3
3
  SESSION_KEY_VAR,
4
4
  pickName,
5
5
  sessionKey
6
- } from "./chunk-7S7ZLGIY.js";
6
+ } from "./chunk-MYIBYAZC.js";
7
7
  import {
8
8
  paths
9
9
  } from "./chunk-HOOHS3MX.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-RFFTWAAF.js";
3
+ } from "./chunk-6YBIZZQG.js";
4
4
  import {
5
5
  isArchived
6
- } from "./chunk-7S7ZLGIY.js";
6
+ } from "./chunk-MYIBYAZC.js";
7
7
 
8
8
  // src/cli/who.ts
9
9
  import { basename } from "path";
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var LEDGE_VERSION = true ? "0.31.0" : "0.0.0-dev";
3
+
4
+ export {
5
+ LEDGE_VERSION
6
+ };
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
3
+ } from "./chunk-TLFKLMBN.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-RFFTWAAF.js";
6
+ } from "./chunk-6YBIZZQG.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-MYIBYAZC.js";
12
12
 
13
13
  // src/cli/task.ts
14
14
  import { randomUUID } from "crypto";
@@ -9,9 +9,9 @@ import {
9
9
  startServer,
10
10
  tasksJournal,
11
11
  teamsJournal
12
- } from "./chunk-TREGH6WM.js";
12
+ } from "./chunk-GMG3ROBU.js";
13
13
  import "./chunk-OLLQBK6N.js";
14
- import "./chunk-WCBXS3EU.js";
14
+ import "./chunk-HUY4CFMX.js";
15
15
  import {
16
16
  QUESTION_TOOLS,
17
17
  crossSession,
@@ -26,11 +26,11 @@ import {
26
26
  readPeers,
27
27
  reduce,
28
28
  stripNote
29
- } from "./chunk-UWDE365N.js";
30
- import "./chunk-73YNZ3BN.js";
29
+ } from "./chunk-TCJG3EHB.js";
30
+ import "./chunk-MIPE2FWL.js";
31
31
  import {
32
32
  agentMessages
33
- } from "./chunk-K3SDHHZF.js";
33
+ } from "./chunk-TLFKLMBN.js";
34
34
  import {
35
35
  DEFAULT_RELAY_URL,
36
36
  DevicePollResponseSchema,
@@ -44,10 +44,10 @@ import {
44
44
  SealedFrameSchema,
45
45
  SessionSchema,
46
46
  backendOf
47
- } from "./chunk-7S7ZLGIY.js";
47
+ } from "./chunk-MYIBYAZC.js";
48
48
  import {
49
49
  LEDGE_VERSION
50
- } from "./chunk-JZEWCO6X.js";
50
+ } from "./chunk-WY5WSK2D.js";
51
51
  import {
52
52
  SERVICE,
53
53
  inDaemonService,
@@ -1,13 +1,16 @@
1
+ import {
2
+ runOnClient
3
+ } from "./chunk-QXH2L4UH.js";
1
4
  import {
2
5
  CODEX_HOOK_VAR
3
- } from "./chunk-K3SDHHZF.js";
6
+ } from "./chunk-TLFKLMBN.js";
4
7
  import {
5
8
  connect
6
- } from "./chunk-RFFTWAAF.js";
9
+ } from "./chunk-6YBIZZQG.js";
7
10
  import {
8
11
  LEDGE_GIVER,
9
12
  TASK_TEXT_MAX
10
- } from "./chunk-7S7ZLGIY.js";
13
+ } from "./chunk-MYIBYAZC.js";
11
14
  import "./chunk-HOOHS3MX.js";
12
15
  import "./chunk-U67V476Y.js";
13
16
 
@@ -40,10 +43,9 @@ async function runDecide(args, opts = {}) {
40
43
  if (!asked.length) return { line: "aucune d\xE9cision en attente", code: 0 };
41
44
  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 };
42
45
  }
43
- client.send({ type: "task.cmd", rid: randomUUID(), by: LEDGE_GIVER, op: "done", task: op.task, text: op.text });
44
- const r = await client.next("task.result", DECIDE_MS);
46
+ const r = await runOnClient(client, "task.answer", { task: op.task, answer: op.text }, { confirmed: true, ms: DECIDE_MS });
45
47
  if (r.reason !== void 0) return { line: `refus\xE9 : ${r.reason}`, code: 1 };
46
- return { line: `r\xE9ponse envoy\xE9e \xE0 ${r.task.giverName}`, code: 0 };
48
+ return { line: `r\xE9ponse envoy\xE9e \xE0 ${r.row?.vars?.session ?? "la session"}`, code: 0 };
47
49
  } catch (e) {
48
50
  return { line: `pas de r\xE9ponse de Ledge : ${e.message}`, code: 1 };
49
51
  } finally {
@@ -3,10 +3,10 @@ import {
3
3
  handoverArgs,
4
4
  handoverOnClient,
5
5
  runHandover
6
- } from "./chunk-XZYQMKKO.js";
7
- import "./chunk-K3SDHHZF.js";
8
- import "./chunk-RFFTWAAF.js";
9
- import "./chunk-7S7ZLGIY.js";
6
+ } from "./chunk-HNC5Q5PV.js";
7
+ import "./chunk-TLFKLMBN.js";
8
+ import "./chunk-6YBIZZQG.js";
9
+ import "./chunk-MYIBYAZC.js";
10
10
  import "./chunk-HOOHS3MX.js";
11
11
  import "./chunk-U67V476Y.js";
12
12
  export {