@dendelion/paper-camp 0.32.0 → 0.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/dist/chunks/{daemon-state.61FBbbsV.js → daemon-state.BeDnhzBY.js} +47 -43
  3. package/dist/chunks/daemon-state.BeDnhzBY.js.map +1 -0
  4. package/dist/chunks/phase-progress.cMGsSLa8.js +3003 -0
  5. package/dist/chunks/phase-progress.cMGsSLa8.js.map +1 -0
  6. package/dist/cli/index.js +5933 -21107
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/core/ci/ci-release.d.ts +9 -1
  9. package/dist/core/ci/ci-release.d.ts.map +1 -1
  10. package/dist/core/daemon-state/daemon-state.d.ts +1 -0
  11. package/dist/core/daemon-state/daemon-state.d.ts.map +1 -1
  12. package/dist/core/doctor/checks/tooling.d.ts +3 -0
  13. package/dist/core/doctor/checks/tooling.d.ts.map +1 -0
  14. package/dist/core/doctor/checks/tooling.test.d.ts +2 -0
  15. package/dist/core/doctor/checks/tooling.test.d.ts.map +1 -0
  16. package/dist/core/doctor/doctor.d.ts +1 -0
  17. package/dist/core/doctor/doctor.d.ts.map +1 -1
  18. package/dist/core/doctor/doctor.test.d.ts +2 -0
  19. package/dist/core/doctor/doctor.test.d.ts.map +1 -0
  20. package/dist/core/doctor/rules.d.ts +6 -1
  21. package/dist/core/doctor/rules.d.ts.map +1 -1
  22. package/dist/core/git-pr/pr-lookup.d.ts +11 -0
  23. package/dist/core/git-pr/pr-lookup.d.ts.map +1 -1
  24. package/dist/core/git-pr/pr.d.ts +1 -1
  25. package/dist/core/git-pr/pr.d.ts.map +1 -1
  26. package/dist/core/index.js +172 -157
  27. package/dist/core/notifications.d.ts +3 -1
  28. package/dist/core/notifications.d.ts.map +1 -1
  29. package/dist/core/parse/parser.d.ts.map +1 -1
  30. package/dist/core/parse/schemas.d.ts +60 -0
  31. package/dist/core/parse/schemas.d.ts.map +1 -1
  32. package/dist/core/push-send.d.ts +14 -0
  33. package/dist/core/push-send.d.ts.map +1 -0
  34. package/dist/core/push-send.test.d.ts +2 -0
  35. package/dist/core/push-send.test.d.ts.map +1 -0
  36. package/dist/core/push-store.d.ts +37 -0
  37. package/dist/core/push-store.d.ts.map +1 -0
  38. package/dist/core/push-store.test.d.ts +2 -0
  39. package/dist/core/push-store.test.d.ts.map +1 -0
  40. package/dist/core/run-rows.d.ts +3 -0
  41. package/dist/core/run-rows.d.ts.map +1 -1
  42. package/dist/core/scaffold/scaffold.d.ts +1 -0
  43. package/dist/core/scaffold/scaffold.d.ts.map +1 -1
  44. package/dist/core/scaffold/templates.d.ts +7 -1
  45. package/dist/core/scaffold/templates.d.ts.map +1 -1
  46. package/dist/core/scaffold/templates.test.d.ts +2 -0
  47. package/dist/core/scaffold/templates.test.d.ts.map +1 -0
  48. package/dist/core/stats.d.ts.map +1 -1
  49. package/dist/core/vapid-keys.d.ts +7 -0
  50. package/dist/core/vapid-keys.d.ts.map +1 -0
  51. package/dist/core/vapid-keys.test.d.ts +2 -0
  52. package/dist/core/vapid-keys.test.d.ts.map +1 -0
  53. package/dist/toolbar/toolbar.js +3652 -3666
  54. package/dist/toolbar/toolbar.js.map +1 -1
  55. package/dist/types/index.d.ts +20 -6
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/index.js +44 -22
  58. package/dist/types/index.js.map +1 -1
  59. package/dist/vite/index.js +1 -1
  60. package/package.json +7 -2
  61. package/dist/chunks/daemon-state.61FBbbsV.js.map +0 -1
  62. package/dist/chunks/phase-progress.Cos0IBFk.js +0 -7338
  63. package/dist/chunks/phase-progress.Cos0IBFk.js.map +0 -1
