@paradow/ledge 0.27.0 → 0.29.0-snapshot.41297455946.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.
Files changed (48) hide show
  1. package/README.md +8 -0
  2. package/dist/cli/{action-7SJJTIEA.js → action-MCR4BCSE.js} +5 -5
  3. package/dist/cli/ask-L3PSQZ2K.js +17 -0
  4. package/dist/cli/{attach-V7UPHVB2.js → attach-R7FT7LFH.js} +9 -14
  5. package/dist/cli/brain-BJTBN2ZK.js +20 -0
  6. package/dist/cli/{bridge-JK3PMG7T.js → bridge-YBHXFEFX.js} +2 -2
  7. package/dist/cli/{chunk-37G5F75H.js → chunk-2X56ZRK7.js} +1229 -1156
  8. package/dist/cli/{chunk-7OGFH6KJ.js → chunk-6EW2FD2U.js} +3 -5
  9. package/dist/cli/chunk-DJMFCYF4.js +60 -0
  10. package/dist/cli/chunk-DLKJOK3B.js +6 -0
  11. package/dist/cli/{chunk-7GIUG73R.js → chunk-FWLT3SAN.js} +1 -1
  12. package/dist/cli/{chunk-6IYPRUQG.js → chunk-G3ST5WKR.js} +1 -1
  13. package/dist/cli/{chunk-7JRQCKBP.js → chunk-GY35ZR5I.js} +102 -72
  14. package/dist/cli/{chunk-NLL2EQJ2.js → chunk-KBSXP63H.js} +22 -7
  15. package/dist/cli/chunk-LOXLGCGN.js +57 -0
  16. package/dist/cli/{chunk-ADAGKOFO.js → chunk-O4MUYFPH.js} +6 -7
  17. package/dist/cli/{chunk-2N7PSP7C.js → chunk-OR2NHT5O.js} +4 -4
  18. package/dist/cli/chunk-S6BZV7AY.js +57 -0
  19. package/dist/cli/{chunk-IGAGJVRZ.js → chunk-TCQ5PYIF.js} +3 -3
  20. package/dist/cli/{chunk-ISNHG5SJ.js → chunk-UMQGRTA4.js} +17 -39
  21. package/dist/cli/{chunk-RA3OIXEQ.js → chunk-VQR5ME75.js} +4 -3
  22. package/dist/cli/{chunk-HOOHS3MX.js → chunk-W724IVDC.js} +1 -1
  23. package/dist/cli/{chunk-K7UEKSB2.js → chunk-WYRQZA4G.js} +2 -2
  24. package/dist/cli/chunk-XTDE2URL.js +365 -0
  25. package/dist/cli/daemon-ICC6LBCO.js +16562 -0
  26. package/dist/cli/{decide-HFI2WQXI.js → decide-JSY46QZC.js} +14 -16
  27. package/dist/cli/{handover-GKORMXZ2.js → handover-5RUSRVAD.js} +5 -5
  28. package/dist/cli/{hook-TJJEFV54.js → hook-QQP3ENGA.js} +87 -81
  29. package/dist/cli/index.js +40 -28
  30. package/dist/cli/launch-RTBGUJSC.js +28 -0
  31. package/dist/cli/{send-RI7JOO5K.js → send-BIIH6SQW.js} +5 -5
  32. package/dist/cli/{setup-K42IVMHS.js → setup-OLVRJLJE.js} +4 -4
  33. package/dist/cli/{status-RQRS26S2.js → status-Z3I33KZJ.js} +3 -3
  34. package/dist/cli/{tui-UWR7SDYF.js → tui-AIXCETOB.js} +6036 -3629
  35. package/dist/cli/{uninstall-4IMMR55T.js → uninstall-X65CWHIJ.js} +4 -4
  36. package/dist/cli/{version-YYNMMWKJ.js → version-QMHFVP3N.js} +1 -1
  37. package/dist/cli/who-C2VMEM35.js +12 -0
  38. package/package.json +21 -6
  39. package/dist/cli/chunk-CVHX7GUB.js +0 -9226
  40. package/dist/cli/chunk-HMTOPOJG.js +0 -6
  41. package/dist/cli/chunk-TOSPL5H2.js +0 -118
  42. package/dist/cli/chunk-UPKJO3BZ.js +0 -159
  43. package/dist/cli/chunk-YLN3VOGV.js +0 -198
  44. package/dist/cli/daemon-YUPB5NUG.js +0 -2322
  45. package/dist/cli/launch-QKQZZSIM.js +0 -35
  46. package/dist/cli/task-U2XHBUKW.js +0 -19
  47. package/dist/cli/team-NFC4XEIA.js +0 -205
  48. package/dist/cli/who-WW6IL4KD.js +0 -12
