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