package/README.md CHANGED
@@ -23,7 +23,7 @@ paper-camp start
23
23
  ```
24
24
 
25
25
  Open the Local link `start` prints — it opens
26
- [the hosted client](https://paper-camp.vercel.app), the one dashboard for
26
+ [the hosted client](https://paper.adoo.one), the one dashboard for
27
27
  every project this package runs, pointed at the API `start` just launched on
28
28
  this machine. `~/dev` stands for the folder holding your repositories;
29
29
  `paper-camp init` run inside a single repo registers just that one instead of
@@ -1,5 +1,5 @@
1
1
  import { randomBytes as $ } from "node:crypto";
2
- import { readFile as l, mkdir as j, writeFile as w, rename as k, readdir as b, access as N, rm as v } from "node:fs/promises";
2
+ import { readFile as p, mkdir as j, writeFile as w, rename as k, readdir as b, access as N, rm as v } from "node:fs/promises";
3
3
  import { join as c, dirname as M, resolve as P, basename as m } from "node:path";
4
4
  import { MACHINE_PROJECTS_PATH as D, MACHINE_NIGHT_PATH as E } from "../types/index.js";
5
5
  import { homedir as A } from "node:os";
@@ -85,7 +85,7 @@ function _(t) {
85
85
  async function rt(t) {
86
86
  let n;
87
87
  try {
88
- n = await l(t, "utf-8");
88
+ n = await p(t, "utf-8");
89
89
  } catch (e) {
90
90
  return e.code !== "ENOENT" && console.error("paper-camp: could not read machine registry:", e), f;
91
91
  }
@@ -102,10 +102,10 @@ async function st(t, n) {
102
102
  await w(e, `${JSON.stringify(n, null, 2)}
103
103
  `, "utf-8"), await k(e, t);
104
104
  }
105
- function x(t) {
105
+ function L(t) {
106
106
  return t.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
107
107
  }
108
- function L(t, n) {
108
+ function x(t, n) {
109
109
  if (!n.has(t)) return t;
110
110
  let e = 2;
111
111
  for (; n.has(`${t}-${e}`); ) e++;
@@ -114,7 +114,7 @@ function L(t, n) {
114
114
  function at(t, n, e) {
115
115
  const o = P(n), r = t.projects.find((a) => a.path === o);
116
116
  if (r) return { registry: t, entry: r, created: !1 };
117
- const s = new Set(t.projects.map((a) => a.slug)), i = { slug: L(x(m(o)), s), path: o, name: e ?? m(o) };
117
+ const s = new Set(t.projects.map((a) => a.slug)), i = { slug: x(L(m(o)), s), path: o, name: e ?? m(o) };
118
118
  return {
119
119
  registry: { ...t, projects: [...t.projects, i] },
120
120
  entry: i,
@@ -138,7 +138,7 @@ function ft(t) {
138
138
  const { night: n, ...e } = t;
139
139
  return e;
140
140
  }
141
- function pt(t, n) {
141
+ function lt(t, n) {
142
142
  if (!t.night) return t;
143
143
  if (n === null) {
144
144
  const { pausedUntil: e, ...o } = t.night;
@@ -146,7 +146,7 @@ function pt(t, n) {
146
146
  }
147
147
  return { ...t, night: { ...t.night, pausedUntil: n } };
148
148
  }
149
- async function lt(t) {
149
+ async function pt(t) {
150
150
  try {
151
151
  return await N(c(t, "papercamp", "config.json")), !1;
152
152
  } catch {
@@ -156,7 +156,7 @@ async function lt(t) {
156
156
  async function F(t, n) {
157
157
  let e;
158
158
  try {
159
- e = await l(t, "utf-8");
159
+ e = await p(t, "utf-8");
160
160
  } catch {
161
161
  return { hasConfig: !1, name: n };
162
162
  }
@@ -179,18 +179,21 @@ async function dt(t) {
179
179
  }
180
180
  return o.sort((r, s) => r.name.localeCompare(s.name));
181
181
  }
182
- function mt() {
183
- return c(d(), "daemon.json");
182
+ function mt(t) {
183
+ return t.tailnet ?? t.tunnel;
184
184
  }
185
185
  function ht() {
186
+ return c(d(), "daemon.json");
187
+ }
188
+ function gt() {
186
189
  return c(d(), "daemon.log");
187
190
  }
188
- function p(t) {
191
+ function l(t) {
189
192
  return t === void 0 || typeof t == "string";
190
193
  }
191
194
  function H(t) {
192
195
  const n = t;
193
- return typeof n == "object" && n !== null && typeof n.host == "string" && p(n.network) && p(n.tailnet) && p(n.tunnel);
196
+ return typeof n == "object" && n !== null && typeof n.host == "string" && l(n.network) && l(n.tailnet) && l(n.tunnel);
194
197
  }
195
198
  function J(t) {
196
199
  const n = t;
@@ -210,10 +213,10 @@ function U(t) {
210
213
  const n = t;
211
214
  return typeof n == "object" && n !== null && typeof n.pid == "number" && typeof n.port == "number" && typeof n.version == "string" && typeof n.startedAt == "string" && typeof n.share == "boolean" && typeof n.tailnet == "boolean" && (n.updateEvent === void 0 || J(n.updateEvent)) && (n.updatePendingVersion === void 0 || n.updatePendingVersion === null || typeof n.updatePendingVersion == "string") && (n.links === void 0 || H(n.links));
212
215
  }
213
- async function V(t) {
216
+ async function B(t) {
214
217
  let n;
215
218
  try {
216
- n = await l(t, "utf-8");
219
+ n = await p(t, "utf-8");
217
220
  } catch {
218
221
  return;
219
222
  }
@@ -224,7 +227,7 @@ async function V(t) {
224
227
  return;
225
228
  }
226
229
  }
227
- function B(t) {
230
+ function V(t) {
228
231
  try {
229
232
  return process.kill(t, 0), !0;
230
233
  } catch {
@@ -245,7 +248,7 @@ async function G(t) {
245
248
  async function q(t) {
246
249
  return await G(t) !== null;
247
250
  }
248
- async function gt(t) {
251
+ async function yt(t) {
249
252
  try {
250
253
  const n = await fetch(`http://localhost:${t}${E}`, {