@@ -1,6 +0,0 @@
1
- // src/version.ts
2
- var LEDGE_VERSION = true ? "0.27.0" : "0.0.0-dev";
3
-
4
- export {
5
- LEDGE_VERSION
6
- };
@@ -1,118 +0,0 @@
1
- import {
2
- CODEX_HOOK_VAR
3
- } from "./chunk-ADAGKOFO.js";
4
- import {
5
- connect
6
- } from "./chunk-7GIUG73R.js";
7
- import {
8
- LEDGE_GIVER,
9
- TASK_TEXT_MAX,
10
- TASK_TITLE_MAX
11
- } from "./chunk-37G5F75H.js";
12
-
13
- // src/cli/task.ts
14
- import { randomUUID } from "crypto";
15
- var TASK_USAGE = `ledge task give <nom|@r\xF4le> "<titre>" ["<d\xE9tail>"] confier un travail \xE0 une session (@r\xF4le : dans ton \xE9quipe)
16
- ledge task give ledge "<question>" "<options, recommandation>" une d\xE9cision pour l'utilisateur ; sa r\xE9ponse te r\xE9veille
17
- ledge task list [--all] tes t\xE2ches (tenues ou confi\xE9es), ouvertes ; --all : closes aussi
18
- ledge task show <id> une t\xE2che, son d\xE9tail et son historique
19
- ledge task take <id> la prendre
20
- ledge task done <id> "<r\xE9sultat>" la terminer, avec ce qui en est sorti (la session qui l'a confi\xE9e est pr\xE9venue)
21
- ledge task refuse <id> "<raison>" la refuser, ou l'annuler si tu l'as confi\xE9e
22
- ledge task pass <id> <nom|@r\xF4le> ["<note>"] la passer \xE0 une autre session`;
23
- var TASK_MS = 4e3;
24
- var ID = /^t[0-9a-f]{6}$/;
25
- function taskArgs(args) {
26
- const [op, ...rest] = args;
27
- const id = rest[0] && ID.test(rest[0]) ? rest[0] : void 0;
28
- const fits = (min, max) => rest.length >= min && rest.length <= max && rest.slice(0, min).every((a) => a.trim() !== "");
29
- switch (op) {
30
- case "give":
31
- return fits(2, 3) && rest[1].length <= TASK_TITLE_MAX && (rest[2]?.length ?? 0) <= TASK_TEXT_MAX ? { op, to: rest[0], title: rest[1], ...rest[2] ? { text: rest[2] } : {} } : void 0;
32
- case "list":
33
- return rest.length === 0 ? { op } : rest.length === 1 && rest[0] === "--all" ? { op, all: true } : void 0;
34
- case "show":
35
- case "take":
36
- return fits(1, 1) && id ? { op, task: id } : void 0;
37
- case "done":
38
- return fits(2, 2) && id && rest[1].length <= TASK_TEXT_MAX ? { op, task: id, text: rest[1] } : void 0;
39
- case "refuse":
40
- return fits(2, 2) && id && rest[1].length <= TASK_TEXT_MAX ? { op, task: id, text: rest[1] } : void 0;
41
- case "pass":
42
- return fits(2, 3) && id && (rest[2]?.length ?? 0) <= TASK_TEXT_MAX ? { op, task: id, to: rest[1], ...rest[2] ? { text: rest[2] } : {} } : void 0;
43
- default:
44
- return void 0;
45
- }
46
- }
47
- var STATE = { open: "\xE0 prendre", taken: "prise", done: "termin\xE9e", refused: "refus\xE9e", dropped: "abandonn\xE9e" };
48
- var time = (iso) => iso.slice(0, 16).replace("T", " ");
49
- function formatTask(t) {
50
- return [
51
- `${t.id} \xB7 ${STATE[t.state]} \xB7 de ${t.giverName} \xE0 ${t.ownerName} \xB7 ${time(t.at)}`,
52
- t.title,
53
- ...t.text ? ["", t.text] : [],
54
- ...t.result ? ["", `${t.state === "done" ? "R\xE9sultat" : "Raison"} : ${t.result}`] : [],
55
- "",
56
- "Historique :",
57
- ...t.log.map((l) => ` ${time(l.at)} ${l.by} : ${l.what}`)
58
- ].join("\n");
59
- }
60
- async function taskOnClient(client, args, by, ms) {
61
- const op = taskArgs(args);
62
- if (!op) return { line: TASK_USAGE, code: 1 };
63
- if (by === LEDGE_GIVER) return { line: "refus\xE9 : seul Ledge confie une t\xE2che en son nom", code: 1 };
64
- try {
65
- client.send({ type: "task.cmd", rid: randomUUID(), by, ...op });
66
- const r = await client.next("task.result", ms);
67
- if (r.reason !== void 0) return { line: `refus\xE9 : ${r.reason}`, code: 1 };
68
- if (op.op === "list") {
69
- const list = r.tasks ?? [];
70
- if (!list.length) return { line: op.all ? "aucune t\xE2che" : "aucune t\xE2che ouverte", code: 0 };
71
- return { line: list.map((t2) => `${t2.id} ${STATE[t2.state].padEnd(10)} ${t2.giverName} \u2192 ${t2.ownerName} ${t2.title}`).join("\n"), code: 0 };
72
- }
73
- const t = r.task;
74
- switch (op.op) {
75
- case "give":
76
- return { line: t.owner === LEDGE_GIVER ? `d\xE9cision ${t.id} pos\xE9e \xE0 l'utilisateur (ledge decide) : sa r\xE9ponse t'arrivera comme une t\xE2che termin\xE9e` : `t\xE2che ${t.id} confi\xE9e \xE0 ${t.ownerName} : elle lui arrive \xE0 son prochain moment libre`, code: 0 };
77
- case "take":
78
- return { line: `t\xE2che ${t.id} prise`, code: 0 };
79
- case "done":
80
- return { line: `t\xE2che ${t.id} termin\xE9e ; Ledge pr\xE9vient ${t.giverName}`, code: 0 };
81
- case "refuse":
82
- return { line: t.giver === by ? `t\xE2che ${t.id} annul\xE9e ; Ledge pr\xE9vient ${t.ownerName}` : `t\xE2che ${t.id} refus\xE9e ; Ledge pr\xE9vient ${t.giverName}`, code: 0 };
83
- case "pass":
84
- return { line: `t\xE2che ${t.id} pass\xE9e \xE0 ${t.ownerName}`, code: 0 };
85
- default:
86
- return { line: formatTask(t), code: 0 };
87
- }
88
- } catch (e) {
89
- return { line: `pas de r\xE9ponse de Ledge : ${e.message}`, code: 1 };
90
- }
91
- }
92
- async function runTask(args, opts = {}) {
93
- if (!taskArgs(args)) return { line: TASK_USAGE, code: args.length ? 1 : 0 };
94
- const env = opts.env ?? process.env;
95
- const by = env[CODEX_HOOK_VAR] || env.LEDGE_SESSION;
96
- if (!by) return { line: "ledge task ne marche que dans une session lanc\xE9e par Ledge", code: 1 };
97
- const deadline = Date.now() + (opts.timeoutMs ?? TASK_MS);
98
- const left = () => Math.max(0, deadline - Date.now());
99
- let client;
100
- try {
101
- client = await connect({ port: opts.port, timeoutMs: left() });
102
- } catch {
103
- return { line: "daemon not running (start a session with `ledge claude`, or run `ledge daemon`)", code: 1 };
104
- }
105
- try {
106
- return await taskOnClient(client, args, by, left());
107
- } finally {
108
- await client.close();
109
- }
110
- }
111
-
112
- export {
113
- TASK_USAGE,
114
- taskArgs,
115
- formatTask,
116
- taskOnClient,
117
- runTask
118
- };
@@ -1,159 +0,0 @@
1
- import {
2
- ROLE_LABEL_MAX,
3
- ROLE_PROMPT_MAX,
4
- RoleSchema
5
- } from "./chunk-37G5F75H.js";
6
- import {
7
- log
8
- } from "./chunk-6IYPRUQG.js";
9
- import {
10
- ledgeDir
11
- } from "./chunk-HOOHS3MX.js";
12
-
13
- // src/daemon/roles.ts
14
- import { createHash } from "crypto";
15
- import { existsSync, readdirSync, readFileSync, statSync } from "fs";
16
- import { dirname, join, resolve } from "path";
17
- var FILE_MAX = 64 * 1024;
18
- function repoRoot(cwd) {
19
- const start = resolve(cwd);
20
- for (let dir = start; ; dir = dirname(dir)) {
21
- if (existsSync(join(dir, ".git"))) return dir;
22
- if (dirname(dir) === dir) return start;
23
- }
24
- }
25
- function definitionDirs(kind, cwd) {
26
- const home = join(ledgeDir(), kind);
27
- const repo = cwd ? join(repoRoot(cwd), ".ledge", kind) : void 0;
28
- return [...repo && resolve(repo) !== resolve(home) ? [{ dir: repo, source: "repo" }] : [], { dir: home, source: "home" }];
29
- }
30
- function definitionFiles(dir, ext) {
31
- let names;
32
- try {
33
- names = readdirSync(dir);
34
- } catch {
35
- return [];
36
- }
37
- return names.filter((n) => ext.some((e) => n.endsWith(e)) && !n.startsWith(".")).sort().map((n) => join(dir, n)).filter((p) => {
38
- try {
39
- return statSync(p).isFile();
40
- } catch {
41
- return false;
42
- }
43
- });
44
- }
45
- function readSmall(path) {
46
- if (statSync(path).size > FILE_MAX) throw new Error(`file over ${FILE_MAX / 1024} KB`);
47
- return readFileSync(path, "utf8");
48
- }
49
- function frontMatter(text) {
50
- const src = text.replace(/^/, "").replace(/\r\n/g, "\n");
51
- const m = /^---\n([\s\S]*?)\n---[ \t]*(?:\n|$)/.exec(src);
52
- if (!m) return { fields: {}, body: src.trim() };
53
- const fields = {};
54
- for (const raw of m[1].split("\n")) {
55
- const line = raw.trim();
56
- if (!line || line.startsWith("#")) continue;
57
- const i = line.indexOf(":");
58
- if (i <= 0) throw new Error(`front matter line without a key: ${line.replace(/\s+#.*$/, "").slice(0, 60)}`);
59
- fields[line.slice(0, i).trim()] = scalarValue(line.slice(i + 1));
60
- }
61
- return { fields, body: src.slice(m[0].length).trim() };
62
- }
63
- function scalarValue(raw) {
64
- const v = raw.trim();
65
- const q = v[0];
66
- if (q === '"' || q === "'") {
67
- const end = v.indexOf(q, 1);
68
- if (end > 0 && /^(\s+#.*)?$/.test(v.slice(end + 1))) return v.slice(1, end);
69
- }
70
- return unquote(v.replace(/(^|\s)#.*$/, "").trim());
71
- }
72
- function quoteScalar(v) {
73
- if (/[\r\n]/.test(v)) return null;
74
- if (/^[\w./@:+-]+$/.test(v) && !/^(true|false|null|yes|no|~)$/i.test(v)) return v;
75
- if (!v.includes('"')) return `"${v}"`;
76
- if (!v.includes("'")) return `'${v}'`;
77
- return null;
78
- }
79
- var definitionHash = (text) => createHash("sha256").update(text).digest("hex").slice(0, 16);
80
- var unquote = (v) => v.length >= 2 && (v[0] === '"' || v[0] === "'") && v.at(-1) === v[0] ? v.slice(1, -1) : v;
81
- var ROLE_KEYS = /* @__PURE__ */ new Set(["label", "tool", "model", "effort", "autonomy"]);
82
- function parseRole(id, text, source, path) {
83
- let parsed;
84
- try {
85
- parsed = frontMatter(text);
86
- } catch (e) {
87
- return e.message;
88
- }
89
- const { fields, body } = parsed;
90
- const unknown = Object.keys(fields).find((k) => !ROLE_KEYS.has(k));
91
- if (unknown) return `unknown key ${unknown}`;
92
- if (body.length > ROLE_PROMPT_MAX) return `prompt over ${ROLE_PROMPT_MAX} characters`;
93
- const label = (fields.label ?? id).slice(0, ROLE_LABEL_MAX);
94
- const r = RoleSchema.safeParse({
95
- id,
96
- label,
97
- prompt: body,
98
- source,
99
- path,
100
- ...fields.tool ? { tool: fields.tool } : {},
101
- ...fields.model ? { model: fields.model } : {},
102
- ...fields.effort ? { effort: fields.effort } : {},
103
- ...fields.autonomy ? { autonomy: fields.autonomy } : {}
104
- });
105
- if (!r.success) {
106
- const issue = r.error.issues[0];
107
- return `${issue.path.join(".") || "role"}: ${issue.message}`;
108
- }
109
- return r.data;
110
- }
111
- function loadRole(id, path, source, problems) {
112
- let r;
113
- try {
114
- const text = readSmall(path);
115
- r = parseRole(id, text, source, path);
116
- if (typeof r !== "string") r = { ...r, hash: definitionHash(text) };
117
- } catch (e) {
118
- r = e.message;
119
- }
120
- if (typeof r === "string") {
121
- log(`role ${path} skipped: ${r}`);
122
- problems.push({ path, reason: r });
123
- return void 0;
124
- }
125
- return r;
126
- }
127
- function listRoles(cwd) {
128
- const roles = /* @__PURE__ */ new Map();
129
- const problems = [];
130
- for (const { dir, source } of definitionDirs("roles", cwd)) {
131
- for (const path of definitionFiles(dir, [".md"])) {
132
- const id = path.slice(dir.length + 1, -".md".length);
133
- const won = roles.get(id);
134
- if (won) {
135
- if (source === "home") roles.set(id, { ...won, shadows: path });
136
- continue;
137
- }
138
- const r = loadRole(id, path, source, problems);
139
- if (r) roles.set(id, r);
140
- }
141
- }
142
- return { roles: [...roles.values()].sort((a, b) => a.id.localeCompare(b.id)), problems };
143
- }
144
- function findRole(id, cwd) {
145
- return listRoles(cwd).roles.find((r) => r.id === id);
146
- }
147
-
148
- export {
149
- repoRoot,
150
- definitionDirs,
151
- definitionFiles,
152
- readSmall,
153
- scalarValue,
154
- quoteScalar,
155
- definitionHash,
156
- loadRole,
157
- listRoles,
158
- findRole
159
- };
@@ -1,198 +0,0 @@
1
- import {
2
- definitionDirs,
3
- definitionFiles,
4
- definitionHash,
5
- listRoles,
6
- quoteScalar,
7
- readSmall,
8
- scalarValue
9
- } from "./chunk-UPKJO3BZ.js";
10
- import {
11
- SeatsSchema,
12
- TeamNameSchema
13
- } from "./chunk-37G5F75H.js";
14
- import {
15
- log
16
- } from "./chunk-6IYPRUQG.js";
17
- import {
18
- ledgeDir
19
- } from "./chunk-HOOHS3MX.js";
20
-
21
- // src/daemon/teams.ts
22
- import { existsSync, writeFileSync, mkdirSync, renameSync } from "fs";
23
- import { join } from "path";
24
- var scalar = scalarValue;
25
- function flowMap(raw) {
26
- const inner = raw.trim().replace(/^\{/, "").replace(/\}$/, "");
27
- const out = {};
28
- for (const part of inner.split(",")) {
29
- if (!part.trim()) continue;
30
- const i = part.indexOf(":");
31
- if (i <= 0) throw new Error(`not a key: value pair: ${part.trim().slice(0, 40)}`);
32
- out[part.slice(0, i).trim()] = scalar(part.slice(i + 1));
33
- }
34
- return out;
35
- }
36
- function parseTemplateText(text) {
37
- const src = text.replace(/^/, "").replace(/\r\n/g, "\n");
38
- if (src.trimStart().startsWith("{")) return JSON.parse(src);
39
- const out = {};
40
- let list = null;
41
- let item = null;
42
- let itemIndent = -1;
43
- for (const raw of src.split("\n")) {
44
- if (!raw.trim() || raw.trimStart().startsWith("#")) continue;
45
- if (raw.includes(" ")) throw new Error("tabs are not allowed in YAML");
46
- const indent = raw.length - raw.trimStart().length;
47
- const line = raw.trim();
48
- if (indent === 0 && !line.startsWith("- ")) {
49
- item = null;
50
- list = null;
51
- const i2 = line.indexOf(":");
52
- if (i2 <= 0) throw new Error(`line without a key: ${line.slice(0, 60)}`);
53
- const key = line.slice(0, i2).trim();
54
- const rest = line.slice(i2 + 1).trim();
55
- if (rest === "") {
56
- list = [];
57
- out[key] = list;
58
- } else if (rest.startsWith("[")) out[key] = rest.replace(/^\[|\]$/g, "").split(",").map(scalar).filter(Boolean);
59
- else out[key] = scalar(rest);
60
- continue;
61
- }
62
- if (!list) throw new Error(`indented line outside a list: ${line.slice(0, 60)}`);
63
- if (line.startsWith("- ") || line === "-") {
64
- const rest = line.slice(1).trim();
65
- if (rest.startsWith("{")) {
66
- list.push(flowMap(rest));
67
- item = null;
68
- continue;
69
- }
70
- item = {};
71
- itemIndent = indent;
72
- list.push(item);
73
- if (rest) {
74
- const i2 = rest.indexOf(":");
75
- if (i2 <= 0) {
76
- list[list.length - 1] = scalar(rest);
77
- item = null;
78
- continue;
79
- }
80
- item[rest.slice(0, i2).trim()] = scalar(rest.slice(i2 + 1));
81
- }
82
- continue;
83
- }
84
- if (!item || indent <= itemIndent) throw new Error(`line outside a seat: ${line.slice(0, 60)}`);
85
- const i = line.indexOf(":");
86
- if (i <= 0) throw new Error(`line without a key: ${line.slice(0, 60)}`);
87
- item[line.slice(0, i).trim()] = scalar(line.slice(i + 1));
88
- }
89
- return out;
90
- }
91
- function parseTemplate(id, text, source, path) {
92
- let raw;
93
- try {
94
- raw = parseTemplateText(text);
95
- } catch (e) {
96
- return e.message;
97
- }
98
- const name = TeamNameSchema.safeParse(typeof raw.name === "string" ? raw.name : id);
99
- if (!name.success) return "name: a name of 1 to 60 characters";
100
- const seats = SeatsSchema.safeParse(raw.seats);
101
- if (!seats.success) {
102
- const issue = seats.error.issues[0];
103
- return `seats${issue.path.length ? `.${issue.path.join(".")}` : ""}: ${issue.message}`;
104
- }
105
- return { id, name: name.data, seats: seats.data, source, path };
106
- }
107
- function loadTemplate(id, path, source, problems) {
108
- let t;
109
- try {
110
- const text = readSmall(path);
111
- t = parseTemplate(id, text, source, path);
112
- if (typeof t !== "string") t = { ...t, hash: definitionHash(text) };
113
- } catch (e) {
114
- t = e.message;
115
- }
116
- if (typeof t === "string") {
117
- log(`team ${path} skipped: ${t}`);
118
- problems.push({ path, reason: t });
119
- return void 0;
120
- }
121
- return t;
122
- }
123
- function listTemplates(cwd) {
124
- const templates = /* @__PURE__ */ new Map();
125
- const problems = [];
126
- for (const { dir, source } of definitionDirs("teams", cwd)) {
127
- for (const path of definitionFiles(dir, [".yaml", ".yml"])) {
128
- const id = path.slice(dir.length + 1).replace(/\.ya?ml$/, "");
129
- if (templates.has(id)) continue;
130
- const t = loadTemplate(id, path, source, problems);
131
- if (t) templates.set(id, t);
132
- }
133
- }
134
- return { templates: [...templates.values()].sort((a, b) => a.id.localeCompare(b.id)), problems };
135
- }
136
- function resolveSeats(seats, roles, defaults = { tool: "claude" }) {
137
- const byId = new Map(roles.map((r) => [r.id, r]));
138
- const unknown = seats.filter((s) => !byId.has(s.role)).map((s) => s.role);
139
- if (unknown.length) return { unknown };
140
- return seats.map((s) => {
141
- const role = byId.get(s.role);
142
- const tool = s.tool ?? role.tool ?? defaults.tool;
143
- const own = s.tool === void 0 || s.tool === role.tool;
144
- const model = s.model ?? (own ? role.model : void 0) ?? (tool === defaults.tool ? defaults.model : void 0);
145
- const effort = s.effort ?? (own ? role.effort : void 0) ?? (tool === defaults.tool ? defaults.effort : void 0);
146
- return { role, tool, ...model ? { model } : {}, ...effort ? { effort } : {}, ...s.name ? { name: s.name } : {} };
147
- });
148
- }
149
- function listDefinitions(cwd) {
150
- const r = listRoles(cwd);
151
- const t = listTemplates(cwd);
152
- return { roles: r.roles, templates: t.templates, problems: [...r.problems, ...t.problems] };
153
- }
154
- function templateId(name) {
155
- const id = name.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
156
- return id || "team";
157
- }
158
- var SEAT_KEYS = ["role", "tool", "model", "effort", "name"];
159
- function templateText(name, seats) {
160
- const q = (v) => v.includes(" ") ? null : quoteScalar(v);
161
- const head = q(name);
162
- if (head === null) return null;
163
- const lines = [`name: ${head}`, "seats:"];
164
- for (const s of seats) {
165
- let first = true;
166
- for (const k of SEAT_KEYS) {
167
- if (s[k] === void 0) continue;
168
- const v = q(String(s[k]));
169
- if (v === null) return null;
170
- lines.push(`${first ? " - " : " "}${k}: ${v}`);
171
- first = false;
172
- }
173
- }
174
- return `${lines.join("\n")}
175
- `;
176
- }
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")) {
180
- const path = templatePath(name, dir);
181
- const text = templateText(name, seats);
182
- 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;
188
- }
189
-
190
- export {
191
- loadTemplate,
192
- resolveSeats,
193
- listDefinitions,
194
- templateId,
195
- templateText,
196
- templateExists,
197
- saveTemplate
198
- };