@dendelion/paper-camp 0.35.1 → 0.37.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.
@@ -1,2996 +0,0 @@
1
- import { readFile as v, mkdir as A, writeFile as E, readdir as z, stat as Tt, rename as Nt, access as Ct } from "node:fs/promises";
2
- import { dirname as O, join as f, basename as _t } from "node:path";
3
- import { parse as K, stringify as xt } from "yaml";
4
- import { spawn as b } from "node:child_process";
5
- import { AGENT_IDS as D, NIGHT_CHECK_IDS as Ot, NOTIFICATION_SETTING_KINDS as Dt, PLAN_KINDS as Mt } from "../types/index.js";
6
- import { createHash as jt } from "node:crypto";
7
- import { existsSync as se, readFileSync as De } from "node:fs";
8
- import { fileURLToPath as Lt } from "node:url";
9
- import { z as Ft, A as Ht, e as Gt, n as Bt, a as Yt, u as qt } from "./daemon-state.BeDnhzBY.js";
10
- import { z as d } from "zod";
11
- const Ut = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;
12
- function zt(e) {
13
- return e.length >= 2 && (e.startsWith('"') && e.endsWith('"') || e.startsWith("'") && e.endsWith("'")) ? e.slice(1, -1) : e;
14
- }
15
- function ke(e) {
16
- return e === "" || /[\s#"]/.test(e) ? `"${e.replace(/"/g, '\\"')}"` : e;
17
- }
18
- function Me(e) {
19
- const t = e.trim();
20
- if (!t || t.startsWith("#")) return null;
21
- const n = t.match(Ut);
22
- return n ? { key: n[1], value: zt(n[2]) } : null;
23
- }
24
- function ti(e) {
25
- const t = [];
26
- for (const n of e.split(`
27
- `)) {
28
- const s = Me(n);
29
- s && t.push(s);
30
- }
31
- return t;
32
- }
33
- function ni(e, t) {
34
- const n = new Map(t.map((i) => [i.key, i.value])), s = e.length > 0 ? e.split(`
35
- `) : [], a = [];
36
- for (const i of s) {
37
- const r = Me(i);
38
- if (!r) {
39
- a.push(i);
40
- continue;
41
- }
42
- n.has(r.key) && (a.push(`${r.key}=${ke(n.get(r.key) ?? "")}`), n.delete(r.key));
43
- }
44
- for (const [i, r] of n)
45
- a.push(`${i}=${ke(r)}`);
46
- for (; a.length > 0 && a[a.length - 1] === ""; ) a.pop();
47
- return a.length > 0 ? `${a.join(`
48
- `)}
49
- ` : "";
50
- }
51
- function si(e) {
52
- return e.archived === !0 || e.status === "done";
53
- }
54
- function X(e) {
55
- const t = e.phases.length > 0 && e.phases.every((s) => s.done), n = (e.fixes ?? []).every((s) => s.done);
56
- return t && n;
57
- }
58
- function W(e, t, n, s = !1) {
59
- return e.kind === "note" || e.status === "dropped" ? e.status : e.archived ? "done" : t ? t.state === "merged" ? X(e) ? "done" : "planned" : t.state === "closed" ? "dropped" : X(e) ? "review" : "in-progress" : n ? e.status === "review" || e.status === "done" ? e.status : s && e.phases.length > 0 ? X(e) ? "review" : "in-progress" : e.phases.length > 0 ? "planned" : "idea" : e.status ?? (e.phases.length > 0 ? "planned" : "idea");
60
- }
61
- function Kt(e, t, n) {
62
- return e.kind === "note" || e.kind === "board" || e.status === "dropped" || e.archived || t ? !1 : !n;
63
- }
64
- function Wt(e, t) {
65
- if (e.kind === "note" || e.archived || (t == null ? void 0 : t.state) !== "merged") return !1;
66
- const n = W(e, t, !0);
67
- return n === "review" || n === "done";
68
- }
69
- function je(e) {
70
- return e.length === 0 ? "idea" : e.every((t) => t === "done" || t === "dropped") ? "review" : e.some((t) => t !== "idea" && t !== "planned") ? "in-progress" : "planned";
71
- }
72
- function Jt(e = [], t = [], n = [], s = []) {
73
- const a = [
74
- ...e.map((r) => ({ kind: "log", date: r.date, text: r.text })),
75
- ...t.map((r) => ({ kind: "clarification", date: r.date, text: r.text })),
76
- ...s.map((r) => ({ kind: "review", date: r.date, text: r.text }))
77
- ].sort((r, o) => r.date.localeCompare(o.date)), i = n.map((r) => ({
78
- kind: r.kind ?? "note",
79
- text: r.anchor.kind === "phase" ? `[phase ${r.anchor.index}] ${r.prose}` : r.prose,
80
- state: r.state
81
- }));
82
- return [...a, ...i];
83
- }
84
- function ae(e, t) {
85
- return e.filter((n) => n.kind === t).map((n) => ({ date: n.date ?? "", text: n.text }));
86
- }
87
- function Le(e = []) {
88
- return ae(e, "log");
89
- }
90
- function Vt(e = []) {
91
- return ae(e, "clarification");
92
- }
93
- function Xt(e = []) {
94
- return ae(e, "review");
95
- }
96
- function Zt(e = []) {
97
- return e.filter(
98
- (t) => t.kind === "note" || t.kind === "decision" || t.kind === "question"
99
- ).map((t) => ({
100
- anchor: { kind: "body" },
101
- prose: t.text,
102
- state: t.state ?? "open",
103
- kind: t.kind
104
- }));
105
- }
106
- function ai(e, t, n) {
107
- return [...(e ?? []).filter((s) => !t.includes(s.kind)), ...n];
108
- }
109
- function ii(e, t, n, s) {
110
- return e.map((a, i) => {
111
- if (i !== t) return a;
112
- const r = s ? `${a.text}
113
-
114
- ${s}` : a.text;
115
- if (n === "decision") return { ...a, kind: n, state: "open", text: r };
116
- const { state: o, ...c } = a;
117
- return { ...c, kind: n, text: r };
118
- });
119
- }
120
- function ri(e = []) {
121
- const t = e.reduce((n, s, a) => s.kind === "log" ? a : n, -1);
122
- return e.slice(t + 1).filter((n) => n.kind === "chat");
123
- }
124
- function Fe(e, t, n = !1, s = !1) {
125
- return {
126
- title: e.title,
127
- // Non-note entities can't carry the note-only 'open' (schema-enforced).
128
- status: W(e, t, n, s),
129
- statusFallback: Kt(e, t, n),
130
- kind: e.type,
131
- entityKind: e.kind === "note" ? void 0 : e.kind,
132
- id: e.id,
133
- idea: e.idea,
134
- agent: e.agent,
135
- created: e.created,
136
- updated: e.updated,
137
- audited: e.audited,
138
- auditedHash: e.auditedHash,
139
- released: e.released,
140
- tags: e.tags,
141
- subject: e.subject,
142
- order: e.order,
143
- issueSource: e.issueSource,
144
- body: e.body,
145
- phases: e.phases,
146
- fixes: e.fixes,
147
- log: Le(e.thread),
148
- clarifications: Vt(e.thread),
149
- notes: Zt(e.thread),
150
- review: Xt(e.thread),
151
- thread: e.thread,
152
- archived: e.archived,
153
- pr: t
154
- };
155
- }
156
- function Qt(e) {
157
- return {
158
- id: e.id,
159
- title: e.title,
160
- body: e.body,
161
- kind: "note",
162
- status: e.status,
163
- subject: e.subject,
164
- order: e.order,
165
- created: e.created,
166
- log: Le(e.thread)
167
- };
168
- }
169
- const en = /^[0-9a-f]{4,40}$/i, tn = /^Merge pull request #\d+ from \S+\/([a-z]+-\d+)-/i;
170
- function C(e, t) {
171
- return new Promise((n) => {
172
- var i;
173
- const s = b("git", t, { cwd: e, stdio: ["ignore", "pipe", "ignore"] });
174
- let a = "";
175
- (i = s.stdout) == null || i.on("data", (r) => {
176
- a += r.toString();
177
- }), s.on("close", () => n(a)), s.on("error", () => n(""));
178
- });
179
- }
180
- async function He(e) {
181
- var n;
182
- return ((n = (await C(e, ["symbolic-ref", "refs/remotes/origin/HEAD"])).trim().match(/refs\/remotes\/origin\/(.+)/)) == null ? void 0 : n[1]) ?? "main";
183
- }
184
- function Q(e) {
185
- const t = e.match(/^Refs:\s*([A-Za-z]+-\d+)\s*$/m);
186
- if (t) return t[1].toUpperCase();
187
- const n = e.split(`
188
- `, 1)[0], s = n.match(/\(([A-Za-z]+-\d+)\)/);
189
- if (s) return s[1].toUpperCase();
190
- const a = n.match(tn);
191
- return a ? a[1].toUpperCase() : null;
192
- }
193
- function nn(e) {
194
- return e.length > 0 && e.every((t) => t.startsWith("papercamp/"));
195
- }
196
- async function Ge(e) {
197
- const t = await He(e), n = await C(e, ["log", "--format=%x02%B%x00", "--name-only", t]), s = /* @__PURE__ */ new Set();
198
- for (const a of n.split("")) {
199
- if (!a) continue;
200
- const [i, r = ""] = a.split("\0"), o = r.split(`
201
- `).map((u) => u.trim()).filter(Boolean);
202
- if (nn(o)) continue;
203
- const c = Q(i.trim());
204
- c && s.add(c);
205
- }
206
- return s;
207
- }
208
- const k = /* @__PURE__ */ new Map(), sn = 5 * 60 * 1e3, ie = (e) => f(e, "papercamp", "pr-map.json");
209
- async function an(e, t, n) {
210
- const s = ie(e);
211
- try {
212
- const a = { fetchedAt: n, prs: Object.fromEntries(t) };
213
- await A(O(s), { recursive: !0 }), await E(s, `${JSON.stringify(a, null, 2)}
214
- `, "utf-8");
215
- } catch (a) {
216
- console.error(`papercamp: could not persist PR map for ${e}:`, a);
217
- }
218
- }
219
- async function Be(e) {
220
- try {
221
- const t = await v(ie(e), "utf-8"), n = JSON.parse(t);
222
- return { prs: new Map(Object.entries(n.prs)), fetchedAt: n.fetchedAt };
223
- } catch {
224
- return;
225
- }
226
- }
227
- const rn = {
228
- APPROVED: "approved",
229
- CHANGES_REQUESTED: "changes-requested",
230
- REVIEW_REQUIRED: "review-required"
231
- };
232
- function on(e) {
233
- const t = e.state === "MERGED" ? "merged" : e.state === "CLOSED" ? "closed" : e.isDraft ? "draft" : "open", n = rn[e.reviewDecision];
234
- return {
235
- number: e.number,
236
- url: e.url,
237
- state: t,
238
- ...n && { reviewDecision: n },
239
- ...e.headRefOid && { headSha: e.headRefOid },
240
- ...e.headRefName && { headBranch: e.headRefName }
241
- };
242
- }
243
- const Se = { merged: 4, open: 3, draft: 2, closed: 1 };
244
- function Ye(e, t) {
245
- const n = e == null ? void 0 : e.match(/\*\*Plan:\*\*\s*`?([A-Za-z]+-\d+)`?/);
246
- if (n) return n[1].toUpperCase();
247
- const s = t == null ? void 0 : t.match(/^[a-z]+\/([a-z]+-\d+)-/);
248
- return s ? s[1].toUpperCase() : null;
249
- }
250
- const cn = `
251
- query($owner: String!, $repo: String!, $number: Int!) {
252
- repository(owner: $owner, name: $repo) {
253
- pullRequest(number: $number) {
254
- reviewThreads(first: 100) { nodes { isResolved } }
255
- commits(last: 1) { nodes { commit { committedDate } } }
256
- comments(last: 1) { nodes { createdAt } }
257
- reviews(last: 20) { nodes { createdAt body } }
258
- }
259
- }
260
- }`;
261
- function dn(e, t) {
262
- return `Paper Scout · ${e} · ${t.slice(0, 7)}`;
263
- }
264
- function M(e) {
265
- const t = e.match(/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/);
266
- if (!t) return null;
267
- const [, n, s, a] = t;
268
- return { owner: n, repo: s, number: a };
269
- }
270
- const un = 15e3;
271
- function qe(e, t) {
272
- return new Promise((n) => {
273
- var c, u;
274
- const s = b("gh", t, { cwd: e, stdio: ["ignore", "pipe", "pipe"] });
275
- let a = !1;
276
- const i = (l) => {
277
- a || (a = !0, clearTimeout(r), l());
278
- }, r = setTimeout(() => {
279
- s.kill(), i(() => n(void 0));
280
- }, un);
281
- let o = "";
282
- (c = s.stdout) == null || c.on("data", (l) => {
283
- o += l.toString();
284
- }), (u = s.stderr) == null || u.on("data", () => {
285
- }), s.on("close", (l) => {
286
- i(() => {
287
- if (l !== 0) {
288
- n(void 0);
289
- return;
290
- }
291
- try {
292
- n(JSON.parse(o));
293
- } catch {
294
- n(void 0);
295
- }
296
- });
297
- }), s.on("error", () => i(() => n(void 0)));
298
- });
299
- }
300
- function Ue(e, t, n, s, a) {
301
- return Ke(e, [
302
- "-f",
303
- `query=${t}`,
304
- "-f",
305
- `owner=${n}`,
306
- "-f",
307
- `repo=${s}`,
308
- "-F",
309
- `number=${a}`
310
- ]);
311
- }
312
- function ze(e, t, n) {
313
- const s = ["-f", `query=${t}`];
314
- for (const [a, i] of Object.entries(n))
315
- s.push("-f", `${a}=${i}`);
316
- return Ke(e, s);
317
- }
318
- function Ke(e, t) {
319
- return qe(e, ["api", "graphql", ...t]);
320
- }
321
- async function ln(e, t) {
322
- var l, p, h, w, g;
323
- const n = M(t);
324
- if (!n) return;
325
- const s = await Ue(e, cn, n.owner, n.repo, n.number), a = (p = (l = s == null ? void 0 : s.data) == null ? void 0 : l.repository) == null ? void 0 : p.pullRequest;
326
- if (!a) return;
327
- const i = a.reviewThreads.nodes.filter((m) => !m.isResolved).length, r = (h = a.commits.nodes[0]) == null ? void 0 : h.commit.committedDate, o = [(w = a.comments.nodes[0]) == null ? void 0 : w.createdAt, (g = a.reviews.nodes.at(-1)) == null ? void 0 : g.createdAt].filter((m) => !!m).sort().at(-1), c = !!(r && o && o > r), u = a.reviews.nodes.map((m) => m.body);
328
- return { unresolvedThreadCount: i, hasNewCommentsSincePush: c, reviewBodies: u };
329
- }
330
- const fn = `
331
- query($owner: String!, $repo: String!, $number: Int!) {
332
- repository(owner: $owner, name: $repo) {
333
- pullRequest(number: $number) {
334
- reviewThreads(first: 100) {
335
- nodes {
336
- id
337
- isResolved
338
- comments(first: 1) { nodes { path line body author { login } } }
339
- }
340
- }
341
- }
342
- }
343
- }`;
344
- async function oi(e, t) {
345
- var i, r, o;
346
- const n = M(t);
347
- if (!n) return [];
348
- const s = await Ue(e, fn, n.owner, n.repo, n.number);
349
- return (((o = (r = (i = s == null ? void 0 : s.data) == null ? void 0 : i.repository) == null ? void 0 : r.pullRequest) == null ? void 0 : o.reviewThreads.nodes) ?? []).filter((c) => !c.isResolved).map((c) => ({ id: c.id, comment: c.comments.nodes[0] })).filter((c) => !!c.comment).map(({ id: c, comment: u }) => {
350
- var l;
351
- return {
352
- id: c,
353
- ...u.path ? { path: u.path } : {},
354
- ...u.line != null ? { line: u.line } : {},
355
- ...(l = u.author) != null && l.login ? { author: u.author.login } : {},
356
- body: u.body
357
- };
358
- });
359
- }
360
- const pn = `
361
- mutation($threadId: ID!) {
362
- resolveReviewThread(input: { threadId: $threadId }) {
363
- thread { id isResolved }
364
- }
365
- }`, hn = `
366
- mutation($threadId: ID!, $body: String!) {
367
- addPullRequestReviewThreadReply(input: { pullRequestReviewThreadId: $threadId, body: $body }) {
368
- comment { id }
369
- }
370
- }`;
371
- async function ci(e, t) {
372
- var s, a, i;
373
- const n = await ze(e, pn, { threadId: t });
374
- return !!((i = (a = (s = n == null ? void 0 : n.data) == null ? void 0 : s.resolveReviewThread) == null ? void 0 : a.thread) != null && i.isResolved);
375
- }
376
- async function di(e, t, n) {
377
- var a, i, r;
378
- const s = await ze(e, hn, { threadId: t, body: n });
379
- return !!((r = (i = (a = s == null ? void 0 : s.data) == null ? void 0 : a.addPullRequestReviewThreadReply) == null ? void 0 : i.comment) != null && r.id);
380
- }
381
- function We(e, t, n) {
382
- return new Promise((s) => {
383
- var r, o, c;
384
- const a = b("gh", ["api", t, "-X", "POST", "--input", "-"], {
385
- cwd: e,
386
- stdio: ["pipe", "ignore", "pipe"]
387
- });
388
- let i = "";
389
- (r = a.stderr) == null || r.on("data", (u) => {
390
- i += u;
391
- }), a.on(
392
- "close",
393
- (u) => s(u === 0 ? { delivered: !0 } : { delivered: !1, body: i.trim() })
394
- ), a.on("error", (u) => s({ delivered: !1, body: u.message })), (o = a.stdin) == null || o.on("error", () => {
395
- }), (c = a.stdin) == null || c.end(JSON.stringify(n));
396
- });
397
- }
398
- async function ui(e, t, n) {
399
- const s = M(t);
400
- return s ? We(
401
- e,
402
- `repos/${s.owner}/${s.repo}/pulls/${s.number}/reviews`,
403
- n
404
- ) : { delivered: !1 };
405
- }
406
- async function li(e, t, n) {
407
- const s = M(t);
408
- return s ? We(e, `repos/${s.owner}/${s.repo}/dispatches`, {
409
- event_type: "paper-camp-review",
410
- client_payload: { review: { number: Number(s.number), ...n } }
411
- }) : { delivered: !1 };
412
- }
413
- async function mn(e, t) {
414
- const n = [...t.entries()].filter(
415
- ([, a]) => a.state === "open" || a.state === "draft"
416
- ), s = await Promise.all(n.map(([, a]) => ln(e, a.url)));
417
- n.forEach(([a, i], r) => {
418
- const o = s[r];
419
- if (!o) return;
420
- const { reviewBodies: c, ...u } = o, l = !!i.headSha && c.some((p) => p.includes(dn(a, i.headSha)));
421
- t.set(a, { ...i, ...u, ...l && { scoutReviewObserved: l } });
422
- });
423
- }
424
- async function gn(e) {
425
- const t = await qe(e, [
426
- "pr",
427
- "list",
428
- "--state",
429
- "all",
430
- "--limit",
431
- "2000",
432
- "--json",
433
- "number,url,state,isDraft,headRefName,headRefOid,body,reviewDecision"
434
- ]);
435
- if (!t) return;
436
- const n = /* @__PURE__ */ new Map();
437
- for (const s of t) {
438
- const a = Ye(s.body, s.headRefName);
439
- if (!a) continue;
440
- const i = on(s), r = n.get(a);
441
- (!r || Se[i.state] > Se[r.state]) && n.set(a, i);
442
- }
443
- return await mn(e, n), n;
444
- }
445
- async function Je(e, t = sn) {
446
- let n = k.get(e);
447
- if (!n) {
448
- const a = await Be(e);
449
- a && (k.set(e, a), n = a);
450
- }
451
- if (n && Date.now() - n.fetchedAt < t) return n.prs;
452
- if (!Number.isFinite(t)) return n == null ? void 0 : n.prs;
453
- const s = await gn(e);
454
- if (s !== void 0) {
455
- const a = Date.now();
456
- return k.set(e, { prs: s, fetchedAt: a }), await an(e, s, a), s;
457
- }
458
- return n == null ? void 0 : n.prs;
459
- }
460
- function fi(e) {
461
- var t;
462
- return (t = k.get(e)) == null ? void 0 : t.prs;
463
- }
464
- function pi(e, t) {
465
- const n = (a) => `${a.number}:${a.headSha ?? "unknown"}`, s = [];
466
- for (const [a, i] of t) {
467
- if (i.reviewDecision !== "changes-requested") continue;
468
- const r = e == null ? void 0 : e.get(a);
469
- ((r == null ? void 0 : r.reviewDecision) === "changes-requested" ? n(r) : void 0) !== n(i) && s.push({ entityId: a, pr: i });
470
- }
471
- return s;
472
- }
473
- async function hi(e) {
474
- let t = k.get(e);
475
- if (!t) {
476
- const n = await Be(e);
477
- n && (k.set(e, n), t = n);
478
- }
479
- return (t == null ? void 0 : t.fetchedAt) ?? null;
480
- }
481
- async function mi(e) {
482
- if (e === void 0) {
483
- k.clear();
484
- return;
485
- }
486
- const t = k.get(e);
487
- t && k.set(e, { ...t, fetchedAt: 0 });
488
- const n = ie(e);
489
- try {
490
- const s = await v(n, "utf-8"), a = JSON.parse(s);
491
- a.fetchedAt = 0, await E(n, `${JSON.stringify(a, null, 2)}
492
- `, "utf-8");
493
- } catch {
494
- }
495
- }
496
- const Ve = /^#{2,3}\s+/, H = /^[-*]\s+\[([ xX])\]\s+(.*)$/, yn = /^\[(review|manual|issue)\]\s+(.*)$/, wn = /^run:\s*(.+)$/, $e = /^-\s+(\d{4}-\d{2}-\d{2}):\s*(.*)$/, bn = /^\[(?:phase:(\d+)|body)\]\s+(?:\[(decision|question)\]\s+)?(.*)$/, Ie = /^-\s+\[([ xX])\]\s+(?:(\d{4}-\d{2}-\d{2})\s+)?\[(log|clarification|review|note|decision|question|chat)\]\s+(\[agent\]\s+)?(?:\[\[([A-Za-z]+-\d+)\]\]\s+)?(.*)$/, vn = ["note", "decision", "question"];
497
- function re(e, t, n, s) {
498
- const a = [];
499
- let i = t;
500
- for (; i < n; ) {
501
- const r = e[i];
502
- if (r.trim() === "" || !/^\s/.test(r)) break;
503
- const o = r.trimStart();
504
- if (s.test(o) || Ve.test(o)) break;
505
- a.push(o), i++;
506
- }
507
- return { text: a.join(" "), next: i };
508
- }
509
- function oe(e, t) {
510
- return t ? `${e.trim()} ${t}` : e.trim();
511
- }
512
- function Xe(e, t, n) {
513
- const s = [];
514
- let a = t;
515
- for (; a < n; ) {
516
- const i = e[a].match(H);
517
- if (i) {
518
- const r = i[1].toLowerCase() === "x", o = i[2].trim(), c = o.match(yn), u = c ? c[2].trim() : o, l = c ? c[1] : void 0, p = [];
519
- let h;
520
- for (a++; a < n; ) {
521
- const w = e[a];
522
- if (w.trim() === "" || H.test(w) || Ve.test(w)) break;
523
- if (/^\s/.test(w)) {
524
- const g = w.trimStart(), m = g.match(wn), y = m ? Ft(m[1]) : void 0;
525
- y ? h = y : p.push(g), a++;
526
- } else
527
- break;
528
- }
529
- s.push({
530
- done: r,
531
- text: u,
532
- description: p.length > 0 ? p.join(`
533
- `) : void 0,
534
- source: l,
535
- run: h
536
- });
537
- } else
538
- a++;
539
- }
540
- return s;
541
- }
542
- function ce(e, t, n) {
543
- const s = [];
544
- let a = t;
545
- for (; a < n; ) {
546
- const i = e[a].match($e);
547
- if (!i) {
548
- a++;
549
- continue;
550
- }
551
- const r = re(e, a + 1, n, $e);
552
- s.push({ date: i[1], text: oe(i[2], r.text) }), a = r.next;
553
- }
554
- return s;
555
- }
556
- function Ze(e, t) {
557
- const n = [e];
558
- for (const s of t) {
559
- const a = s.source ? `[${s.source}] ${s.text}` : s.text;
560
- if (n.push(`- [${s.done ? "x" : " "}] ${a}`), s.description)
561
- for (const i of s.description.split(`
562
- `)) n.push(` ${i}`);
563
- s.run && n.push(` run: ${Ht(s.run)}`);
564
- }
565
- return n;
566
- }
567
- function de(e, t) {
568
- return [e, ...t.map((n) => `- ${n.date}: ${n.text}`)];
569
- }
570
- function En(e) {
571
- return e.kind === "phase" ? `[phase:${e.index}]` : "[body]";
572
- }
573
- function kn(e, t, n) {
574
- const s = [];
575
- let a = t;
576
- for (; a < n; ) {
577
- const i = e[a].match(H), r = i ? i[2].trim().match(bn) : null;
578
- if (!i || !r) {
579
- a++;
580
- continue;
581
- }
582
- const o = r[1] ? { kind: "phase", index: Number(r[1]) } : { kind: "body" }, c = r[2], u = re(e, a + 1, n, H);
583
- s.push({
584
- anchor: o,
585
- prose: oe(r[3], u.text),
586
- state: i[1].toLowerCase() === "x" ? "resolved" : "open",
587
- ...c ? { kind: c } : {}
588
- }), a = u.next;
589
- }
590
- return s;
591
- }
592
- function Sn(e) {
593
- const t = ["### Notes"];
594
- for (const n of e) {
595
- const s = n.kind && n.kind !== "note" ? `[${n.kind}] ` : "";
596
- t.push(
597
- `- [${n.state === "resolved" ? "x" : " "}] ${En(n.anchor)} ${s}${n.prose}`
598
- );
599
- }
600
- return t;
601
- }
602
- const J = {
603
- headingRe: /^#{2,3}\s+Phases\s*$/i,
604
- parseEntries: Xe,
605
- formatLines: (e) => Ze("### Phases", e)
606
- }, Qe = {
607
- headingRe: /^#{2,3}\s+Fixes\s*$/i,
608
- parseEntries: Xe,
609
- formatLines: (e) => Ze("### Fixes", e)
610
- }, j = {
611
- headingRe: /^#{2,3}\s+Log\s*$/i,
612
- parseEntries: ce,
613
- formatLines: (e) => de("### Log", e)
614
- }, ue = {
615
- headingRe: /^#{2,3}\s+Clarifications\s*$/i,
616
- parseEntries: ce,
617
- formatLines: (e) => de("### Clarifications", e)
618
- }, le = {
619
- headingRe: /^#{2,3}\s+Notes\s*$/i,
620
- parseEntries: kn,
621
- formatLines: Sn
622
- }, $n = {
623
- headingRe: /^#{2,3}\s+Review\s*$/i,
624
- parseEntries: ce,
625
- formatLines: (e) => de("### Review", e)
626
- };
627
- function In(e, t, n) {
628
- const s = [];
629
- let a = t;
630
- for (; a < n; ) {
631
- const i = e[a].match(Ie);
632
- if (!i) {
633
- a++;
634
- continue;
635
- }
636
- const r = i[3], o = re(e, a + 1, n, Ie), c = { kind: r, text: oe(i[6], o.text) };
637
- i[2] && (c.date = i[2]), i[4] && (c.from = "agent"), i[5] && (c.entityId = i[5]), vn.includes(r) && (c.state = i[1].toLowerCase() === "x" ? "resolved" : "open"), s.push(c), a = o.next;
638
- }
639
- return s;
640
- }
641
- function Rn(e) {
642
- const t = ["### Thread"];
643
- for (const n of e) {
644
- const s = n.state ? n.state === "resolved" : !0, a = n.date ? `${n.date} ` : "", i = n.from === "agent" ? "[agent] " : "", r = n.entityId ? `[[${n.entityId}]] ` : "";
645
- t.push(`- [${s ? "x" : " "}] ${a}[${n.kind}] ${i}${r}${n.text}`);
646
- }
647
- return t;
648
- }
649
- const et = {
650
- headingRe: /^#{2,3}\s+Thread\s*$/i,
651
- parseEntries: In,
652
- formatLines: Rn
653
- }, S = d.preprocess(
654
- (e) => typeof e == "string" ? { agent: e } : e,
655
- d.object({
656
- agent: d.enum(D),
657
- model: d.string().optional(),
658
- effort: d.string().optional()
659
- })
660
- ), $ = d.string().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD"), An = d.object({
661
- status: d.enum(["idea", "planned", "in-progress", "review", "done", "dropped"]),
662
- kind: d.enum(["feat", "fix", "chore", "docs", "refactor"]).optional(),
663
- id: d.string().optional(),
664
- idea: d.string().optional(),
665
- agent: d.enum(D).optional(),
666
- created: $,
667
- updated: $.optional(),
668
- tags: d.string().optional()
669
- }), Pn = d.object({
670
- id: d.string().describe("Permanent plan ID, e.g. FEAT-24"),
671
- title: d.string().describe('Human-readable plan name, e.g. "Plan storage architecture"'),
672
- kind: d.enum(["feat", "fix", "chore", "docs", "refactor"]).describe("Plan kind matching Conventional Commits types"),
673
- status: d.enum(["idea", "planned", "in-progress", "review", "done", "dropped"]).describe("Current lifecycle status"),
674
- idea: d.string().optional().describe("IDEA-N backlink if this plan grew out of an idea"),
675
- agent: d.enum(D).optional().describe("Per-plan agent override"),
676
- created: $.describe("Creation date (YYYY-MM-DD)"),
677
- updated: $.optional().describe("Last significant update date (YYYY-MM-DD)"),
678
- audited: $.optional().describe("Date of last successful convergence audit (YYYY-MM-DD)"),
679
- "audited-hash": d.string().optional().describe("Content hash of the plan at last audit, used to detect edits regardless of mtime"),
680
- tags: d.array(d.string()).optional().describe("Tagging categories")
681
- }).passthrough(), Tn = d.object({
682
- id: d.string().describe("Permanent idea ID, e.g. IDEA-20"),
683
- title: d.string().describe("Short idea headline (3-6 words)"),
684
- kind: d.enum(["idea", "note"]).optional().describe('"note" for ideas that never need a plan; omitted means a plan-bearing idea'),
685
- status: d.enum(["open", "done", "dropped"]).optional().describe("Manual lifecycle, valid only on notes — plan-bearing ideas carry no status")
686
- }).passthrough().refine((e) => e.status === void 0 || e.kind === "note", {
687
- message: "status is only valid on ideas with kind: note",
688
- path: ["status"]
689
- }), tt = d.object({
690
- id: d.string().describe("Permanent lifetime entity ID, e.g. IDEA-45 — never changes"),
691
- title: d.string().describe("Human-readable entity name"),
692
- type: d.enum(["feat", "fix", "chore", "docs", "refactor"]).optional().describe(
693
- "Work classification (Conventional Commits values) driving commit types and branch prefixes; usually set once a plan is drafted"
694
- ),
695
- kind: d.enum(["note", "fix", "board", "ticket"]).optional().describe(
696
- '"note" marks an entity that never grows phases; "fix" is a follow-up entity linked to a done/archived parent via `idea`; "board" decomposes into "ticket" children instead of phases; "ticket" is a full entity linked back to its board via `idea`; omitted for normal ideas'
697
- ),
698
- status: d.enum(["idea", "planned", "in-progress", "review", "done", "dropped", "open"]).optional().describe(
699
- "Stored override, no longer the source of truth: most lifecycle states derive from phases/branch/PR. Only dropped, a planless idea/note being closed, or the offline fallback need this set."
700
- ),
701
- agent: d.enum(D).optional().describe("Per-entity agent override"),
702
- created: $.describe("Creation date (YYYY-MM-DD)"),
703
- updated: $.optional().describe("Last significant update date (YYYY-MM-DD)"),
704
- audited: $.optional().describe("Date of last successful convergence audit (YYYY-MM-DD)"),
705
- "audited-hash": d.string().optional().describe(
706
- "Content hash of the entity at last audit, used to detect edits regardless of mtime"
707
- ),
708
- released: d.string().optional().describe(
709
- "Version tag (e.g. v0.13.1) that first shipped this idea, stamped from the release train"
710
- ),
711
- tags: d.array(d.string()).optional().describe("Tagging categories"),
712
- idea: d.string().optional().describe("IDEA-N backlink to the parent this fix addresses; required when kind: fix"),
713
- subject: d.string().optional().describe('Subject group name; absent renders as the virtual "No subject" group'),
714
- order: d.number().int().optional().describe("Run order; absent means unordered, sorting after ordered entries"),
715
- issueSource: d.string().optional().describe(
716
- "sourceKind:sourceKey of the Issue (IDEA-192) this entity was promoted from, if any"
717
- )
718
- }).passthrough(), Nn = new Set(
719
- Object.keys(tt.shape)
720
- ), nt = tt.refine(
721
- (e) => e.kind !== "note" || e.status === void 0 || ["open", "done", "dropped"].includes(e.status),
722
- {
723
- message: "a note entity must use status open, done, or dropped",
724
- path: ["status"]
725
- }
726
- ).refine((e) => e.kind === "note" || e.status !== "open", {
727
- message: "status open is only valid on entities with kind: note",
728
- path: ["status"]
729
- }).refine((e) => e.kind !== "fix" || e.idea !== void 0, {
730
- message: "a kind: fix entity requires an idea: link to its parent",
731
- path: ["idea"]
732
- }).refine((e) => e.kind !== "ticket" || e.idea !== void 0, {
733
- message: "a kind: ticket entity requires an idea: link to its board",
734
- path: ["idea"]
735
- }), Cn = d.object({
736
- name: d.string(),
737
- cmd: d.string(),
738
- port: d.number().int().positive().optional(),
739
- healthcheck: d.string().optional()
740
- }), _n = d.object({
741
- name: d.string(),
742
- cmd: d.string(),
743
- fixCmd: d.string().optional()
744
- }), xn = d.object({
745
- repo: d.string(),
746
- branch: d.string().optional(),
747
- releasePlease: d.boolean().optional()
748
- }), On = d.object({
749
- services: d.array(Cn).optional(),
750
- checks: d.array(_n).optional(),
751
- ci: xn.optional()
752
- }), Dn = d.object({
753
- from: d.string(),
754
- to: d.string()
755
- }), Mn = d.object({
756
- name: d.string(),
757
- prompt: d.string()
758
- }), jn = d.object({
759
- ceiling: d.number().optional(),
760
- floor: d.number().optional(),
761
- window: Dn.optional(),
762
- roots: d.array(d.string()).optional(),
763
- maxChunks: d.number().int().positive().optional(),
764
- threshold: d.number().min(0).max(100).optional(),
765
- checks: d.record(d.enum(Ot), d.boolean()).optional(),
766
- customChecks: d.array(Mn).optional(),
767
- maxTurns: d.number().int().positive().optional(),
768
- maxCostUsd: d.number().positive().optional()
769
- }), Ln = d.object({
770
- kinds: d.record(d.enum(Dt), d.boolean()).optional()
771
- }), Fn = d.object({
772
- endpoint: d.string(),
773
- keys: d.object({ p256dh: d.string(), auth: d.string() })
774
- }), gi = d.discriminatedUnion("transport", [
775
- d.object({
776
- transport: d.literal("webpush"),
777
- name: d.string(),
778
- subscription: Fn
779
- }),
780
- d.object({ transport: d.literal("expo"), name: d.string(), token: d.string() })
781
- ]), yi = d.discriminatedUnion("transport", [
782
- d.object({ transport: d.literal("webpush"), endpoint: d.string() }),
783
- d.object({ transport: d.literal("expo"), token: d.string() })
784
- ]), Hn = d.object({
785
- version: d.number().int().describe("Corpus format version (see CORPUS_FORMAT_VERSION), not the package version"),
786
- projectName: d.string(),
787
- initializedAt: d.string(),
788
- nextId: d.object({
789
- // idea: unified-entity counter minting lifetime IDEA-N ids. ticket: board/ticket
790
- // counter (IDEA-201) minting TICKET-N ids. The rest are legacy per-kind counters.
791
- idea: d.number().optional(),
792
- ticket: d.number().optional(),
793
- feat: d.number().optional(),
794
- fix: d.number().optional(),
795
- chore: d.number().optional(),
796
- docs: d.number().optional(),
797
- refactor: d.number().optional()
798
- }).optional(),
799
- defaultAgent: d.enum(D).optional(),
800
- defaultAgents: d.object({
801
- phase: S,
802
- planDraft: S,
803
- ideaExtend: S,
804
- commitSuggest: S,
805
- feedback: S,
806
- codeReview: S,
807
- deskDiscovery: S,
808
- nightShift: S
809
- }).optional(),
810
- desk: On.optional(),
811
- night: jn.optional(),
812
- notifications: Ln.optional()
813
- }), Gn = d.object({
814
- id: d.string(),
815
- kind: d.enum([
816
- "completed",
817
- "reply",
818
- "check-failed",
819
- "pr-review-changes-requested",
820
- "night-review-findings",
821
- "service-stopped"
822
- ]),
823
- entityId: d.string(),
824
- entityTitle: d.string(),
825
- text: d.string(),
826
- date: d.string(),
827
- read: d.boolean(),
828
- outcome: d.enum(["done", "error"]).optional(),
829
- push: d.boolean().optional().default(!0)
830
- }), Re = /^##\s+(.+?)\s*$/, Bn = /^\*\*([A-Za-z][A-Za-z-]*):\*\*\s*(.*)$/, Yn = /^#{2,3}\s+/;
831
- function G(e, t) {
832
- const n = e.split(`
833
- `), s = n.findIndex((o) => t.headingRe.test(o));
834
- if (s === -1) return { body: e, entries: [] };
835
- let a = n.length;
836
- for (let o = s + 1; o < n.length; o++)
837
- if (Yn.test(n[o])) {
838
- a = o;
839
- break;
840
- }
841
- const i = t.parseEntries(n, s + 1, a);
842
- return { body: [...n.slice(0, s), ...n.slice(a)].join(`
843
- `).trim(), entries: i };
844
- }
845
- const Ae = {
846
- phases: J,
847
- log: j,
848
- clarifications: ue,
849
- notes: le,
850
- review: $n
851
- };
852
- function fe(e) {
853
- const t = {
854
- phases: [],
855
- log: [],
856
- clarifications: [],
857
- notes: [],
858
- review: []
859
- };
860
- let n = e;
861
- for (const s of Object.keys(Ae)) {
862
- const a = G(n, Ae[s]);
863
- n = a.body, t[s] = a.entries;
864
- }
865
- return { body: n, ...t };
866
- }
867
- function qn(e) {
868
- const t = e.split(`
869
- `), n = [];
870
- for (let a = 0; a < t.length; a++)
871
- Re.test(t[a]) && n.push(a);
872
- const s = [];
873
- for (let a = 0; a < n.length; a++) {
874
- const i = n[a], r = a + 1 < n.length ? n[a + 1] : t.length, o = t[i].match(Re)[1], c = t.slice(i + 1, r);
875
- let u = 0;
876
- for (; u < c.length && c[u].trim() === ""; ) u++;
877
- const l = {};
878
- for (; u < c.length; ) {
879
- const L = c[u].match(Bn);
880
- if (!L) break;
881
- l[L[1].toLowerCase()] = L[2].trim(), u++;
882
- }
883
- for (; u < c.length && c[u].trim() === ""; ) u++;
884
- const p = c.slice(u).join(`
885
- `).trim(), { body: h, phases: w, log: g, clarifications: m, notes: y, review: x } = fe(p);
886
- s.push({ title: o, fields: l, body: h, phases: w, log: g, clarifications: m, notes: y, review: x });
887
- }
888
- return s;
889
- }
890
- function wi(e) {
891
- const t = [], n = [];
892
- for (const s of qn(e)) {
893
- const a = An.safeParse(s.fields);
894
- if (!a.success) {
895
- n.push({
896
- title: s.title,
897
- message: a.error.issues.map((r) => r.message).join("; ")
898
- });
899
- continue;
900
- }
901
- const i = a.data;
902
- t.push({
903
- title: s.title,
904
- status: i.status,
905
- kind: i.kind,
906
- id: i.id,
907
- idea: i.idea,
908
- agent: i.agent,
909
- created: i.created,
910
- updated: i.updated,
911
- tags: i.tags ? i.tags.split(",").map((r) => r.trim()).filter(Boolean) : [],
912
- body: s.body,
913
- phases: s.phases,
914
- log: s.log,
915
- clarifications: s.clarifications,
916
- notes: s.notes,
917
- review: s.review
918
- });
919
- }
920
- return { entries: t, warnings: n };
921
- }
922
- const Un = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n)?/;
923
- function pe(e, t) {
924
- const n = [], s = e.match(Un);
925
- if (!s)
926
- return { data: null, body: e.trim(), warnings: n };
927
- const a = s[1], i = e.slice(s[0].length).trim();
928
- let r;
929
- try {
930
- r = K(a);
931
- } catch (c) {
932
- return n.push({
933
- title: "(frontmatter)",
934
- message: `Invalid YAML frontmatter: ${c.message}`
935
- }), { data: null, body: i, warnings: n };
936
- }
937
- if (typeof r != "object" || r === null || Array.isArray(r))
938
- return n.push({
939
- title: "(frontmatter)",
940
- message: "YAML frontmatter did not produce an object"
941
- }), { data: null, body: i, warnings: n };
942
- const o = t.safeParse(r);
943
- if (!o.success) {
944
- const c = r.id;
945
- return n.push({
946
- title: c ?? "(frontmatter)",
947
- message: o.error.issues.map((u) => u.message).join("; ")
948
- }), { data: null, body: i, warnings: n };
949
- }
950
- return { data: o.data, body: i, warnings: n };
951
- }
952
- function zn(e, t) {
953
- const n = Object.fromEntries(
954
- Object.entries(e).filter(([s]) => !t.has(s))
955
- );
956
- return Object.keys(n).length > 0 ? n : void 0;
957
- }
958
- function st(e) {
959
- const t = [], {
960
- data: n,
961
- body: s,
962
- warnings: a
963
- } = pe(e, nt);
964
- if (t.push(...a), !n)
965
- return { entries: [], warnings: t };
966
- const {
967
- body: i,
968
- phases: r,
969
- log: o,
970
- clarifications: c,
971
- notes: u,
972
- review: l
973
- } = fe(s), { body: p, entries: h } = G(i, Qe), { body: w, entries: g } = G(p, et), m = [...g, ...Jt(o, c, u, l)];
974
- n.kind === "note" && r.length > 0 && t.push({
975
- title: n.title,
976
- message: "note entities must not carry a Phases section — kept, but fix the file"
977
- });
978
- const y = zn(n, Nn);
979
- return { entries: [{
980
- id: n.id,
981
- title: n.title,
982
- type: n.type,
983
- kind: n.kind,
984
- status: n.status,
985
- idea: n.idea,
986
- agent: n.agent,
987
- created: n.created,
988
- updated: n.updated,
989
- audited: n.audited,
990
- auditedHash: n["audited-hash"],
991
- released: n.released,
992
- tags: n.tags ?? [],
993
- subject: n.subject,
994
- order: n.order,
995
- issueSource: n.issueSource,
996
- body: w,
997
- phases: r,
998
- ...h.length > 0 && { fixes: h },
999
- ...m.length > 0 && { thread: m },
1000
- ...y && { unknownFrontmatter: y }
1001
- }], warnings: t };
1002
- }
1003
- function bi(e) {
1004
- const t = [], {
1005
- data: n,
1006
- body: s,
1007
- warnings: a
1008
- } = pe(e, Pn);
1009
- if (t.push(...a), !n)
1010
- return { entries: [], warnings: t };
1011
- const { body: i, phases: r, log: o, clarifications: c, notes: u, review: l } = fe(s);
1012
- return { entries: [{
1013
- title: n.title,
1014
- status: n.status,
1015
- kind: n.kind,
1016
- id: n.id,
1017
- idea: n.idea,
1018
- agent: n.agent,
1019
- created: n.created,
1020
- updated: n.updated,
1021
- audited: n.audited,
1022
- auditedHash: n["audited-hash"],
1023
- tags: n.tags ?? [],
1024
- body: i,
1025
- phases: r,
1026
- log: o,
1027
- clarifications: c,
1028
- notes: u,
1029
- review: l
1030
- }], warnings: t };
1031
- }
1032
- function vi(e) {
1033
- const {
1034
- data: t,
1035
- body: n,
1036
- warnings: s
1037
- } = pe(e, Tn);
1038
- if (!t)
1039
- return { entries: [], warnings: s };
1040
- const { body: a, entries: i } = G(n, j);
1041
- return { entries: [{
1042
- id: t.id,
1043
- title: t.title,
1044
- body: a || "",
1045
- ...t.kind && { kind: t.kind },
1046
- ...t.status && { status: t.status },
1047
- ...i.length > 0 && { log: i }
1048
- }], warnings: s };
1049
- }
1050
- const Kn = /^(IDEA-\d+):\s*/, Wn = /\n---+\n/;
1051
- function Ei(e) {
1052
- return e.split(Wn).filter(Boolean).map((n) => {
1053
- var c;
1054
- const s = n.match(/^#{1,3}\s+(.+)/m), a = s ? s[1].trim() : ((c = n.trim().split(`
1055
- `)[0]) == null ? void 0 : c.trim()) ?? "Untitled", i = a.match(Kn), r = (i == null ? void 0 : i[1]) ?? null, o = r ? a.slice(i[0].length) : a;
1056
- return { id: r, title: o, body: n.trim() };
1057
- });
1058
- }
1059
- const Pe = 40;
1060
- function Jn(e, t = []) {
1061
- const n = [];
1062
- for (const s of e)
1063
- if (!s.archived && (t.length > 0 && s.subject && !t.includes(s.subject) && n.push({
1064
- kind: "orphan-subject",
1065
- section: "plans",
1066
- title: s.title,
1067
- planId: s.id,
1068
- message: `Subject "${s.subject}" isn't in the roadmap vocabulary — "${s.title}"`
1069
- }), s.status !== "done" && s.status !== "dropped")) {
1070
- const a = [];
1071
- s.title.length > Pe && a.push(`${s.title.length} chars over the ${Pe}-char limit`), s.title.includes("—") && a.push("em-dash subtitle"), a.length > 0 && n.push({
1072
- kind: "title-style",
1073
- section: "plans",
1074
- title: s.title,
1075
- planId: s.id,
1076
- message: `Title style — ${a.join(", ")}; the detail belongs in the body: "${s.title}"`
1077
- });
1078
- }
1079
- return n;
1080
- }
1081
- function Vn(e) {
1082
- const t = /* @__PURE__ */ new Map(), n = [];
1083
- for (const s of e.split(`
1084
- `)) {
1085
- const a = s.trim();
1086
- if (!a) continue;
1087
- let i;
1088
- try {
1089
- i = JSON.parse(a);
1090
- } catch {
1091
- continue;
1092
- }
1093
- const r = t.get(i.id);
1094
- r ? t.set(i.id, { ...r, ...i }) : (t.set(i.id, i), n.push(i.id));
1095
- }
1096
- return n.map((s) => t.get(s));
1097
- }
1098
- function ki(e) {
1099
- const t = [];
1100
- for (const n of e.split(`
1101
- `)) {
1102
- const s = n.trim();
1103
- if (s)
1104
- try {
1105
- const a = Gn.safeParse(JSON.parse(s));
1106
- a.success && t.push(a.data);
1107
- } catch {
1108
- }
1109
- }
1110
- return t;
1111
- }
1112
- const at = /^-\s+(\d{4}-\d{2}-\d{2}):\s+(.+?)\s+—\s+(.*)$/;
1113
- function Si(e) {
1114
- const t = [];
1115
- for (const n of e.split(`
1116
- `)) {
1117
- const s = n.match(at);
1118
- s && t.push({ date: s[1], title: s[2].trim(), description: s[3].trim() });
1119
- }
1120
- return t;
1121
- }
1122
- const ee = " — ";
1123
- function Xn(e) {
1124
- return e.split(`
1125
- `).map((t) => t.trim()).filter((t) => t.length > 0).map((t) => {
1126
- const n = t.indexOf(ee);
1127
- return n === -1 ? { id: t, title: "" } : {
1128
- id: t.slice(0, n).trim(),
1129
- title: t.slice(n + ee.length).trim()
1130
- };
1131
- });
1132
- }
1133
- function $i(e) {
1134
- return e.length === 0 ? "" : `${e.map((t) => `${t.id}${ee}${t.title}`).join(`
1135
- `)}
1136
- `;
1137
- }
1138
- async function Zn(e) {
1139
- try {
1140
- return await z(e);
1141
- } catch {
1142
- return [];
1143
- }
1144
- }
1145
- async function it(e) {
1146
- try {
1147
- return await v(e, "utf-8");
1148
- } catch {
1149
- return "";
1150
- }
1151
- }
1152
- async function Qn(e) {
1153
- const t = await it(f(e, "..", "run-order.md"));
1154
- return new Map(Xn(t).map((n, s) => [n.id, s + 1]));
1155
- }
1156
- async function _(e) {
1157
- const t = [], n = [];
1158
- let s = 0;
1159
- const a = await Qn(e);
1160
- for (const i of [e, f(e, "archive")]) {
1161
- const r = i !== e, o = (await Zn(i)).filter((u) => u.endsWith(".md") && u !== "index.md");
1162
- s += o.length;
1163
- const c = await Promise.all(
1164
- o.map(async (u) => {
1165
- const l = await it(f(i, u));
1166
- return l ? st(l) : { warnings: [{ title: u, message: "Could not read entity file" }] };
1167
- })
1168
- );
1169
- for (const u of c)
1170
- "entries" in u && t.push(
1171
- ...u.entries.map((l) => ({
1172
- ...l,
1173
- archived: r,
1174
- storedOrder: l.order,
1175
- order: a.get(l.id) ?? l.order
1176
- }))
1177
- ), n.push(...u.warnings);
1178
- }
1179
- return { entries: t, warnings: n, fileCount: s };
1180
- }
1181
- async function he(e, t) {
1182
- const { entries: n, warnings: s } = await _(e), a = f(e, "..", ".."), [i, r] = await Promise.all([
1183
- Je(a, t),
1184
- Ge(a)
1185
- ]);
1186
- return { entries: n, warnings: s, prs: i, resolved: i !== void 0, mainActivityIds: r };
1187
- }
1188
- async function Ii(e) {
1189
- const { entries: t, warnings: n, prs: s, resolved: a, mainActivityIds: i } = await he(e), r = t.map((c) => ({
1190
- ...c,
1191
- status: W(c, s == null ? void 0 : s.get(c.id), a, i.has(c.id))
1192
- }));
1193
- return { entries: r.map((c) => {
1194
- if (c.kind !== "board" || c.archived || c.status === "done" || c.status === "dropped") return c;
1195
- const u = r.filter((l) => l.kind === "ticket" && l.idea === c.id).map((l) => l.status ?? "idea");
1196
- return { ...c, status: je(u) };
1197
- }), warnings: n };
1198
- }
1199
- async function Ri(e, t) {
1200
- const { entries: n, warnings: s, prs: a, resolved: i, mainActivityIds: r } = await he(
1201
- e,
1202
- t
1203
- ), o = n.filter((u) => u.kind !== "note").map((u) => Fe(u, a == null ? void 0 : a.get(u.id), i, r.has(u.id)));
1204
- return { entries: o.map((u) => {
1205
- if (u.entityKind !== "board" || u.archived || u.status === "done" || u.status === "dropped")
1206
- return u;
1207
- const l = o.filter((p) => p.entityKind === "ticket" && p.idea === u.id).map((p) => p.status);
1208
- return { ...u, status: je(l) };
1209
- }), warnings: s, resolved: i };
1210
- }
1211
- async function Ai(e) {
1212
- const { entries: t, prs: n, resolved: s } = await he(e);
1213
- return {
1214
- entries: t.flatMap((a) => {
1215
- const i = n == null ? void 0 : n.get(a.id);
1216
- return i && Wt(a, i) ? [{ id: a.id, title: a.title, pr: i }] : [];
1217
- }),
1218
- resolved: s
1219
- };
1220
- }
1221
- async function Pi(e) {
1222
- const { entries: t, warnings: n } = await _(e);
1223
- return {
1224
- entries: t.filter((s) => s.kind === "note").map(Qt),
1225
- warnings: n
1226
- };
1227
- }
1228
- const es = [
1229
- {
1230
- id: "frontmatter-schema",
1231
- category: "metadata",
1232
- severity: "error",
1233
- summary: "Frontmatter fails entityFrontmatterSchema — missing required field, bad enum, malformed date, or a violated note/status refinement."
1234
- },
1235
- {
1236
- id: "filename-id-mismatch",
1237
- category: "metadata",
1238
- severity: "error",
1239
- summary: "Frontmatter id does not match the file name (IDEA-N.md); references break silently."
1240
- },
1241
- {
1242
- id: "duplicate-id",
1243
- category: "metadata",
1244
- severity: "error",
1245
- summary: "Two entity files share one id; whichever loads last wins and the other disappears."
1246
- },
1247
- {
1248
- id: "id-counter-stale",
1249
- category: "metadata",
1250
- severity: "error",
1251
- summary: "An entity id is greater than or equal to config.nextId.idea, so the next mint collides with an existing file."
1252
- },
1253
- {
1254
- id: "corpus-format-too-new",
1255
- category: "metadata",
1256
- severity: "error",
1257
- summary: "config.version is newer than the format this paper-camp understands; reads stay tolerant but writes are refused until it upgrades."
1258
- },
1259
- {
1260
- id: "phases-list-split",
1261
- category: "structural",
1262
- severity: "error",
1263
- summary: "A checkbox line lives outside the Phases section — a mid-file heading split the list and orphaned phases, so the entity parses as fewer phases than it has."
1264
- },
1265
- {
1266
- id: "note-has-phases",
1267
- category: "structural",
1268
- severity: "error",
1269
- summary: "A kind: note entity carries a Phases section; notes never grow phases."
1270
- },
1271
- {
1272
- id: "duplicate-phases-section",
1273
- category: "structural",
1274
- severity: "error",
1275
- summary: "A file carries more than one Phases heading — a redraft appended instead of replacing the existing list in place."
1276
- },
1277
- {
1278
- id: "archive-placement",
1279
- category: "structural",
1280
- severity: "warning",
1281
- summary: "File location contradicts status — a done/dropped entity still under ideas/, or an active entity already under ideas/archive/."
1282
- },
1283
- {
1284
- id: "dangling-link",
1285
- category: "structural",
1286
- severity: "warning",
1287
- summary: "A [[IDEA-N]] wikilink targets an id that no entity in the corpus defines."
1288
- },
1289
- {
1290
- id: "missing-permissions-allow",
1291
- category: "tooling",
1292
- severity: "warning",
1293
- summary: ".claude/settings.json has no permissions.allow list, so a headless run denies every edit and shell command outside the defaults — run `paper-camp init --settings` to add it."
1294
- }
1295
- ], ts = Object.fromEntries(
1296
- es.map((e) => [e.id, e])
1297
- );
1298
- function B(e) {
1299
- return ts[e.rule].severity;
1300
- }
1301
- const Te = { error: 0, warning: 1 };
1302
- function rt(e) {
1303
- return [...e].sort(
1304
- (t, n) => t.file.localeCompare(n.file) || t.line - n.line || Te[B(t)] - Te[B(n)] || t.rule.localeCompare(n.rule)
1305
- );
1306
- }
1307
- function Ti(e) {
1308
- const t = rt(e).map((n) => ({
1309
- ...n,
1310
- severity: B(n)
1311
- }));
1312
- return {
1313
- findings: t,
1314
- errorCount: t.filter((n) => n.severity === "error").length,
1315
- warningCount: t.filter((n) => n.severity === "warning").length
1316
- };
1317
- }
1318
- function Ni(e) {
1319
- const t = rt(e);
1320
- let n = 0, s = 0;
1321
- const a = t.map((r) => {
1322
- const o = B(r);
1323
- return o === "error" ? n++ : s++, `${r.file}:${r.line} ${o.padEnd(7)} ${r.rule} ${r.message}`;
1324
- }), i = t.length === 0 ? "paper-camp doctor: no issues found." : `paper-camp doctor: ${n} error(s), ${s} warning(s).`;
1325
- return {
1326
- text: [...a, ...a.length > 0 ? [""] : [], i].join(`
1327
- `),
1328
- errorCount: n,
1329
- warningCount: s
1330
- };
1331
- }
1332
- const I = 1;
1333
- class ns extends Error {
1334
- constructor(t) {
1335
- super(
1336
- `This corpus is in format version ${t}, newer than the format version ${I} this paper-camp understands. Writes are refused so a field this version doesn’t recognise is never dropped — upgrade paper-camp to edit this corpus.`
1337
- ), this.name = "CorpusTooNewError";
1338
- }
1339
- }
1340
- async function ot(e) {
1341
- let t;
1342
- try {
1343
- t = await v(e, "utf-8");
1344
- } catch {
1345
- return null;
1346
- }
1347
- try {
1348
- const n = JSON.parse(t);
1349
- return n && typeof n == "object" && !Array.isArray(n) ? n : null;
1350
- } catch {
1351
- return null;
1352
- }
1353
- }
1354
- function ct(e) {
1355
- const t = e == null ? void 0 : e.version;
1356
- return typeof t == "number" ? t : null;
1357
- }
1358
- async function Ci(e) {
1359
- const t = ct(await ot(e));
1360
- if (t !== null && t > I)
1361
- throw new ns(t);
1362
- }
1363
- async function _i(e) {
1364
- const t = await ot(e);
1365
- if (!t) return null;
1366
- const n = ct(t);
1367
- return n !== null && n >= I ? null : (t.version = I, await E(e, `${JSON.stringify(t, null, 2)}
1368
- `, "utf-8"), { from: n, to: I });
1369
- }
1370
- const dt = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n)?/, ss = 2;
1371
- function me(e) {
1372
- const t = e.content.match(dt);
1373
- if (!t) return null;
1374
- let n = null;
1375
- try {
1376
- const s = K(t[1]);
1377
- s && typeof s == "object" && !Array.isArray(s) && (n = s);
1378
- } catch {
1379
- }
1380
- return { yaml: t[1], data: n };
1381
- }
1382
- function ut(e, t) {
1383
- const n = new RegExp(`^\\s*${t}:`), s = e.split(`
1384
- `).findIndex((a) => n.test(a));
1385
- return s === -1 ? 1 : ss + s;
1386
- }
1387
- function ge(e) {
1388
- const t = me(e);
1389
- return t ? ut(t.yaml, "id") : 1;
1390
- }
1391
- function lt(e) {
1392
- var n, s;
1393
- const t = (s = (n = me(e)) == null ? void 0 : n.data) == null ? void 0 : s.id;
1394
- return typeof t == "string" ? t : e.id;
1395
- }
1396
- function R(e, t, n, s) {
1397
- return { file: e.path, line: t, rule: n, message: s };
1398
- }
1399
- const as = ({ files: e }) => e.flatMap((t) => {
1400
- const n = t.content.match(dt);
1401
- if (!n)
1402
- return [R(t, 1, "frontmatter-schema", "missing YAML frontmatter block")];
1403
- let s;
1404
- try {
1405
- s = K(n[1]);
1406
- } catch (i) {
1407
- return [R(t, 1, "frontmatter-schema", `invalid YAML: ${i.message}`)];
1408
- }
1409
- if (typeof s != "object" || s === null || Array.isArray(s))
1410
- return [R(t, 1, "frontmatter-schema", "frontmatter is not a key/value mapping")];
1411
- const a = nt.safeParse(s);
1412
- return a.success ? [] : a.error.issues.map((i) => {
1413
- const r = String(i.path[0] ?? ""), o = i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message;
1414
- return R(t, r ? ut(n[1], r) : 1, "frontmatter-schema", o);
1415
- });
1416
- }), is = ({ files: e }) => e.flatMap((t) => {
1417
- var s, a;
1418
- const n = (a = (s = me(t)) == null ? void 0 : s.data) == null ? void 0 : a.id;
1419
- return typeof n != "string" || n === t.id ? [] : [
1420
- R(
1421
- t,
1422
- ge(t),
1423
- "filename-id-mismatch",
1424
- `frontmatter id "${n}" does not match file name ${t.id}.md`
1425
- )
1426
- ];
1427
- }), rs = ({ files: e }) => {
1428
- const t = /* @__PURE__ */ new Map();
1429
- for (const s of e) {
1430
- const a = lt(s), i = t.get(a);
1431
- i ? i.push(s) : t.set(a, [s]);
1432
- }
1433
- const n = [];
1434
- for (const [s, a] of t) {
1435
- if (a.length < 2) continue;
1436
- const i = a.map((r) => r.path).join(", ");
1437
- for (const r of a)
1438
- n.push(
1439
- R(
1440
- r,
1441
- ge(r),
1442
- "duplicate-id",
1443
- `id ${s} is defined by ${a.length} files: ${i}`
1444
- )
1445
- );
1446
- }
1447
- return n;
1448
- }, os = ({ files: e, config: t }) => {
1449
- var s;
1450
- const n = (s = t == null ? void 0 : t.nextId) == null ? void 0 : s.idea;
1451
- return n == null ? [] : e.flatMap((a) => {
1452
- const i = lt(a), r = i.match(/^IDEA-(\d+)$/);
1453
- return r ? Number(r[1]) < n ? [] : [
1454
- R(
1455
- a,
1456
- ge(a),
1457
- "id-counter-stale",
1458
- `id ${i} is >= config nextId.idea (${n}); the next minted id would collide`
1459
- )
1460
- ] : [];
1461
- });
1462
- }, cs = ({ config: e }) => {
1463
- const t = e == null ? void 0 : e.version;
1464
- return typeof t != "number" || t <= I ? [] : [
1465
- {
1466
- file: "papercamp/config.json",
1467
- line: 1,
1468
- rule: "corpus-format-too-new",
1469
- message: `config.version ${t} is newer than the format version ${I} this paper-camp understands; writes are refused until it's upgraded`
1470
- }
1471
- ];
1472
- }, ds = [
1473
- as,
1474
- is,
1475
- rs,
1476
- os,
1477
- cs
1478
- ], us = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n)?/, ls = /^#{1,6}\s+(.+?)\s*$/, fs = /^[-*]\s+\[[ xX]\]\s+(.*)$/, ps = /^(phases|fixes)$/i, ft = /^#{1,6}\s+Phases\s*$/i, hs = /^(?:\d{4}-\d{2}-\d{2}\s+)?\[(?:log|clarification|review|note|decision|question|chat)\]/, ms = /^\[(?:phase:\d+|body)\]/, gs = /\[\[\s*((?:IDEA|TICKET)-\d+)(?:\s*\|[^\]]*)?\s*\]\]/g, ys = /* @__PURE__ */ new Set(["idea", "planned", "in-progress", "review", "open"]), ws = /* @__PURE__ */ new Set(["done", "dropped"]);
1479
- function ye(e) {
1480
- const t = e.match(us);
1481
- if (!t) return null;
1482
- try {
1483
- const n = K(t[1]);
1484
- if (n && typeof n == "object" && !Array.isArray(n))
1485
- return n;
1486
- } catch {
1487
- }
1488
- return null;
1489
- }
1490
- function bs(e, t) {
1491
- const n = e.split(`
1492
- `).findIndex((s) => t.test(s));
1493
- return n === -1 ? 1 : n + 1;
1494
- }
1495
- function N(e, t, n, s) {
1496
- return { file: e.path, line: t, rule: n, message: s };
1497
- }
1498
- const vs = ({ files: e }) => e.flatMap((t) => {
1499
- const n = t.content.split(`
1500
- `), s = [];
1501
- let a = !1;
1502
- for (let i = 0; i < n.length; i++) {
1503
- const r = n[i].match(ls);
1504
- if (r) {
1505
- a = ps.test(r[1].trim());
1506
- continue;
1507
- }
1508
- if (a) continue;
1509
- const o = n[i].match(fs);
1510
- if (!o) continue;
1511
- const c = o[1].trim();
1512
- hs.test(c) || ms.test(c) || s.push(
1513
- N(
1514
- t,
1515
- i + 1,
1516
- "phases-list-split",
1517
- `orphaned phase checkbox outside any Phases section: "${n[i].trim()}"`
1518
- )
1519
- );
1520
- }
1521
- return s;
1522
- }), Es = ({ files: e }) => e.flatMap((t) => {
1523
- var a;
1524
- if (((a = ye(t.content)) == null ? void 0 : a.kind) !== "note") return [];
1525
- const s = t.content.split(`
1526
- `).findIndex((i) => ft.test(i));
1527
- return s === -1 ? [] : [N(t, s + 1, "note-has-phases", "a kind: note entity carries a Phases section")];
1528
- }), ks = ({ files: e }) => e.flatMap((t) => t.content.split(`
1529
- `).flatMap((a, i) => ft.test(a) ? [i] : []).slice(1).map(
1530
- (a) => N(
1531
- t,
1532
- a + 1,
1533
- "duplicate-phases-section",
1534
- "a second Phases heading exists — a redraft must replace the existing list in place, not append a new one"
1535
- )
1536
- )), Ss = ({ files: e }) => e.flatMap((t) => {
1537
- var a;
1538
- const n = (a = ye(t.content)) == null ? void 0 : a.status;
1539
- if (typeof n != "string") return [];
1540
- const s = bs(t.content, /^status:/);
1541
- return t.archived && ys.has(n) ? [
1542
- N(
1543
- t,
1544
- s,
1545
- "archive-placement",
1546
- `status "${n}" is active but the file is under ideas/archive/`
1547
- )
1548
- ] : !t.archived && ws.has(n) ? [
1549
- N(
1550
- t,
1551
- s,
1552
- "archive-placement",
1553
- `status "${n}" is closed but the file is still under ideas/ — it should be archived`
1554
- )
1555
- ] : [];
1556
- }), $s = ({ files: e }) => {
1557
- var n;
1558
- const t = /* @__PURE__ */ new Set();
1559
- for (const s of e) {
1560
- t.add(s.id);
1561
- const a = (n = ye(s.content)) == null ? void 0 : n.id;
1562
- typeof a == "string" && t.add(a);
1563
- }
1564
- return e.flatMap((s) => {
1565
- const a = s.content.split(`
1566
- `), i = [];
1567
- for (let r = 0; r < a.length; r++)
1568
- for (const o of a[r].matchAll(gs))
1569
- t.has(o[1]) || i.push(
1570
- N(
1571
- s,
1572
- r + 1,
1573
- "dangling-link",
1574
- `[[${o[1]}]] points at an id no entity in the corpus defines`
1575
- )
1576
- );
1577
- return i;
1578
- });
1579
- }, Is = [
1580
- vs,
1581
- Es,
1582
- ks,
1583
- Ss,
1584
- $s
1585
- ], Rs = ".claude/settings.json", As = ({ hasPermissionsAllow: e }) => e === !1 ? [
1586
- {
1587
- file: Rs,
1588
- line: 1,
1589
- rule: "missing-permissions-allow",
1590
- message: "no permissions.allow list — headless runs deny every edit and shell command outside the defaults; run `paper-camp init --settings` to add it."
1591
- }
1592
- ] : [], Ps = [As], Ts = [
1593
- ...ds,
1594
- ...Is,
1595
- ...Ps
1596
- ];
1597
- function we(e) {
1598
- return (e == null ? void 0 : e.code) === "ENOENT";
1599
- }
1600
- async function Ns(e) {
1601
- try {
1602
- return await z(e);
1603
- } catch (t) {
1604
- if (we(t)) return [];
1605
- throw t;
1606
- }
1607
- }
1608
- async function Cs(e) {
1609
- let t;
1610
- try {
1611
- t = await v(e, "utf-8");
1612
- } catch (n) {
1613
- if (we(n)) return null;
1614
- throw n;
1615
- }
1616
- try {
1617
- return JSON.parse(t);
1618
- } catch {
1619
- return null;
1620
- }
1621
- }
1622
- async function _s(e) {
1623
- var n;
1624
- let t;
1625
- try {
1626
- t = await v(f(e, ".claude", "settings.json"), "utf-8");
1627
- } catch (s) {
1628
- if (we(s)) return !1;
1629
- throw s;
1630
- }
1631
- try {
1632
- const s = JSON.parse(t);
1633
- return Array.isArray((n = s.permissions) == null ? void 0 : n.allow) && s.permissions.allow.length > 0;
1634
- } catch {
1635
- return !1;
1636
- }
1637
- }
1638
- async function xs(e) {
1639
- const t = f(e, "ideas"), n = [], s = [
1640
- { dir: t, archived: !1, names: await z(t) },
1641
- {
1642
- dir: f(t, "archive"),
1643
- archived: !0,
1644
- names: await Ns(f(t, "archive"))
1645
- }
1646
- ];
1647
- for (const { dir: a, archived: i, names: r } of s) {
1648
- const o = r.filter((c) => c.endsWith(".md") && c !== "index.md").sort();
1649
- for (const c of o)
1650
- n.push({
1651
- id: _t(c, ".md"),
1652
- path: `papercamp/ideas${i ? "/archive" : ""}/${c}`,
1653
- content: await v(f(a, c), "utf-8"),
1654
- archived: i
1655
- });
1656
- }
1657
- return {
1658
- files: n,
1659
- config: await Cs(f(e, "config.json")),
1660
- hasPermissionsAllow: await _s(O(e))
1661
- };
1662
- }
1663
- function Os(e) {
1664
- return Ts.flatMap((t) => t(e));
1665
- }
1666
- async function xi(e) {
1667
- return Os(await xs(e));
1668
- }
1669
- const Ds = {
1670
- rule: "archive-placement",
1671
- fix: (e, t) => ({
1672
- kind: "move",
1673
- from: t.path,
1674
- to: t.archived ? t.path.replace("/archive/", "/") : t.path.replace(/\/(?=[^/]+$)/, "/archive/")
1675
- })
1676
- }, Ms = [Ds], js = new Map(
1677
- Ms.map((e) => [e.rule, e])
1678
- );
1679
- function Oi(e, t) {
1680
- const n = new Map(e.files.map((o) => [o.path, o])), s = [], a = [], i = [], r = [];
1681
- for (const o of t) {
1682
- const c = js.get(o.rule), u = n.get(o.file), l = c && u ? c.fix(o, u) : null;
1683
- if (!l) {
1684
- i.push(o);
1685
- continue;
1686
- }
1687
- if (l.kind === "move" && n.has(l.to)) {
1688
- r.push(o);
1689
- continue;
1690
- }
1691
- s.push(l), a.push(o);
1692
- }
1693
- return { actions: s, fixed: a, unfixable: i, rejected: r };
1694
- }
1695
- async function Y(e) {
1696
- try {
1697
- return await v(e, "utf-8");
1698
- } catch {
1699
- return "";
1700
- }
1701
- }
1702
- function pt(e, t) {
1703
- var n;
1704
- return (n = e.split(`
1705
- `).find((s) => s.includes(`(${t})`))) == null ? void 0 : n.trim();
1706
- }
1707
- const Ls = /^## \[.+?\]\(.*\/compare\/(.+?)\.\.\.(.+?)\)/;
1708
- function Fs(e) {
1709
- return e.split(`
1710
- `).map((t) => Ls.exec(t)).filter((t) => t !== null).map((t) => ({ version: t[2], range: `${t[1]}..${t[2]}` }));
1711
- }
1712
- function Hs(e, t) {
1713
- return e.split(`
1714
- `).find((n) => {
1715
- const s = n.match(/\/commit\/([0-9a-f]+)\)/i);
1716
- return s ? s[1].startsWith(t) || t.startsWith(s[1]) : !1;
1717
- });
1718
- }
1719
- const Gs = /^[a-z]+\/([a-z]+-\d+)-/;
1720
- async function Bs(e, t) {
1721
- var a;
1722
- const n = await C(e, [
1723
- "for-each-ref",
1724
- "--format=%(refname)",
1725
- "refs/heads",
1726
- "refs/remotes"
1727
- ]), s = t.toLowerCase();
1728
- for (const i of n.split(`
1729
- `)) {
1730
- const r = i.replace(/^refs\/heads\//, "").replace(/^refs\/remotes\/[^/]+\//, "");
1731
- if (((a = Gs.exec(r)) == null ? void 0 : a[1]) === s) return r;
1732
- }
1733
- }
1734
- async function Ys(e, t) {
1735
- const n = await Bs(e, t);
1736
- if (!n) return [];
1737
- const s = await He(e);
1738
- return (await C(e, ["log", "--format=%s", `${s}..${n}`])).split(`
1739
- `).map((i) => i.trim()).filter(Boolean);
1740
- }
1741
- async function qs(e, t) {
1742
- if (!en.test(t)) return null;
1743
- const n = await C(e, ["log", "-1", "--format=%B", t]), s = n ? Q(n) : null;
1744
- if (s) return s;
1745
- const a = await Y(f(e, "CHANGELOG.md")), i = Hs(a, t);
1746
- return i ? Q(i) : null;
1747
- }
1748
- async function Us(e, t) {
1749
- const s = (await C(e, ["log", "--format=%H", "--reverse", t])).split(`
1750
- `).map((r) => r.trim()).filter(Boolean), a = await Promise.all(s.map((r) => qs(e, r))), i = /* @__PURE__ */ new Map();
1751
- return s.forEach((r, o) => {
1752
- const c = a[o];
1753
- if (!c) return;
1754
- const u = i.get(c);
1755
- u ? u.push(r) : i.set(c, [r]);
1756
- }), i;
1757
- }
1758
- async function Di(e, t) {
1759
- const [{ entries: n }, s, a, i, r, o] = await Promise.all([
1760
- _(f(e, "papercamp", "ideas")),
1761
- Je(e),
1762
- Y(f(e, "papercamp", "tasks.log")),
1763
- Y(f(e, "CHANGELOG.md")),
1764
- Ys(e, t),
1765
- Ge(e)
1766
- ]), c = n.find((h) => h.id === t), u = s == null ? void 0 : s.get(t), l = Vn(a).filter((h) => h.planId === t), p = pt(i, t);
1767
- return {
1768
- id: t,
1769
- idea: c ? {
1770
- reached: !0,
1771
- data: {
1772
- title: c.title,
1773
- status: W(c, u, s !== void 0, o.has(t)),
1774
- type: c.type
1775
- }
1776
- } : { reached: !1 },
1777
- phases: c ? { reached: c.phases.length > 0, data: c.phases } : { reached: !1 },
1778
- taskRuns: l.length > 0 ? { reached: !0, data: l } : { reached: !1 },
1779
- commits: r.length > 0 ? { reached: !0, data: r } : { reached: !1 },
1780
- pr: u ? { reached: !0, data: u } : { reached: !1 },
1781
- releaseLine: p ? { reached: !0, data: p } : { reached: !1 }
1782
- };
1783
- }
1784
- const F = /^##\s+/, zs = /^##\s+The goal\s*$/i, ht = /^##\s+(Horizon\s+\d+\s*[—-].*)\r?$/i, Ks = /^##\s+Standing concerns\s*$/i, q = /^-\s+\*\*(.+?)\*\*\s+[—-]\s+(.*)\r?$/, Ws = /^\s+-\s+→\s+(.+?)\r?$/, mt = /^\s+-\s+(.+?)\r?$/, gt = /^\s+\S/;
1785
- function Ne(e, t, n) {
1786
- const s = [];
1787
- let a = t;
1788
- for (; a < n; ) {
1789
- const i = e[a].match(q);
1790
- if (!i) {
1791
- a++;
1792
- continue;
1793
- }
1794
- const r = [i[2].trim()], o = [], c = [];
1795
- for (a++; a < n && !q.test(e[a]); ) {
1796
- const u = e[a].match(Ws);
1797
- if (u) {
1798
- c.push(u[1].trim()), a++;
1799
- continue;
1800
- }
1801
- const l = e[a].match(mt);
1802
- if (l) {
1803
- o.push(l[1].trim()), a++;
1804
- continue;
1805
- }
1806
- if (!gt.test(e[a])) break;
1807
- r.push(e[a].trim()), a++;
1808
- }
1809
- s.push({ name: i[1].trim(), description: r.join(" "), candidates: o, linked: c });
1810
- }
1811
- return s;
1812
- }
1813
- function Js(e) {
1814
- const t = e.split(`
1815
- `);
1816
- let n = "";
1817
- const s = [];
1818
- let a = [];
1819
- for (let i = 0; i < t.length; i++) {
1820
- if (zs.test(t[i])) {
1821
- let o = i + 1;
1822
- for (; o < t.length && !F.test(t[o]); ) o++;
1823
- n = t.slice(i + 1, o).join(`
1824
- `).trim(), i = o - 1;
1825
- continue;
1826
- }
1827
- const r = t[i].match(ht);
1828
- if (r) {
1829
- let o = i + 1;
1830
- for (; o < t.length && !F.test(t[o]); ) o++;
1831
- s.push({ title: r[1].trim(), items: Ne(t, i + 1, o) }), i = o - 1;
1832
- continue;
1833
- }
1834
- if (Ks.test(t[i])) {
1835
- let o = i + 1;
1836
- for (; o < t.length && !F.test(t[o]); ) o++;
1837
- a = Ne(t, i + 1, o), i = o - 1;
1838
- }
1839
- }
1840
- return { goal: n, horizons: s, standingConcerns: a };
1841
- }
1842
- function yt(e, t) {
1843
- for (let n = 0; n < e.length; n++) {
1844
- const s = e[n].match(ht);
1845
- if (!s || s[1].trim() !== t) continue;
1846
- let a = n + 1;
1847
- for (; a < e.length && !F.test(e[a]); ) a++;
1848
- return { start: n + 1, end: a };
1849
- }
1850
- }
1851
- function be(e, t, n) {
1852
- const s = yt(e, t);
1853
- if (s)
1854
- for (let a = s.start; a < s.end; a++) {
1855
- const i = e[a].match(q);
1856
- if (!i || i[1].trim() !== n) continue;
1857
- let r = a + 1;
1858
- for (; r < s.end && !q.test(e[r]) && gt.test(e[r]); )
1859
- r++;
1860
- return { start: a, end: r };
1861
- }
1862
- }
1863
- function Mi(e, t, n, s) {
1864
- const a = e.split(`
1865
- `), i = be(a, t, n);
1866
- if (!i) return e;
1867
- if (s === void 0)
1868
- return a.splice(i.start, i.end - i.start), a.join(`
1869
- `);
1870
- for (let r = i.start + 1; r < i.end; r++) {
1871
- const o = a[r].match(mt);
1872
- if (o && o[1].trim() === s)
1873
- return a.splice(r, 1), a.join(`
1874
- `);
1875
- }
1876
- return e;
1877
- }
1878
- function ji(e, t, n, s) {
1879
- const a = e.split(`
1880
- `), i = yt(a, t);
1881
- if (!i) return e;
1882
- let r = i.end;
1883
- for (; r > i.start && a[r - 1].trim() === ""; ) r--;
1884
- return a.splice(r, 0, `- **${n}** — ${s}`), a.join(`
1885
- `);
1886
- }
1887
- function Li(e, t, n, s) {
1888
- const a = e.split(`
1889
- `), i = be(a, t, n);
1890
- return i ? (a.splice(i.end, 0, ` - ${s}`), a.join(`
1891
- `)) : e;
1892
- }
1893
- function Fi(e, t, n, s) {
1894
- const a = e.split(`
1895
- `), i = be(a, t, n);
1896
- return i ? (a.splice(i.end, 0, ` - → ${s}`), a.join(`
1897
- `)) : e;
1898
- }
1899
- function Vs(e) {
1900
- return [
1901
- ...e.horizons.flatMap((t) => t.items.map((n) => n.name)),
1902
- ...e.standingConcerns.map((t) => t.name)
1903
- ];
1904
- }
1905
- function Hi(e, t, n = [], s = "") {
1906
- const a = new Map(t.filter((c) => c.id).map((c) => [c.id, c])), i = /* @__PURE__ */ new Map();
1907
- for (const c of n)
1908
- c.planId && i.set(c.planId, (i.get(c.planId) ?? 0) + 1);
1909
- const r = e.horizons.map((c) => {
1910
- const u = c.items.map((p) => {
1911
- const h = p.linked.flatMap((g) => {
1912
- const m = a.get(g);
1913
- return m != null && m.status ? [
1914
- {
1915
- id: g,
1916
- status: m.status,
1917
- taskRuns: i.get(g) ?? 0,
1918
- pr: m.pr,
1919
- released: pt(s, g) !== void 0
1920
- }
1921
- ] : [];
1922
- }), w = { total: h.length, done: h.filter((g) => g.status === "done").length };
1923
- return { ...p, links: h, rollup: w };
1924
- }), l = u.reduce(
1925
- (p, h) => ({
1926
- total: p.total + h.rollup.total,
1927
- done: p.done + h.rollup.done
1928
- }),
1929
- { total: 0, done: 0 }
1930
- );
1931
- return { title: c.title, items: u, rollup: l };
1932
- }), o = Xs(e, t, n);
1933
- return { goal: e.goal, horizons: r, events: o };
1934
- }
1935
- function Xs(e, t, n) {
1936
- const s = /* @__PURE__ */ new Map();
1937
- for (const i of e.horizons)
1938
- for (const r of i.items)
1939
- for (const o of r.linked)
1940
- s.set(o, { horizonTitle: i.title, itemName: r.name });
1941
- const a = [];
1942
- for (const i of t) {
1943
- if (!i.id) continue;
1944
- const r = s.get(i.id);
1945
- r && a.push({
1946
- date: i.created,
1947
- kind: "created",
1948
- entityId: i.id,
1949
- horizonTitle: r.horizonTitle,
1950
- itemName: r.itemName,
1951
- label: `${i.title} created`
1952
- });
1953
- }
1954
- for (const i of n) {
1955
- if (!i.planId) continue;
1956
- const r = s.get(i.planId);
1957
- r && a.push({
1958
- date: i.startedAt,
1959
- kind: "task-run",
1960
- entityId: i.planId,
1961
- horizonTitle: r.horizonTitle,
1962
- itemName: r.itemName,
1963
- label: `${i.taskKind} run (${i.outcome})`
1964
- });
1965
- }
1966
- return a.sort((i, r) => Date.parse(i.date) - Date.parse(r.date));
1967
- }
1968
- function Zs(e) {
1969
- const t = JSON.stringify({
1970
- body: e.body,
1971
- phases: e.phases.map((n) => ({
1972
- done: n.done,
1973
- text: n.text,
1974
- description: n.description ?? null,
1975
- source: n.source ?? null
1976
- }))
1977
- });
1978
- return jt("sha256").update(t).digest("hex");
1979
- }
1980
- const ve = /* @__PURE__ */ new Set([
1981
- "core",
1982
- "cli",
1983
- "app",
1984
- "server",
1985
- "agent",
1986
- "audit",
1987
- "plans",
1988
- "ideas",
1989
- "docs",
1990
- "settings",
1991
- "stack",
1992
- "ui",
1993
- "ci",
1994
- "config",
1995
- "deps",
1996
- "repo",
1997
- "release",
1998
- "main"
1999
- ]);
2000
- function Qs(e, t) {
2001
- return (e == null ? void 0 : e.find((n) => ve.has(n))) ?? t;
2002
- }
2003
- function wt(e, t) {
2004
- return new Promise((n) => {
2005
- var i, r;
2006
- const s = b(
2007
- "gh",
2008
- ["pr", "view", t, "--json", "title,body,headRefName,labels,isDraft,state,url,comments"],
2009
- {
2010
- cwd: e,
2011
- stdio: ["ignore", "pipe", "pipe"]
2012
- }
2013
- );
2014
- let a = "";
2015
- (i = s.stdout) == null || i.on("data", (o) => {
2016
- a += o.toString();
2017
- }), (r = s.stderr) == null || r.on("data", () => {
2018
- }), s.on("close", (o) => {
2019
- if (o !== 0) {
2020
- n(void 0);
2021
- return;
2022
- }
2023
- try {
2024
- n(JSON.parse(a));
2025
- } catch {
2026
- n(void 0);
2027
- }
2028
- }), s.on("error", () => n(void 0));
2029
- });
2030
- }
2031
- const ea = 6e4;
2032
- function Gi(e, t, n = ea) {
2033
- return new Promise((s) => {
2034
- var r, o;
2035
- const a = b("gh", ["pr", "diff", t], { cwd: e, stdio: ["ignore", "pipe", "pipe"] });
2036
- let i = "";
2037
- (r = a.stdout) == null || r.on("data", (c) => {
2038
- i += c.toString();
2039
- }), (o = a.stderr) == null || o.on("data", () => {
2040
- }), a.on("close", (c) => {
2041
- if (c !== 0) {
2042
- s(void 0);
2043
- return;
2044
- }
2045
- s(
2046
- i.length > n ? `${i.slice(0, n)}
2047
- ... (diff truncated, exceeds size cap)` : i
2048
- );
2049
- }), a.on("error", () => s(void 0));
2050
- });
2051
- }
2052
- async function ta(e, t) {
2053
- for (const n of ["ideas", f("ideas", "archive")]) {
2054
- const s = f(e, "papercamp", n, `${t}.md`);
2055
- try {
2056
- return await Tt(s), s;
2057
- } catch {
2058
- }
2059
- }
2060
- return null;
2061
- }
2062
- async function P(e, t) {
2063
- const n = await wt(e, t), s = Ye(n == null ? void 0 : n.body, (n == null ? void 0 : n.headRefName) ?? t);
2064
- if (!s) return;
2065
- const a = await ta(e, s);
2066
- if (!a) return;
2067
- const { entries: i } = st(await v(a, "utf-8")), r = i[0];
2068
- if (r)
2069
- return { id: s, view: n, entry: r };
2070
- }
2071
- async function Bi(e, t) {
2072
- const n = await P(e, t);
2073
- if (!n) return;
2074
- const { id: s, entry: a } = n;
2075
- return { id: s, kind: a.type, tags: a.tags, phases: a.phases };
2076
- }
2077
- const bt = "<!-- papercamp:phases:start -->", vt = "<!-- papercamp:phases:end -->", Ce = new RegExp(`${bt}[\\s\\S]*?${vt}`);
2078
- function na(e, t) {
2079
- const n = t.map((i) => `- [${i.done ? "x" : " "}] ${i.text}`).join(`
2080
- `), s = `${bt}
2081
- ### Phases
2082
- ${n}
2083
- ${vt}`;
2084
- if (Ce.test(e)) return e.replace(Ce, () => s);
2085
- const a = e.trimEnd();
2086
- return a.length > 0 ? `${a}
2087
-
2088
- ${s}` : s;
2089
- }
2090
- function sa(e, t, n) {
2091
- return new Promise((s) => {
2092
- var i, r;
2093
- const a = b("gh", ["pr", "edit", t, "--body-file", "-"], {
2094
- cwd: e,
2095
- stdio: ["pipe", "ignore", "pipe"]
2096
- });
2097
- (i = a.stderr) == null || i.on("data", () => {
2098
- }), a.on("close", (o) => s(o === 0)), a.on("error", () => s(!1)), (r = a.stdin) == null || r.end(n);
2099
- });
2100
- }
2101
- async function Yi(e, t) {
2102
- const n = await P(e, t);
2103
- if (!(n != null && n.view)) return "unresolved";
2104
- const { view: s, entry: a } = n, i = na(s.body, a.phases);
2105
- return i === s.body ? "unchanged" : await sa(e, t, i) ? "updated" : "unresolved";
2106
- }
2107
- function aa(e) {
2108
- const t = /* @__PURE__ */ new Set();
2109
- e.kind && t.add(e.kind);
2110
- for (const n of e.tags)
2111
- ve.has(n) && t.add(n);
2112
- return [...t];
2113
- }
2114
- function ia(e) {
2115
- return new Promise((t) => {
2116
- var a, i;
2117
- const n = b("gh", ["label", "list", "--limit", "200", "--json", "name"], {
2118
- cwd: e,
2119
- stdio: ["ignore", "pipe", "pipe"]
2120
- });
2121
- let s = "";
2122
- (a = n.stdout) == null || a.on("data", (r) => {
2123
- s += r.toString();
2124
- }), (i = n.stderr) == null || i.on("data", () => {
2125
- }), n.on("close", (r) => {
2126
- if (r !== 0) {
2127
- t(void 0);
2128
- return;
2129
- }
2130
- try {
2131
- const o = JSON.parse(s);
2132
- t(new Set(o.map((c) => c.name)));
2133
- } catch {
2134
- t(void 0);
2135
- }
2136
- }), n.on("error", () => t(void 0));
2137
- });
2138
- }
2139
- function ra(e, t) {
2140
- return new Promise((n) => {
2141
- var a;
2142
- const s = b("gh", ["label", "create", t, "--color", "ededed"], {
2143
- cwd: e,
2144
- stdio: ["ignore", "ignore", "pipe"]
2145
- });
2146
- (a = s.stderr) == null || a.on("data", () => {
2147
- }), s.on("close", (i) => n(i === 0)), s.on("error", () => n(!1));
2148
- });
2149
- }
2150
- function oa(e, t, n) {
2151
- return new Promise((s) => {
2152
- var i;
2153
- const a = b("gh", ["pr", "edit", t, "--add-label", n.join(",")], {
2154
- cwd: e,
2155
- stdio: ["ignore", "ignore", "pipe"]
2156
- });
2157
- (i = a.stderr) == null || i.on("data", () => {
2158
- }), a.on("close", (r) => s(r === 0)), a.on("error", () => s(!1));
2159
- });
2160
- }
2161
- async function qi(e, t) {
2162
- const n = await P(e, t);
2163
- if (!(n != null && n.view)) return "unresolved";
2164
- const { view: s, entry: a } = n, i = aa({ kind: a.type, tags: a.tags }), r = new Set((s.labels ?? []).map((l) => l.name)), o = i.filter((l) => !r.has(l));
2165
- if (o.length === 0) return "unchanged";
2166
- const c = await ia(e);
2167
- if (c) {
2168
- const l = o.filter((p) => !c.has(p));
2169
- for (const p of l)
2170
- await ra(e, p);
2171
- }
2172
- return await oa(e, t, o) ? "updated" : "unresolved";
2173
- }
2174
- function Et(e, t) {
2175
- const n = t.type ?? "feat", s = Qs(t.tags, "repo");
2176
- return `${n}(${s}): ${t.title} (${e})`;
2177
- }
2178
- const ca = new RegExp(`^(${Mt.join("|")})\\(([a-z-]+)\\): .+$`);
2179
- function da(e) {
2180
- const t = e.match(ca);
2181
- return !!t && ve.has(t[2]);
2182
- }
2183
- function ua(e, t, n) {
2184
- return new Promise((s) => {
2185
- var i;
2186
- const a = b("gh", ["pr", "edit", t, "--title", n], {
2187
- cwd: e,
2188
- stdio: ["ignore", "ignore", "pipe"]
2189
- });
2190
- (i = a.stderr) == null || i.on("data", () => {
2191
- }), a.on("close", (r) => s(r === 0)), a.on("error", () => s(!1));
2192
- });
2193
- }
2194
- async function Ui(e, t) {
2195
- const n = await P(e, t);
2196
- if (!(n != null && n.view)) return "unresolved";
2197
- const { id: s, view: a, entry: i } = n, r = Et(s, i);
2198
- return a.title === r ? "unchanged" : await ua(e, t, r) ? "updated" : "unresolved";
2199
- }
2200
- async function zi(e, t) {
2201
- const n = await wt(e, t);
2202
- if (!n) return "no-pr";
2203
- const s = await P(e, t);
2204
- return s ? n.title === Et(s.id, s.entry) ? "valid" : "invalid" : da(n.title) ? "valid" : "invalid";
2205
- }
2206
- function Ki(e, t) {
2207
- return new Promise((n) => {
2208
- var i;
2209
- const s = b("gh", ["pr", "merge", t, "--squash"], {
2210
- cwd: e,
2211
- stdio: ["ignore", "ignore", "pipe"]
2212
- });
2213
- let a = "";
2214
- (i = s.stderr) == null || i.on("data", (r) => {
2215
- a += r.toString();
2216
- }), s.on("close", (r) => {
2217
- n(r === 0 ? { ok: !0 } : {
2218
- ok: !1,
2219
- message: a.trim() || `gh pr merge ${t} --squash exited with code ${r}`
2220
- });
2221
- }), s.on("error", (r) => n({ ok: !1, message: r.message }));
2222
- });
2223
- }
2224
- function la(e, t) {
2225
- return new Promise((n) => {
2226
- var a;
2227
- const s = b("gh", ["pr", "ready", t], {
2228
- cwd: e,
2229
- stdio: ["ignore", "ignore", "pipe"]
2230
- });
2231
- (a = s.stderr) == null || a.on("data", () => {
2232
- }), s.on("close", (i) => n(i === 0)), s.on("error", () => n(!1));
2233
- });
2234
- }
2235
- function fa(e, t) {
2236
- return new Promise((n) => {
2237
- var a;
2238
- const s = b("gh", ["pr", "close", t], {
2239
- cwd: e,
2240
- stdio: ["ignore", "ignore", "pipe"]
2241
- });
2242
- (a = s.stderr) == null || a.on("data", () => {
2243
- }), s.on("close", (i) => n(i === 0)), s.on("error", () => n(!1));
2244
- });
2245
- }
2246
- async function Wi(e, t) {
2247
- const n = await P(e, t);
2248
- if (!(n != null && n.view)) return "unresolved";
2249
- const { view: s, entry: a } = n;
2250
- return a.status === "dropped" ? s.state !== "OPEN" ? "unchanged" : await fa(e, t) ? "closed" : "unresolved" : !(a.phases.length > 0 && a.phases.every((o) => o.done)) || !s.isDraft ? "unchanged" : await la(e, t) ? "ready" : "unresolved";
2251
- }
2252
- const kt = "<!-- papercamp:consistency:start -->", pa = "<!-- papercamp:consistency:end -->";
2253
- function ha(e, t) {
2254
- const n = ["### Paper Camp checks", ""];
2255
- if (e.length === 0)
2256
- n.push("No consistency issues found.");
2257
- else
2258
- for (const s of e)
2259
- n.push(`- **${s.kind}** (${s.section}): ${s.message}`);
2260
- return t && (n.push(""), n.push(
2261
- t.stale ? `Convergence audit: last run \`${t.audited}\`, plan has changed since — due for a re-audit.` : `Convergence audit: last run \`${t.audited}\`, still current.`
2262
- )), `${kt}
2263
- ${n.join(`
2264
- `)}
2265
- ${pa}`;
2266
- }
2267
- function ma(e, t, n) {
2268
- return new Promise((s) => {
2269
- var i, r;
2270
- const a = b("gh", ["pr", "comment", t, "--body-file", "-"], {
2271
- cwd: e,
2272
- stdio: ["pipe", "ignore", "pipe"]
2273
- });
2274
- (i = a.stderr) == null || i.on("data", () => {
2275
- }), a.on("close", (o) => s(o === 0)), a.on("error", () => s(!1)), (r = a.stdin) == null || r.end(n);
2276
- });
2277
- }
2278
- function ga(e, t, n, s, a) {
2279
- return new Promise((i) => {
2280
- var o, c;
2281
- const r = b(
2282
- "gh",
2283
- [
2284
- "api",
2285
- `repos/${t}/${n}/issues/comments/${s}`,
2286
- "-X",
2287
- "PATCH",
2288
- "-F",
2289
- "body=@-"
2290
- ],
2291
- { cwd: e, stdio: ["pipe", "ignore", "pipe"] }
2292
- );
2293
- (o = r.stderr) == null || o.on("data", () => {
2294
- }), r.on("close", (u) => i(u === 0)), r.on("error", () => i(!1)), (c = r.stdin) == null || c.end(a);
2295
- });
2296
- }
2297
- async function Ji(e, t) {
2298
- var g, m;
2299
- const n = await P(e, t);
2300
- if (!((g = n == null ? void 0 : n.view) != null && g.url)) return "unresolved";
2301
- const { view: s, entry: a } = n, [{ entries: i }, r] = await Promise.all([
2302
- _(f(e, "papercamp", "ideas")),
2303
- v(f(e, "ROADMAP.md"), "utf-8").catch(() => "")
2304
- ]), o = i.filter((y) => y.kind !== "note").map((y) => Fe(y)), c = r ? Vs(Js(r)) : [], u = Jn(o, c), l = a.audited && a.auditedHash ? {
2305
- audited: a.audited,
2306
- stale: Zs(a) !== a.auditedHash
2307
- } : void 0, p = ha(u, l), h = (s.comments ?? []).find((y) => y.body.includes(kt));
2308
- if (h) {
2309
- if (h.body === p) return "unchanged";
2310
- const y = M(s.url), x = (m = h.url.match(/issuecomment-(\d+)/)) == null ? void 0 : m[1];
2311
- return !y || !x ? "unresolved" : await ga(e, y.owner, y.repo, x, p) ? "updated" : "unresolved";
2312
- }
2313
- return await ma(e, t, p) ? "created" : "unresolved";
2314
- }
2315
- function Vi(e, t, n) {
2316
- if (!e) return;
2317
- const s = (t ?? "feat").toLowerCase(), a = n.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, ""), i = a.length <= 40 ? a : a[40] === "-" ? a.slice(0, 40) : a.slice(0, 40).replace(/-[^-]*$/, "");
2318
- return `${s}/${e.toLowerCase()}-${i}`;
2319
- }
2320
- function V(e, t) {
2321
- for (const { entries: n, section: s } of t)
2322
- n && n.length > 0 && e.push(s.formatLines(n).join(`
2323
- `));
2324
- }
2325
- function St() {
2326
- return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2327
- }
2328
- function Xi(e, t = "log", n) {
2329
- return {
2330
- kind: t,
2331
- date: St(),
2332
- text: e,
2333
- from: "agent",
2334
- ...t === "question" ? { state: "open" } : {},
2335
- ...n ? { entityId: n } : {}
2336
- };
2337
- }
2338
- function Zi(e) {
2339
- const t = [`## ${e.title}`, "", `**Status:** ${e.status}`];
2340
- e.kind && t.push(`**Kind:** ${e.kind}`), e.id && t.push(`**Id:** ${e.id}`), e.idea && t.push(`**Idea:** ${e.idea}`), e.agent && t.push(`**Agent:** ${e.agent}`), t.push(`**Created:** ${e.created}`), e.updated && t.push(`**Updated:** ${e.updated}`), e.tags && e.tags.length > 0 && t.push(`**Tags:** ${e.tags.join(", ")}`);
2341
- const n = [t.join(`
2342
- `)];
2343
- return e.body && n.push(e.body), V(n, [
2344
- { entries: e.clarifications, section: ue },
2345
- { entries: e.phases, section: J },
2346
- { entries: e.log, section: j },
2347
- { entries: e.notes, section: le }
2348
- ]), n.join(`
2349
-
2350
- `).trimEnd();
2351
- }
2352
- function Ee(e) {
2353
- return `---
2354
- ${xt(e).trimEnd()}
2355
- ---`;
2356
- }
2357
- function Qi(e) {
2358
- const t = {
2359
- id: e.id,
2360
- title: e.title,
2361
- kind: e.kind,
2362
- status: e.status,
2363
- created: e.created
2364
- };
2365
- e.idea && (t.idea = e.idea), e.agent && (t.agent = e.agent), e.updated && (t.updated = e.updated), e.audited && (t.audited = e.audited), e.auditedHash && (t["audited-hash"] = e.auditedHash), e.tags && e.tags.length > 0 && (t.tags = e.tags);
2366
- const n = [Ee(t)];
2367
- return e.body && n.push(e.body), V(n, [
2368
- { entries: e.clarifications, section: ue },
2369
- { entries: e.phases, section: J },
2370
- { entries: e.log, section: j },
2371
- { entries: e.notes, section: le }
2372
- ]), n.join(`
2373
-
2374
- `).trimEnd();
2375
- }
2376
- function ya(e) {
2377
- const t = {
2378
- id: e.id,
2379
- title: e.title
2380
- };
2381
- e.type && (t.type = e.type), e.kind && (t.kind = e.kind), e.status && (t.status = e.status), e.idea && (t.idea = e.idea), t.created = e.created, e.agent && (t.agent = e.agent), e.updated && (t.updated = e.updated), e.audited && (t.audited = e.audited), e.auditedHash && (t["audited-hash"] = e.auditedHash), e.released && (t.released = e.released), e.tags && e.tags.length > 0 && (t.tags = e.tags), e.subject && (t.subject = e.subject), e.order !== void 0 && (t.order = e.order), e.issueSource && (t.issueSource = e.issueSource);
2382
- for (const s of Object.keys(e.unknownFrontmatter ?? {}).sort())
2383
- t[s] = e.unknownFrontmatter[s];
2384
- const n = [Ee(t)];
2385
- return e.body && n.push(e.body), V(n, [
2386
- { entries: e.phases, section: J },
2387
- { entries: e.fixes, section: Qe },
2388
- { entries: e.thread, section: et }
2389
- ]), n.join(`
2390
-
2391
- `).trimEnd();
2392
- }
2393
- function er(e) {
2394
- const t = {
2395
- id: e.id,
2396
- title: e.title
2397
- };
2398
- e.kind && (t.kind = e.kind), e.status && (t.status = e.status);
2399
- const n = [Ee(t)], s = `## ${e.id}: ${e.title}`;
2400
- return n.push(e.body ? `${s}
2401
-
2402
- ${e.body}` : s), V(n, [{ entries: e.log, section: j }]), n.join(`
2403
-
2404
- `).trimEnd();
2405
- }
2406
- function tr(e, t) {
2407
- let n = !1;
2408
- const s = e.split(`
2409
- `).filter((a) => {
2410
- if (!n) {
2411
- const i = a.match(at);
2412
- if (i && i[1] === t.date && i[2].trim() === t.title && i[3].trim() === t.description)
2413
- return n = !0, !1;
2414
- }
2415
- return !0;
2416
- });
2417
- return n ? s.join(`
2418
- `) : e;
2419
- }
2420
- let U = Promise.resolve();
2421
- async function wa(e, t) {
2422
- const n = new RegExp(`^${t.toUpperCase()}-(\\d+)\\.md$`), s = [
2423
- f(e, "ideas"),
2424
- f(e, "ideas", "archive"),
2425
- f(e, "plans"),
2426
- f(e, "plans", "archive")
2427
- ];
2428
- let a = 0;
2429
- for (const i of s) {
2430
- let r;
2431
- try {
2432
- r = await z(i);
2433
- } catch {
2434
- continue;
2435
- }
2436
- for (const o of r) {
2437
- const c = n.exec(o);
2438
- c && (a = Math.max(a, Number(c[1])));
2439
- }
2440
- }
2441
- return a;
2442
- }
2443
- async function $t(e, t) {
2444
- const n = U.then(async () => {
2445
- let s = null;
2446
- try {
2447
- s = JSON.parse(await v(e, "utf-8"));
2448
- } catch {
2449
- return;
2450
- }
2451
- if (!(s != null && s.nextId)) return;
2452
- const a = s.nextId[t] ?? 1, i = await wa(O(e), t), r = Math.max(a, i + 1), o = `${t.toUpperCase()}-${r}`;
2453
- return s.nextId[t] = r + 1, await E(e, `${JSON.stringify(s, null, 2)}
2454
- `), o;
2455
- });
2456
- return U = n.catch(() => {
2457
- }), n;
2458
- }
2459
- async function nr(e) {
2460
- return $t(e, "idea");
2461
- }
2462
- async function sr(e) {
2463
- return $t(e, "ticket");
2464
- }
2465
- async function ar(e, t) {
2466
- const n = U.then(async () => {
2467
- let s = null;
2468
- try {
2469
- s = JSON.parse(await v(e, "utf-8"));
2470
- } catch {
2471
- return;
2472
- }
2473
- const a = s.subjects ?? [];
2474
- a.includes(t) || (s.subjects = [...a, t], await E(e, `${JSON.stringify(s, null, 2)}
2475
- `));
2476
- });
2477
- return U = n.catch(() => {
2478
- }), n;
2479
- }
2480
- async function ir(e, t) {
2481
- const n = f(e, "papercamp", "ideas"), s = f(n, "archive"), a = f(n, `${t}.md`), i = f(s, `${t}.md`);
2482
- await A(s, { recursive: !0 });
2483
- try {
2484
- return await Nt(a, i), !0;
2485
- } catch (r) {
2486
- if (r.code === "ENOENT") return !1;
2487
- throw r;
2488
- }
2489
- }
2490
- const ba = [
2491
- ["pnpm-lock.yaml", "pnpm"],
2492
- ["yarn.lock", "yarn"],
2493
- ["bun.lockb", "bun"],
2494
- ["package-lock.json", "npm"]
2495
- ];
2496
- function It(e) {
2497
- for (const [t, n] of ba)
2498
- if (se(f(e, t))) return n;
2499
- return "npm";
2500
- }
2501
- function va(e) {
2502
- const t = f(e, "package.json");
2503
- if (se(t))
2504
- try {
2505
- return JSON.parse(De(t, "utf-8"));
2506
- } catch {
2507
- return;
2508
- }
2509
- }
2510
- const _e = "@dendelion/paper-camp";
2511
- function Ea(e) {
2512
- const t = va(e);
2513
- if (!t) return !1;
2514
- const n = t.dependencies, s = t.devDependencies;
2515
- return !!(n != null && n[_e] || s != null && s[_e]);
2516
- }
2517
- const ka = ["*.json", "*.ts", "*.tsx", "*.md", "*.config.*"], Sa = ["src/**", "app/**", "scripts/**", "papercamp/**"], $a = ["git status*", "git diff*", "git log*"], Ia = ["ls*", "cat*", "wc*"], Ra = ["run *", "test*", "install*", "view *", "pack*", "ls*"], Aa = ["npx tsc*", "npx biome check*", "npx vitest*", "npx jest*", "npx expo *"];
2518
- function Rt(e) {
2519
- const t = Sa.flatMap((a) => [`Edit(${a})`, `Write(${a})`]), n = ka.flatMap((a) => [`Edit(${a})`, `Write(${a})`]), s = [
2520
- ...$a,
2521
- ...Ia,
2522
- ...Ra.map((a) => `${e} ${a}`),
2523
- ...Aa
2524
- ].map((a) => `Bash(${a})`);
2525
- return [...t, ...n, ...s];
2526
- }
2527
- function Pa(e) {
2528
- return e ? `"${_a}" session-focus` : "paper-camp session-focus";
2529
- }
2530
- function Ta(e, t) {
2531
- let n;
2532
- try {
2533
- n = JSON.parse(e);
2534
- } catch {
2535
- return e;
2536
- }
2537
- const s = Rt(It(t)), a = n.permissions ?? {}, i = Array.isArray(a.allow) ? a.allow : [], r = s.filter((o) => !i.includes(o));
2538
- return r.length === 0 && n.permissions !== void 0 ? e : (n.permissions = { ...a, allow: [...i, ...r] }, `${JSON.stringify(n, null, 2)}
2539
- `);
2540
- }
2541
- function Na(e) {
2542
- const t = It(e), n = Pa(Ea(e));
2543
- return `${JSON.stringify(
2544
- {
2545
- permissions: {
2546
- allow: Rt(t)
2547
- },
2548
- hooks: {
2549
- SessionStart: [
2550
- {
2551
- matcher: "*",
2552
- hooks: [{ type: "command", command: n }]
2553
- }
2554
- ]
2555
- }
2556
- },
2557
- null,
2558
- 2
2559
- )}
2560
- `;
2561
- }
2562
- const Ca = `---
2563
- name: paper-camp
2564
- description: Work inside a project that has a papercamp/ folder — its unified idea entities (each holding its plan as a section), with decisions and open questions logged as notes on the idea they bind. Use this whenever the working directory contains papercamp/ (papercamp/ideas/), and especially before starting, continuing, or completing any plan phase, drafting an idea, logging a decision, or answering "what are we working on / what's next".
2565
- ---
2566
-
2567
- # Paper Camp
2568
-
2569
- Paper Camp is this project's planning methodology: plans and ideas are one
2570
- thing, a unified entity file under \`papercamp/ideas/\`, with decisions and
2571
- open questions logged as notes bound to the idea they concern. This skill
2572
- tells you how to read that state before acting and how to keep it honest as
2573
- you work.
2574
-
2575
- If a \`papercamp\` MCP server is connected in this session, prefer its tools
2576
- (list/get plans, update phase, etc.) over raw file access —
2577
- they enforce the same guards (id allocation, branch conflicts) that the file
2578
- grammar below assumes. Everything in this skill still applies conceptually;
2579
- only the mechanism changes.
2580
-
2581
- ## Before doing any work
2582
-
2583
- Read, in this order, whatever exists:
2584
-
2585
- 1. \`papercamp/ideas/\` — one file per entity, named by id. Ideas and plans are
2586
- one thing: an entity is an *idea* for its whole life, and its plan is a
2587
- \`### Phases\` section inside the same file.
2588
- 2. The specific entity file at \`papercamp/ideas/<ID>.md\` (e.g. \`IDEA-43.md\`)
2589
- for the work you're about to do — YAML frontmatter (\`id\`, \`title\`,
2590
- \`type\`, \`status\`, \`tags\`, ...) plus prose rationale, then optionally a
2591
- \`### Phases\` list of \`- [ ]\`/\`- [x]\` checkboxes with an indented
2592
- description under each. Done/dropped entities live in
2593
- \`papercamp/ideas/archive/\`.
2594
- Its notes carry any decision or open question bound to it — settled calls
2595
- you shouldn't re-litigate without flagging it to the user first, and
2596
- unresolved questions that might block or redirect the work you're about
2597
- to start.
2598
-
2599
- Skip files that don't exist yet (a fresh project may have empty logs).
2600
-
2601
- ## While working
2602
-
2603
- - Work one plan phase at a time unless told otherwise — don't cascade into
2604
- later phases just because they look quick.
2605
- - If a phase's boundary or intent is unclear, ask before continuing.
2606
- - Prose in plans and ideas is more current than your memory of past
2607
- conversations. If they conflict, the files win — say so and resync.
2608
-
2609
- ## Keep the project current as you go
2610
-
2611
- - **Plan phases**: when you finish a phase, flip its checkbox from \`- [ ]\` to
2612
- \`- [x]\` in the plan's frontmatter file. Change only that line — don't touch
2613
- other phases or prose.
2614
- - **Plan status**: keep the plan's \`status:\` frontmatter honest
2615
- (\`planned\` / \`in-progress\` / \`review\` / \`done\`). When every phase is
2616
- checked, set status to \`review\` — never \`done\`. \`done\` is a human-only
2617
- promotion after review; an agent finishing the last phase does not close
2618
- the plan itself.
2619
- - **Decisions / open questions**: if you settle something ambiguous while
2620
- working, log it as a decision note on the idea it bounds; if you surface a
2621
- question you can't resolve yourself, add it as a question note on that idea
2622
- rather than guessing silently.
2623
-
2624
- ## What this skill deliberately does not do
2625
-
2626
- It does not maintain a separate "current focus" file — that's derived at
2627
- session start from live plan data, not hand-maintained here. It does
2628
- not define the file formats in full; treat the existing files under
2629
- \`papercamp/\` as the grammar reference (mirror their structure exactly rather
2630
- than inventing a new shape).
2631
- `, _a = "$CLAUDE_PROJECT_DIR/node_modules/.bin/paper-camp", xa = 5;
2632
- function Oa() {
2633
- try {
2634
- let e = O(Lt(import.meta.url));
2635
- for (let t = 0; t < xa; t++) {
2636
- const n = f(e, "package.json");
2637
- if (se(n))
2638
- return JSON.parse(De(n, "utf-8")).version ?? "0.0.0";
2639
- e = O(e);
2640
- }
2641
- return "0.0.0";
2642
- } catch {
2643
- return "0.0.0";
2644
- }
2645
- }
2646
- const rr = Oa();
2647
- class Da extends Error {
2648
- constructor(t) {
2649
- super(`Paper Camp is already initialized in ${t} (papercamp/config.json exists).`);
2650
- }
2651
- }
2652
- async function T(e) {
2653
- try {
2654
- return await Ct(e), !0;
2655
- } catch {
2656
- return !1;
2657
- }
2658
- }
2659
- const Ma = ["suggestions.md"];
2660
- async function or(e, t) {
2661
- const n = f(e, "papercamp"), s = f(n, "config.json");
2662
- if (await T(s))
2663
- throw new Da(e);
2664
- const a = {
2665
- version: I,
2666
- projectName: t.projectName,
2667
- initializedAt: (/* @__PURE__ */ new Date()).toISOString(),
2668
- nextId: { idea: 2 }
2669
- };
2670
- Hn.parse(a), await A(n, { recursive: !0 });
2671
- const i = f(n, "ideas");
2672
- await A(i, { recursive: !0 });
2673
- const r = f(i, "archive");
2674
- await A(r, { recursive: !0 });
2675
- const o = f(i, "IDEA-1.md");
2676
- if (!await T(o)) {
2677
- const c = ya({
2678
- id: "IDEA-1",
2679
- title: "Capture your first idea",
2680
- status: "idea",
2681
- created: St(),
2682
- body: `This is an example idea, in the format Paper Camp expects: a short title, a status, and a paragraph of context. Read it, then archive or delete it once you've written your own.
2683
-
2684
- Use the New idea button to capture what you're building next, or ask an agent for suggestions.`
2685
- });
2686
- await E(o, `${c}
2687
- `, "utf-8");
2688
- }
2689
- for (const c of Ma) {
2690
- const u = f(n, c);
2691
- await T(u) || await E(u, "", "utf-8");
2692
- }
2693
- await E(s, `${JSON.stringify(a, null, 2)}
2694
- `, "utf-8"), await La(e), await Fa(e), await ja(e, t.projectName);
2695
- }
2696
- async function ja(e, t) {
2697
- const n = Gt(), s = await Bt(n), { registry: a, created: i } = Yt(s, e, t);
2698
- i && await qt(n, a);
2699
- }
2700
- const Z = "papercamp/.pairing.json";
2701
- async function La(e) {
2702
- const t = f(e, ".gitignore"), n = await T(t) ? await v(t, "utf-8") : "", s = n.length > 0 ? n.split(`
2703
- `) : [];
2704
- if (s.some((i) => i.trim() === Z)) return;
2705
- const a = s.reduce(
2706
- (i, r, o) => r.startsWith("papercamp/") ? o : i,
2707
- -1
2708
- );
2709
- if (a === -1) {
2710
- const i = n.length > 0 && !n.endsWith(`
2711
- `) ? `
2712
- ` : "";
2713
- await E(t, `${n}${i}${Z}
2714
- `, "utf-8");
2715
- return;
2716
- }
2717
- s.splice(a + 1, 0, Z), await E(t, s.join(`
2718
- `), "utf-8");
2719
- }
2720
- async function Fa(e) {
2721
- const t = f(e, ".claude", "skills", "paper-camp");
2722
- await A(t, { recursive: !0 });
2723
- const n = f(t, "SKILL.md");
2724
- await T(n) || await E(n, Ca, "utf-8");
2725
- const s = f(e, ".claude");
2726
- await A(s, { recursive: !0 });
2727
- const a = f(s, "settings.json");
2728
- if (await T(a)) {
2729
- const i = await v(a, "utf-8"), r = Ta(i, e);
2730
- r !== i && await E(a, r, "utf-8");
2731
- } else
2732
- await E(a, Na(e), "utf-8");
2733
- }
2734
- const At = {
2735
- feat: "Features",
2736
- fix: "Bug Fixes",
2737
- refactor: "Code Refactoring",
2738
- docs: "Documentation",
2739
- chore: "Miscellaneous"
2740
- }, Ha = Array.from(new Set(Object.values(At)));
2741
- async function cr(e, t) {
2742
- const n = await Y(f(e, "CHANGELOG.md")), s = Fs(n).find((o) => o.version === t);
2743
- if (!s) return null;
2744
- const [{ entries: a }, i] = await Promise.all([
2745
- _(f(e, "papercamp", "ideas")),
2746
- Us(e, s.range)
2747
- ]), r = /* @__PURE__ */ new Map();
2748
- for (const o of i.keys()) {
2749
- const c = a.find((p) => p.id === o);
2750
- if (!c) continue;
2751
- const u = At[c.type ?? "chore"], l = r.get(u) ?? [];
2752
- l.push({ id: c.id, title: c.title }), r.set(u, l);
2753
- }
2754
- return Ha.filter((o) => r.has(o)).map((o) => ({
2755
- label: o,
2756
- ideas: r.get(o)
2757
- }));
2758
- }
2759
- function dr(e, t) {
2760
- const n = [`## ${e}`];
2761
- for (const s of t) {
2762
- n.push("", `### ${s.label}`, "");
2763
- for (const a of s.ideas)
2764
- n.push(`- ${a.title} (${a.id})`);
2765
- }
2766
- return n.join(`
2767
- `);
2768
- }
2769
- function Ga(e) {
2770
- return Math.floor((Date.now() - Date.parse(e)) / 864e5);
2771
- }
2772
- const Ba = (e, t) => e === "question" && (t ?? "open") === "open";
2773
- function Ya(e) {
2774
- return e.flatMap(
2775
- (t) => (t.thread ?? []).filter((n) => Ba(n.kind, n.state)).map((n) => ({
2776
- entityId: t.id,
2777
- entityTitle: t.title,
2778
- text: n.text,
2779
- date: n.date,
2780
- ageDays: n.date ? Ga(n.date) : Number.POSITIVE_INFINITY
2781
- }))
2782
- ).sort((t, n) => n.ageDays - t.ageDays);
2783
- }
2784
- async function ur(e) {
2785
- const { entries: t } = await _(e);
2786
- return Ya(t);
2787
- }
2788
- const te = 0.95, Pt = 3e4, ne = {
2789
- implement: { from: 0, to: 0.6 },
2790
- verify: { from: 0.6, to: 0.9 },
2791
- checkbox: { from: 0.95, to: 0.95 }
2792
- }, xe = {
2793
- implement: 0,
2794
- verify: 1,
2795
- checkbox: 2
2796
- };
2797
- function Oe(e, ...t) {
2798
- for (const n of t)
2799
- if (typeof (e == null ? void 0 : e[n]) == "string") return e[n];
2800
- return "";
2801
- }
2802
- function lr(e, t) {
2803
- const n = e.toLowerCase();
2804
- if (n === "bash")
2805
- return (typeof (t == null ? void 0 : t.command) == "string" ? t.command : "").includes("check-types") ? "verify" : null;
2806
- if (n === "edit" || n === "multiedit" || n === "write") {
2807
- const s = Oe(t, "old_string", "oldString"), a = Oe(t, "new_string", "newString");
2808
- return s.includes("- [ ]") && a.includes("- [x]") ? "checkbox" : "implement";
2809
- }
2810
- return null;
2811
- }
2812
- function fr(e, t) {
2813
- return e ? xe[t] > xe[e] ? t : e : t;
2814
- }
2815
- function pr(e, t) {
2816
- return e === void 0 ? !1 : t - e >= Pt;
2817
- }
2818
- function qa(e) {
2819
- const t = [...e].sort((s, a) => s - a), n = Math.floor(t.length / 2);
2820
- return t.length % 2 === 0 ? (t[n - 1] + t[n]) / 2 : t[n];
2821
- }
2822
- function hr(e) {
2823
- const t = e.filter((a) => a.taskKind === "phase" && a.outcome === "done").map(
2824
- (a) => (a.endedAt ? Date.parse(a.endedAt) : Number.NaN) - Date.parse(a.startedAt)
2825
- ).filter((a) => Number.isFinite(a) && a > 0);
2826
- if (t.length === 0) return {};
2827
- const n = qa(t), s = {};
2828
- for (const a of ["implement", "verify"]) {
2829
- const i = ne[a].to - ne[a].from;
2830
- s[a] = n * i / te;
2831
- }
2832
- return s;
2833
- }
2834
- function mr({
2835
- anchor: e,
2836
- anchorEnteredAt: t,
2837
- lastStreamAt: n,
2838
- now: s,
2839
- medians: a
2840
- }) {
2841
- if (!e) return 0;
2842
- const i = ne[e], r = Math.min(i.from, te), o = a == null ? void 0 : a[e];
2843
- if (!o || o <= 0 || t === void 0 || i.to === i.from)
2844
- return r;
2845
- const c = n === void 0 ? s : Math.min(s, n + Pt), u = Math.min(1, Math.max(0, c - t) / o);
2846
- return Math.min(i.from + u * (i.to - i.from), te);
2847
- }
2848
- export {
2849
- Ai as $,
2850
- Da as A,
2851
- Et as B,
2852
- ve as C,
2853
- Ts as D,
2854
- ui as E,
2855
- $ as F,
2856
- aa as G,
2857
- Xs as H,
2858
- Vs as I,
2859
- Ti as J,
2860
- _n as K,
2861
- xn as L,
2862
- Pe as M,
2863
- On as N,
2864
- Cn as O,
2865
- rr as P,
2866
- It as Q,
2867
- li as R,
2868
- Ca as S,
2869
- ar as T,
2870
- pi as U,
2871
- Nn as V,
2872
- nt as W,
2873
- Qt as X,
2874
- Fe as Y,
2875
- Gi as Z,
2876
- oi as _,
2877
- en as a,
2878
- Hi as a$,
2879
- Jn as a0,
2880
- pt as a1,
2881
- B as a2,
2882
- ya as a3,
2883
- er as a4,
2884
- Zi as a5,
2885
- Qi as a6,
2886
- dr as a7,
2887
- hi as a8,
2888
- Ea as a9,
2889
- An as aA,
2890
- Pn as aB,
2891
- gi as aC,
2892
- yi as aD,
2893
- _ as aE,
2894
- Ii as aF,
2895
- Y as aG,
2896
- Pi as aH,
2897
- ur as aI,
2898
- Vn as aJ,
2899
- Ri as aK,
2900
- Mi as aL,
2901
- tr as aM,
2902
- ha as aN,
2903
- na as aO,
2904
- di as aP,
2905
- Ni as aQ,
2906
- qs as aR,
2907
- Di as aS,
2908
- Q as aT,
2909
- Us as aU,
2910
- Bi as aV,
2911
- Qs as aW,
2912
- Je as aX,
2913
- cr as aY,
2914
- Fs as aZ,
2915
- ci as a_,
2916
- Tn as aa,
2917
- or as ab,
2918
- da as ac,
2919
- pr as ad,
2920
- Fi as ae,
2921
- hr as af,
2922
- Ta as ag,
2923
- jn as ah,
2924
- Mn as ai,
2925
- Dn as aj,
2926
- Ln as ak,
2927
- Hn as al,
2928
- st as am,
2929
- ti as an,
2930
- pe as ao,
2931
- vi as ap,
2932
- Ei as aq,
2933
- ki as ar,
2934
- bi as as,
2935
- wi as at,
2936
- qn as au,
2937
- Js as av,
2938
- Si as aw,
2939
- fi as ax,
2940
- mr as ay,
2941
- Oi as az,
2942
- Ms as b,
2943
- xi as b0,
2944
- Os as b1,
2945
- Fa as b2,
2946
- dn as b3,
2947
- Ee as b4,
2948
- rt as b5,
2949
- Ki as b6,
2950
- Gn as b7,
2951
- Ji as b8,
2952
- Yi as b9,
2953
- qi as ba,
2954
- Wi as bb,
2955
- Ui as bc,
2956
- St as bd,
2957
- zi as be,
2958
- Fn as bf,
2959
- et as bg,
2960
- Ci as bh,
2961
- Xn as bi,
2962
- $i as bj,
2963
- si as bk,
2964
- ii as bl,
2965
- Le as bm,
2966
- C as bn,
2967
- ri as bo,
2968
- ai as bp,
2969
- Jt as bq,
2970
- _i as br,
2971
- es as c,
2972
- ts as d,
2973
- te as e,
2974
- Pt as f,
2975
- at as g,
2976
- Li as h,
2977
- ji as i,
2978
- fr as j,
2979
- S as k,
2980
- Xi as l,
2981
- ni as m,
2982
- ir as n,
2983
- nr as o,
2984
- $t as p,
2985
- sr as q,
2986
- Vi as r,
2987
- Na as s,
2988
- Rt as t,
2989
- Pa as u,
2990
- lr as v,
2991
- mi as w,
2992
- xs as x,
2993
- Ya as y,
2994
- Zs as z
2995
- };
2996
- //# sourceMappingURL=phase-progress.6EDoT9B0.js.map