251
254
  signal: AbortSignal.timeout(S)
@@ -255,11 +258,11 @@ async function gt(t) {
255
258
  return null;
256
259
  }
257
260
  }
258
- async function yt(t) {
259
- const n = await V(t);
260
- return n !== void 0 && B(n.pid) && await q(n.port) ? n : (await Y(t), null);
261
+ async function $t(t) {
262
+ const n = await B(t);
263
+ return n !== void 0 && V(n.pid) && await q(n.port) ? n : (await Y(t), null);
261
264
  }
262
- function $t(t) {
265
+ function jt(t) {
263
266
  const n = T(Date.now() - Date.parse(t.startedAt)), e = [t.share && "share", t.tailnet && "tailnet"].filter(Boolean).join(", ");
264
267
  return `paper-camp: daemon running — pid ${t.pid}, port ${t.port}, v${t.version}, up ${n}${e ? `, ${e}` : ""}`;
265
268
  }
@@ -267,7 +270,7 @@ function z(t) {
267
270
  const n = new Date(t), e = (o) => String(o).padStart(2, "0");
268
271
  return `${e(n.getHours())}:${e(n.getMinutes())}`;
269
272
  }
270
- function jt(t) {
273
+ function wt(t) {
271
274
  if (t.updatePendingVersion)
272
275
  return `paper-camp: update to ${t.updatePendingVersion} pending, waiting for idle`;
273
276
  const n = t.updateEvent;
@@ -281,7 +284,7 @@ function jt(t) {
281
284
  return `paper-camp: ${n.version} installed but did not take effect — run \`paper-camp update\``;
282
285
  }
283
286
  }
284
- function wt(t) {
287
+ function kt(t) {
285
288
  const e = [
286
289
  ["This host", t.host],
287
290
  ["Network", t.network],
@@ -291,7 +294,7 @@ function wt(t) {
291
294
  return e.map(([r, s]) => `${r.padEnd(o)} ${s}`).join(`
292
295
  `);
293
296
  }
294
- async function kt(t, n) {
297
+ async function Mt(t, n) {
295
298
  await j(M(t), { recursive: !0 });
296
299
  const e = `${t}.${$(6).toString("hex")}.tmp`;
297
300
  await w(e, `${JSON.stringify(n, null, 2)}
@@ -301,32 +304,33 @@ async function Y(t) {
301
304
  await v(t, { force: !0 });
302
305
  }
303
306
  export {
304
- et as A,
307
+ tt as A,
308
+ et as B,
305
309
  at as a,
306
- mt as b,
310
+ ht as b,
307
311
  ft as c,
308
- ht as d,
312
+ gt as d,
309
313
  ot as e,
310
- gt as f,
314
+ yt as f,
311
315
  G as g,
312
- wt as h,
313
- $t as i,
314
- jt as j,
315
- B as k,
316
- lt as l,
316
+ kt as h,
317
+ jt as i,
318
+ wt as j,
319
+ V as k,
320
+ pt as l,
317
321
  ct as m,
318
322
  rt as n,
319
323
  d as o,
320
324
  q as p,
321
- Y as q,
322
- yt as r,
323
- it as s,
324
- st as t,
325
- dt as u,
326
- pt as v,
327
- ut as w,
328
- kt as x,
329
- nt as y,
330
- tt as z
325
+ mt as q,
326
+ $t as r,
327
+ Y as s,
328
+ it as t,
329
+ st as u,
330
+ dt as v,
331
+ lt as w,
332
+ ut as x,
333
+ Mt as y,
334
+ nt as z
331
335
  };
332
- //# sourceMappingURL=daemon-state.61FBbbsV.js.map
336
+ //# sourceMappingURL=daemon-state.BeDnhzBY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-state.BeDnhzBY.js","sources":["../../src/core/phase-run.ts","../../src/core/machine-registry/machine-registry.ts","../../src/core/daemon-state/daemon-state.ts"],"sourcesContent":["import type { PhaseRun, RunUsage, TaskLogEntry } from '../types/index';\n\nfunction trimDecimal(value: number, places: number): string {\n return value\n .toFixed(places)\n .replace(/\\.0+$/, '')\n .replace(/(\\.\\d*?)0+$/, '$1');\n}\n\nexport function formatDuration(ms: number): string {\n const totalSeconds = Math.round(ms / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n if (hours > 0) return minutes > 0 ? `${hours}h${minutes}m` : `${hours}h`;\n if (minutes > 0) return seconds > 0 ? `${minutes}m${seconds}s` : `${minutes}m`;\n return `${seconds}s`;\n}\n\nfunction parseDuration(text: string): number | null {\n const match = text.match(/^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/);\n if (!match || (!match[1] && !match[2] && !match[3])) return null;\n const hours = Number(match[1] ?? 0);\n const minutes = Number(match[2] ?? 0);\n const seconds = Number(match[3] ?? 0);\n return (hours * 3600 + minutes * 60 + seconds) * 1000;\n}\n\nexport function formatTokens(n: number): string {\n if (n >= 1_000_000) return `${trimDecimal(n / 1_000_000, 1)}M`;\n if (n >= 1000) return `${trimDecimal(n / 1000, 1)}k`;\n return `${Math.round(n)}`;\n}\n\nfunction parseTokens(text: string): number {\n const match = text.match(/^([\\d.]+)([kM]?)$/);\n if (!match) return 0;\n const value = Number(match[1]);\n if (!Number.isFinite(value)) return 0;\n if (match[2] === 'M') return Math.round(value * 1_000_000);\n if (match[2] === 'k') return Math.round(value * 1000);\n return Math.round(value);\n}\n\nexport function shortModel(model: string): string {\n return model\n .replace(/^(?:[\\w.]+\\.)?anthropic\\./, '')\n .replace(/^claude-/, '')\n .replace(/-\\d{6,8}$/, '');\n}\n\nexport function formatRunSummary(run: PhaseRun): string {\n const base = `${formatTokens(run.inputTokens + run.outputTokens)} tokens · ${formatDuration(run.durationMs)}${run.attempts > 1 ? ` ×${run.attempts}` : ''}${run.model ? ` · ${run.model}` : ''}`;\n return run.sessionId ? `${base} · session ${run.sessionId.slice(0, 8)}` : base;\n}\n\nexport function formatRunLine(run: PhaseRun): string {\n const parts = [\n formatDuration(run.durationMs),\n `${formatTokens(run.inputTokens)} in`,\n `${formatTokens(run.outputTokens)} out`,\n ];\n if (run.model) parts.push(run.model);\n if (run.attempts > 1) parts.push(`×${run.attempts}`);\n if (run.sessionId) parts.push(`sess:${run.sessionId}`);\n return parts.join(' · ');\n}\n\nexport function parseRunLine(value: string): PhaseRun | undefined {\n const segments = value\n .split('·')\n .map((s) => s.trim())\n .filter(Boolean);\n if (segments.length === 0) return undefined;\n const durationMs = parseDuration(segments[0]);\n if (durationMs === null) return undefined;\n const run: PhaseRun = {\n durationMs,\n inputTokens: 0,\n outputTokens: 0,\n attempts: 1,\n };\n for (const segment of segments.slice(1)) {\n const inMatch = segment.match(/^(.+)\\s+in$/);\n const outMatch = segment.match(/^(.+)\\s+out$/);\n const attemptMatch = segment.match(/^×(\\d+)$/);\n const sessionMatch = segment.match(/^sess:(.+)$/);\n if (inMatch) run.inputTokens = parseTokens(inMatch[1]);\n else if (outMatch) run.outputTokens = parseTokens(outMatch[1]);\n else if (attemptMatch) run.attempts = Number(attemptMatch[1]);\n else if (sessionMatch) run.sessionId = sessionMatch[1];\n else run.model = segment;\n }\n return run;\n}\n\nexport function mergeRun(\n prev: PhaseRun | undefined,\n usage: RunUsage,\n sessionId?: string,\n): PhaseRun {\n return {\n durationMs: (prev?.durationMs ?? 0) + usage.durationMs,\n inputTokens: (prev?.inputTokens ?? 0) + usage.inputTokens,\n outputTokens: (prev?.outputTokens ?? 0) + usage.outputTokens,\n model: usage.model ? shortModel(usage.model) : prev?.model,\n attempts: (prev?.attempts ?? 0) + 1,\n sessionId: sessionId ?? prev?.sessionId,\n };\n}\n\nexport interface UsageRollup {\n runs: number;\n durationMs: number;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n}\n\nexport function rollupUsage(taskRuns: TaskLogEntry[], planId?: string): UsageRollup {\n const rollup: UsageRollup = {\n runs: 0,\n durationMs: 0,\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n };\n const add = (usage: RunUsage) => {\n rollup.runs += 1;\n rollup.durationMs += usage.durationMs;\n rollup.inputTokens += usage.inputTokens;\n rollup.outputTokens += usage.outputTokens;\n rollup.cacheCreationTokens += usage.cacheCreationTokens;\n rollup.cacheReadTokens += usage.cacheReadTokens;\n };\n for (const entry of taskRuns) {\n if (planId && entry.planId !== planId) continue;\n if (entry.phaseRuns?.length) for (const p of entry.phaseRuns) add(p.usage);\n else if (entry.usage) add(entry.usage);\n }\n return rollup;\n}\n","import { randomBytes } from 'node:crypto';\nimport { access, mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { basename, dirname, join, resolve } from 'node:path';\n\nexport interface MachineProject {\n slug: string;\n path: string;\n name: string;\n}\n\nexport interface NightSelection {\n slug: string;\n pausedUntil?: number;\n}\n\nexport interface MachineRegistry {\n version: 1;\n projects: MachineProject[];\n /** The one project `paper-camp daemon` runs the night shift for (IDEA-241); absent means off. */\n night?: NightSelection;\n}\n\nconst EMPTY_REGISTRY: MachineRegistry = { version: 1, projects: [] };\n\nexport function machineConfigDir(): string {\n return process.env.PAPERCAMP_CONFIG_DIR ?? join(homedir(), '.config', 'paper-camp');\n}\n\nexport function defaultRegistryPath(): string {\n return join(machineConfigDir(), 'projects.json');\n}\n\nfunction isMachineProject(value: unknown): value is MachineProject {\n const v = value as Partial<MachineProject> | null;\n return (\n typeof v === 'object' &&\n v !== null &&\n typeof v.slug === 'string' &&\n typeof v.path === 'string' &&\n typeof v.name === 'string'\n );\n}\n\nfunction isNightSelection(value: unknown): value is NightSelection {\n const v = value as Partial<NightSelection> | null;\n return (\n typeof v === 'object' &&\n v !== null &&\n typeof v.slug === 'string' &&\n (v.pausedUntil === undefined || typeof v.pausedUntil === 'number')\n );\n}\n\nfunction isMachineRegistry(value: unknown): value is MachineRegistry {\n const v = value as Partial<MachineRegistry> | null;\n return (\n typeof v === 'object' &&\n v !== null &&\n v.version === 1 &&\n Array.isArray(v.projects) &&\n v.projects.every(isMachineProject) &&\n (v.night === undefined || isNightSelection(v.night))\n );\n}\n\n/** Resolves the empty registry on a missing or malformed file — same first-boot\n * path a revoked or never-written file takes. */\nexport async function loadRegistry(path: string): Promise<MachineRegistry> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.error('paper-camp: could not read machine registry:', error);\n }\n return EMPTY_REGISTRY;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isMachineRegistry(parsed) ? parsed : EMPTY_REGISTRY;\n } catch {\n return EMPTY_REGISTRY;\n }\n}\n\n/** Written to a sibling temp path and renamed into place, so a crash mid-write\n * never leaves `loadRegistry` a truncated file to trip over. */\nexport async function saveRegistry(path: string, registry: MachineRegistry): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.${randomBytes(6).toString('hex')}.tmp`;\n await writeFile(tmpPath, `${JSON.stringify(registry, null, 2)}\\n`, 'utf-8');\n await rename(tmpPath, path);\n}\n\nfunction slugify(input: string): string {\n const slug = input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return slug || 'project';\n}\n\nfunction uniqueSlug(base: string, taken: ReadonlySet<string>): string {\n if (!taken.has(base)) return base;\n let suffix = 2;\n while (taken.has(`${base}-${suffix}`)) suffix++;\n return `${base}-${suffix}`;\n}\n\nexport interface AddProjectResult {\n registry: MachineRegistry;\n entry: MachineProject;\n created: boolean;\n}\n\n/** Dedupes by resolved absolute path — re-adding an already-registered project\n * returns its existing entry rather than minting a second slug for it. */\nexport function addProject(\n registry: MachineRegistry,\n projectPath: string,\n name?: string,\n): AddProjectResult {\n const path = resolve(projectPath);\n const existing = registry.projects.find((project) => project.path === path);\n if (existing) return { registry, entry: existing, created: false };\n\n const taken = new Set(registry.projects.map((project) => project.slug));\n const slug = uniqueSlug(slugify(basename(path)), taken);\n const entry: MachineProject = { slug, path, name: name ?? basename(path) };\n return {\n registry: { ...registry, projects: [...registry.projects, entry] },\n entry,\n created: true,\n };\n}\n\nexport interface RemoveProjectResult {\n registry: MachineRegistry;\n removed: boolean;\n}\n\nexport function removeProject(registry: MachineRegistry, slug: string): RemoveProjectResult {\n if (!registry.projects.some((project) => project.slug === slug)) {\n return { registry, removed: false };\n }\n return {\n registry: { ...registry, projects: registry.projects.filter((p) => p.slug !== slug) },\n removed: true,\n };\n}\n\nexport function listProjects(registry: MachineRegistry): MachineProject[] {\n return [...registry.projects].sort((a, b) => a.slug.localeCompare(b.slug));\n}\n\nexport interface SetNightProjectResult {\n registry: MachineRegistry;\n ok: boolean;\n}\n\n/** Fails for a slug not in `projects` — the night shift only ever runs a registered project. */\nexport function setNightProject(registry: MachineRegistry, slug: string): SetNightProjectResult {\n if (!registry.projects.some((project) => project.slug === slug)) {\n return { registry, ok: false };\n }\n return { registry: { ...registry, night: { slug } }, ok: true };\n}\n\nexport function clearNightProject(registry: MachineRegistry): MachineRegistry {\n if (!registry.night) return registry;\n const { night: _night, ...rest } = registry;\n return rest;\n}\n\nexport function setNightPause(\n registry: MachineRegistry,\n pausedUntil: number | null,\n): MachineRegistry {\n if (!registry.night) return registry;\n if (pausedUntil === null) {\n const { pausedUntil: _pausedUntil, ...rest } = registry.night;\n return { ...registry, night: rest };\n }\n return { ...registry, night: { ...registry.night, pausedUntil } };\n}\n\n/** A registered path is missing once its `papercamp/config.json` is gone — the\n * mounter, the machine-projects endpoint, and `ls`/`status` all key off this. */\nexport async function isProjectMissing(path: string): Promise<boolean> {\n try {\n await access(join(path, 'papercamp', 'config.json'));\n return false;\n } catch {\n return true;\n }\n}\n\nexport interface ScanEntry {\n path: string;\n name: string;\n hasConfig: boolean;\n}\n\nasync function inspectProject(\n configPath: string,\n fallbackName: string,\n): Promise<{ hasConfig: boolean; name: string }> {\n let raw: string;\n try {\n raw = await readFile(configPath, 'utf-8');\n } catch {\n return { hasConfig: false, name: fallbackName };\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n const projectName = (parsed as { projectName?: unknown })?.projectName;\n return {\n hasConfig: true,\n name: typeof projectName === 'string' && projectName ? projectName : fallbackName,\n };\n } catch {\n return { hasConfig: true, name: fallbackName };\n }\n}\n\n/** One level deep only — a project's own subdirectories are its concern, not the scan root's. */\nexport async function scanForProjects(dir: string): Promise<ScanEntry[]> {\n const root = resolve(dir);\n const dirents = await readdir(root, { withFileTypes: true });\n const entries: ScanEntry[] = [];\n for (const dirent of dirents) {\n if (!dirent.isDirectory()) continue;\n const projectPath = join(root, dirent.name);\n const configPath = join(projectPath, 'papercamp', 'config.json');\n const { hasConfig, name } = await inspectProject(configPath, dirent.name);\n entries.push({ path: projectPath, name, hasConfig });\n }\n return entries.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { randomBytes } from 'node:crypto';\nimport { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport {\n MACHINE_NIGHT_PATH,\n MACHINE_PROJECTS_PATH,\n type MachineNightGateResponse,\n type MachineProjectSummary,\n} from '../../types/index';\nimport { machineConfigDir } from '../machine-registry';\nimport { formatDuration } from '../phase-run';\n\nexport interface DaemonLinks {\n host: string;\n network?: string;\n tailnet?: string;\n tunnel?: string;\n}\n\nexport function qrEligibleLink(links: DaemonLinks): string | undefined {\n return links.tailnet ?? links.tunnel;\n}\n\nexport type UpdateEvent =\n | { kind: 'hooked'; version: string; at: string }\n | { kind: 'boot check current' }\n | { kind: 'failed'; version: string; output: string };\n\nexport interface DaemonState {\n pid: number;\n port: number;\n version: string;\n startedAt: string;\n share: boolean;\n tailnet: boolean;\n updateEvent?: UpdateEvent;\n updatePendingVersion?: string | null;\n links?: DaemonLinks;\n}\n\nexport function daemonStatePath(): string {\n return join(machineConfigDir(), 'daemon.json');\n}\n\nexport function daemonLogPath(): string {\n return join(machineConfigDir(), 'daemon.log');\n}\n\nfunction isOptionalString(value: unknown): value is string | undefined {\n return value === undefined || typeof value === 'string';\n}\n\nfunction isDaemonLinks(value: unknown): value is DaemonLinks {\n const v = value as Partial<DaemonLinks> | null;\n return (\n typeof v === 'object' &&\n v !== null &&\n typeof v.host === 'string' &&\n isOptionalString(v.network) &&\n isOptionalString(v.tailnet) &&\n isOptionalString(v.tunnel)\n );\n}\n\nfunction isUpdateEvent(value: unknown): value is UpdateEvent {\n const v = value as { kind?: unknown; version?: unknown; at?: unknown; output?: unknown } | null;\n if (typeof v !== 'object' || v === null) return false;\n switch (v.kind) {\n case 'hooked':\n return typeof v.version === 'string' && typeof v.at === 'string';\n case 'boot check current':\n return true;\n case 'failed':\n return typeof v.version === 'string' && typeof v.output === 'string';\n default:\n return false;\n }\n}\n\nfunction isDaemonState(value: unknown): value is DaemonState {\n const v = value as Partial<DaemonState> | null;\n return (\n typeof v === 'object' &&\n v !== null &&\n typeof v.pid === 'number' &&\n typeof v.port === 'number' &&\n typeof v.version === 'string' &&\n typeof v.startedAt === 'string' &&\n typeof v.share === 'boolean' &&\n typeof v.tailnet === 'boolean' &&\n (v.updateEvent === undefined || isUpdateEvent(v.updateEvent)) &&\n (v.updatePendingVersion === undefined ||\n v.updatePendingVersion === null ||\n typeof v.updatePendingVersion === 'string') &&\n (v.links === undefined || isDaemonLinks(v.links))\n );\n}\n\n/** Resolves `undefined` on a missing or malformed file — same first-boot and\n * stale-file shape every other config-dir reader resolves to. */\nasync function loadDaemonState(path: string): Promise<DaemonState | undefined> {\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n return undefined;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isDaemonState(parsed) ? parsed : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nconst PROBE_TIMEOUT_MS = 2_000;\n\nexport async function fetchMachineProjects(port: number): Promise<MachineProjectSummary[] | null> {\n try {\n const response = await fetch(`http://localhost:${port}${MACHINE_PROJECTS_PATH}`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (!response.ok) return null;\n const body = (await response.json()) as { projects: MachineProjectSummary[] };\n return body.projects;\n } catch {\n return null;\n }\n}\n\n/** A response at all is proof the port is a live daemon, not just a live pid\n * (pids get reused, ports get taken by something else). */\nexport async function probeMachineEndpoint(port: number): Promise<boolean> {\n return (await fetchMachineProjects(port)) !== null;\n}\n\nexport async function fetchMachineNightGate(\n port: number,\n): Promise<MachineNightGateResponse | null> {\n try {\n const response = await fetch(`http://localhost:${port}${MACHINE_NIGHT_PATH}`, {\n signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),\n });\n if (!response.ok) return null;\n return (await response.json()) as MachineNightGateResponse;\n } catch {\n return null;\n }\n}\n\n/** The one truth every lifecycle command reads: a state file, a live pid, and\n * a daemon answering on its port. Anything less is stale, so this prunes the\n * file before reporting not-running. */\nexport async function readRunningDaemonState(path: string): Promise<DaemonState | null> {\n const state = await loadDaemonState(path);\n const alive =\n state !== undefined && isProcessAlive(state.pid) && (await probeMachineEndpoint(state.port));\n if (!alive) {\n await removeDaemonState(path);\n return null;\n }\n return state;\n}\n\nexport function formatDaemonStatusLine(state: DaemonState): string {\n const uptime = formatDuration(Date.now() - Date.parse(state.startedAt));\n const flags = [state.share && 'share', state.tailnet && 'tailnet'].filter(Boolean).join(', ');\n return (\n `paper-camp: daemon running — pid ${state.pid}, port ${state.port}, ` +\n `v${state.version}, up ${uptime}${flags ? `, ${flags}` : ''}`\n );\n}\n\nfunction formatClockTime(iso: string): string {\n const date = new Date(iso);\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${pad(date.getHours())}:${pad(date.getMinutes())}`;\n}\n\nexport function formatUpdateStatusLine(state: DaemonState): string {\n if (state.updatePendingVersion) {\n return `paper-camp: update to ${state.updatePendingVersion} pending, waiting for idle`;\n }\n const event = state.updateEvent;\n if (!event) return 'paper-camp: no update check yet';\n switch (event.kind) {\n case 'hooked':\n return `paper-camp: hooked ${event.version} at ${formatClockTime(event.at)}`;\n case 'boot check current':\n return 'paper-camp: boot check current';\n case 'failed':\n return `paper-camp: ${event.version} installed but did not take effect — run \\`paper-camp update\\``;\n }\n}\n\n/** Unlike the daemon banner, which prints only the single best way in, status\n * lists every link this machine has on offer. */\nexport function formatDaemonLinks(links: DaemonLinks): string {\n const rows: [string, string | undefined][] = [\n ['This host', links.host],\n ['Network', links.network],\n ['Tailnet', links.tailnet],\n ['Tunnel', links.tunnel],\n ];\n const present = rows.filter((row): row is [string, string] => row[1] !== undefined);\n const width = Math.max(...present.map(([label]) => label.length));\n return present.map(([label, url]) => `${label.padEnd(width)} ${url}`).join('\\n');\n}\n\n/** Written to a sibling temp path and renamed into place, so a crash mid-write\n * never leaves a stale-file reader a truncated file to trip over. */\nexport async function writeDaemonState(path: string, state: DaemonState): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const tmpPath = `${path}.${randomBytes(6).toString('hex')}.tmp`;\n await writeFile(tmpPath, `${JSON.stringify(state, null, 2)}\\n`, 'utf-8');\n await rename(tmpPath, path);\n}\n\nexport async function removeDaemonState(path: string): Promise<void> {\n await rm(path, { force: true });\n}\n"],"names":["trimDecimal","value","places","formatDuration","ms","totalSeconds","hours","minutes","seconds","parseDuration","text","match","formatTokens","n","parseTokens","shortModel","model","formatRunLine","run","parts","parseRunLine","segments","s","durationMs","segment","inMatch","outMatch","attemptMatch","sessionMatch","mergeRun","prev","usage","sessionId","EMPTY_REGISTRY","machineConfigDir","join","homedir","defaultRegistryPath","isMachineProject","v","isNightSelection","isMachineRegistry","loadRegistry","path","raw","readFile","error","parsed","saveRegistry","registry","mkdir","dirname","tmpPath","randomBytes","writeFile","rename","slugify","input","uniqueSlug","base","taken","suffix","addProject","projectPath","name","resolve","existing","project","entry","basename","removeProject","slug","p","listProjects","a","b","setNightProject","clearNightProject","_night","rest","setNightPause","pausedUntil","_pausedUntil","isProjectMissing","access","inspectProject","configPath","fallbackName","projectName","scanForProjects","dir","root","dirents","readdir","entries","dirent","hasConfig","qrEligibleLink","links","daemonStatePath","daemonLogPath","isOptionalString","isDaemonLinks","isUpdateEvent","isDaemonState","loadDaemonState","isProcessAlive","pid","PROBE_TIMEOUT_MS","fetchMachineProjects","port","response","MACHINE_PROJECTS_PATH","probeMachineEndpoint","fetchMachineNightGate","MACHINE_NIGHT_PATH","readRunningDaemonState","state","removeDaemonState","formatDaemonStatusLine","uptime","flags","formatClockTime","iso","date","pad","formatUpdateStatusLine","event","formatDaemonLinks","present","row","width","label","url","writeDaemonState","rm"],"mappings":"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"}