@dendelion/paper-camp 0.44.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/chunks/{daemon-state.Evil_jr0.js → daemon-state.BEsOWFz5.js} +79 -75
  2. package/dist/chunks/daemon-state.BEsOWFz5.js.map +1 -0
  3. package/dist/chunks/{dev-port.BLsETEnM.js → dev-port.CKE4LWyl.js} +2 -2
  4. package/dist/chunks/{dev-port.BLsETEnM.js.map → dev-port.CKE4LWyl.js.map} +1 -1
  5. package/dist/chunks/phase-progress.BCqVUFLp.js +4094 -0
  6. package/dist/chunks/phase-progress.BCqVUFLp.js.map +1 -0
  7. package/dist/cli/index.js +7353 -6320
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/core/assets.d.ts +11 -0
  10. package/dist/core/assets.d.ts.map +1 -0
  11. package/dist/core/batch-readiness.d.ts +43 -0
  12. package/dist/core/batch-readiness.d.ts.map +1 -0
  13. package/dist/core/batch-readiness.test.d.ts +2 -0
  14. package/dist/core/batch-readiness.test.d.ts.map +1 -0
  15. package/dist/core/batch-run.d.ts +106 -0
  16. package/dist/core/batch-run.d.ts.map +1 -0
  17. package/dist/core/batch-run.test.d.ts +2 -0
  18. package/dist/core/batch-run.test.d.ts.map +1 -0
  19. package/dist/core/capacity.d.ts +6 -2
  20. package/dist/core/capacity.d.ts.map +1 -1
  21. package/dist/core/corpus.d.ts +13 -1
  22. package/dist/core/corpus.d.ts.map +1 -1
  23. package/dist/core/doctor/checks/assets.d.ts +3 -0
  24. package/dist/core/doctor/checks/assets.d.ts.map +1 -0
  25. package/dist/core/doctor/checks/assets.test.d.ts +2 -0
  26. package/dist/core/doctor/checks/assets.test.d.ts.map +1 -0
  27. package/dist/core/doctor/checks/local-state.d.ts +3 -0
  28. package/dist/core/doctor/checks/local-state.d.ts.map +1 -0
  29. package/dist/core/doctor/checks/local-state.test.d.ts +2 -0
  30. package/dist/core/doctor/checks/local-state.test.d.ts.map +1 -0
  31. package/dist/core/doctor/doctor.d.ts +12 -0
  32. package/dist/core/doctor/doctor.d.ts.map +1 -1
  33. package/dist/core/doctor/rules.d.ts +31 -1
  34. package/dist/core/doctor/rules.d.ts.map +1 -1
  35. package/dist/core/entity-view.d.ts.map +1 -1
  36. package/dist/core/git-log.d.ts +4 -0
  37. package/dist/core/git-log.d.ts.map +1 -1
  38. package/dist/core/git-pr/pr-lookup.d.ts.map +1 -1
  39. package/dist/core/index.js +154 -149
  40. package/dist/core/local-paths.d.ts +17 -0
  41. package/dist/core/local-paths.d.ts.map +1 -0
  42. package/dist/core/machine-registry/machine-registry.d.ts +3 -0
  43. package/dist/core/machine-registry/machine-registry.d.ts.map +1 -1
  44. package/dist/core/night-health.d.ts.map +1 -1
  45. package/dist/core/parse/schemas.d.ts +4 -0
  46. package/dist/core/parse/schemas.d.ts.map +1 -1
  47. package/dist/core/project-config.d.ts +2 -0
  48. package/dist/core/project-config.d.ts.map +1 -1
  49. package/dist/core/readers.d.ts.map +1 -1
  50. package/dist/core/release-notes.d.ts +7 -1
  51. package/dist/core/release-notes.d.ts.map +1 -1
  52. package/dist/core/scaffold/scaffold.d.ts +1 -0
  53. package/dist/core/scaffold/scaffold.d.ts.map +1 -1
  54. package/dist/core/stats.d.ts +3 -0
  55. package/dist/core/stats.d.ts.map +1 -1
  56. package/dist/core/trail.d.ts +6 -0
  57. package/dist/core/trail.d.ts.map +1 -1
  58. package/dist/toolbar/toolbar.js +3341 -3257
  59. package/dist/toolbar/toolbar.js.map +1 -1
  60. package/dist/types/index.d.ts +51 -5
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/dist/types/index.js +24 -19
  63. package/dist/types/index.js.map +1 -1
  64. package/dist/vite/index.js +1 -1
  65. package/package.json +2 -1
  66. package/dist/chunks/daemon-state.Evil_jr0.js.map +0 -1
  67. package/dist/chunks/needs.BmY0GqQY.js +0 -3630
  68. package/dist/chunks/needs.BmY0GqQY.js.map +0 -1
@@ -28,7 +28,7 @@ function g(t) {
28
28
  function E(t) {
29
29
  return t.replace(/^(?:[\w.]+\.)?anthropic\./, "").replace(/^claude-/, "").replace(/-\d{6,8}$/, "");
30
30
  }
31
- function tt(t) {
31
+ function nt(t) {
32
32
  const n = [
33
33
  M(t.durationMs),
34
34
  `${h(t.inputTokens)} in`,
@@ -36,7 +36,7 @@ function tt(t) {
36
36
  ];
37
37
  return t.model && n.push(t.model), t.attempts > 1 && n.push(`×${t.attempts}`), t.sessionId && n.push(`sess:${t.sessionId}`), n.join(" · ");
38
38
  }
39
- function nt(t) {
39
+ function et(t) {
40
40
  const n = t.split("·").map((r) => r.trim()).filter(Boolean);
41
41
  if (n.length === 0) return;
42
42
  const e = A(n[0]);
@@ -53,7 +53,7 @@ function nt(t) {
53
53
  }
54
54
  return o;
55
55
  }
56
- function et(t, n, e) {
56
+ function ot(t, n, e) {
57
57
  return {
58
58
  durationMs: ((t == null ? void 0 : t.durationMs) ?? 0) + n.durationMs,
59
59
  inputTokens: ((t == null ? void 0 : t.inputTokens) ?? 0) + n.inputTokens,
@@ -67,22 +67,25 @@ const f = { version: 1, projects: [] };
67
67
  function l() {
68
68
  return process.env.PAPERCAMP_CONFIG_DIR ?? c(R(), ".config", "paper-camp");
69
69
  }
70
- function ot() {
71
- return c(l(), "projects.json");
72
- }
73
70
  function C(t) {
71
+ return c(l(), t);
72
+ }
73
+ function rt() {
74
+ return C("projects.json");
75
+ }
76
+ function I(t) {
74
77
  const n = t;
75
78
  return typeof n == "object" && n !== null && typeof n.slug == "string" && typeof n.path == "string" && typeof n.name == "string";
76
79
  }
77
- function I(t) {
80
+ function _(t) {
78
81
  const n = t;
79
82
  return typeof n == "object" && n !== null && typeof n.slug == "string" && (n.pausedUntil === void 0 || typeof n.pausedUntil == "number");
80
83
  }
81
- function _(t) {
84
+ function O(t) {
82
85
  const n = t;
83
- return typeof n == "object" && n !== null && n.version === 1 && Array.isArray(n.projects) && n.projects.every(C) && (n.night === void 0 || I(n.night));
86
+ return typeof n == "object" && n !== null && n.version === 1 && Array.isArray(n.projects) && n.projects.every(I) && (n.night === void 0 || _(n.night));
84
87
  }
85
- async function rt(t) {
88
+ async function st(t) {
86
89
  let n;
87
90
  try {
88
91
  n = await p(t, "utf-8");
@@ -91,18 +94,18 @@ async function rt(t) {
91
94
  }
92
95
  try {
93
96
  const e = JSON.parse(n);
94
- return _(e) ? e : f;
97
+ return O(e) ? e : f;
95
98
  } catch {
96
99
  return f;
97
100
  }
98
101
  }
99
- async function st(t, n) {
102
+ async function at(t, n) {
100
103
  await $(P(t), { recursive: !0 });
101
104
  const e = `${t}.${y(6).toString("hex")}.tmp`;
102
105
  await j(e, `${JSON.stringify(n, null, 2)}
103
106
  `, "utf-8"), await w(e, t);
104
107
  }
105
- function O(t) {
108
+ function F(t) {
106
109
  return t.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "project";
107
110
  }
108
111
  function x(t, n) {
@@ -111,34 +114,34 @@ function x(t, n) {
111
114
  for (; n.has(`${t}-${e}`); ) e++;
112
115
  return `${t}-${e}`;
113
116
  }
114
- function at(t, n, e) {
117
+ function it(t, n, e) {
115
118
  const o = k(n), r = t.projects.find((a) => a.path === o);
116
119
  if (r) return { registry: t, entry: r, created: !1 };
117
- const s = new Set(t.projects.map((a) => a.slug)), i = { slug: x(O(d(o)), s), path: o, name: e ?? d(o) };
120
+ const s = new Set(t.projects.map((a) => a.slug)), i = { slug: x(F(d(o)), s), path: o, name: e ?? d(o) };
118
121
  return {
119
122
  registry: { ...t, projects: [...t.projects, i] },
120
123
  entry: i,
121
124
  created: !0
122
125
  };
123
126
  }
124
- function it(t, n) {
127
+ function ct(t, n) {
125
128
  return t.projects.some((e) => e.slug === n) ? {
126
129
  registry: { ...t, projects: t.projects.filter((e) => e.slug !== n) },
127
130
  removed: !0
128
131
  } : { registry: t, removed: !1 };
129
132
  }
130
- function ct(t) {
133
+ function ut(t) {
131
134
  return [...t.projects].sort((n, e) => n.slug.localeCompare(e.slug));
132
135
  }
133
- function ut(t, n) {
136
+ function ft(t, n) {
134
137
  return t.projects.some((e) => e.slug === n) ? { registry: { ...t, night: { slug: n } }, ok: !0 } : { registry: t, ok: !1 };
135
138
  }
136
- function ft(t) {
139
+ function pt(t) {
137
140
  if (!t.night) return t;
138
141
  const { night: n, ...e } = t;
139
142
  return e;
140
143
  }
141
- function pt(t, n) {
144
+ function lt(t, n) {
142
145
  if (!t.night) return t;
143
146
  if (n === null) {
144
147
  const { pausedUntil: e, ...o } = t.night;
@@ -146,14 +149,14 @@ function pt(t, n) {
146
149
  }
147
150
  return { ...t, night: { ...t.night, pausedUntil: n } };
148
151
  }
149
- async function lt(t) {
152
+ async function dt(t) {
150
153
  try {
151
154
  return await N(c(t, "papercamp", "config.json")), !1;
152
155
  } catch {
153
156
  return !0;
154
157
  }
155
158
  }
156
- async function F(t, n) {
159
+ async function H(t, n) {
157
160
  let e;
158
161
  try {
159
162
  e = await p(t, "utf-8");
@@ -170,25 +173,25 @@ async function F(t, n) {
170
173
  return { hasConfig: !0, name: n };
171
174
  }
172
175
  }
173
- async function dt(t) {
176
+ async function mt(t) {
174
177
  const n = k(t), e = await S(n, { withFileTypes: !0 }), o = [];
175
178
  for (const r of e) {
176
179
  if (!r.isDirectory()) continue;
177
- const s = c(n, r.name), u = c(s, "papercamp", "config.json"), { hasConfig: i, name: a } = await F(u, r.name);
180
+ const s = c(n, r.name), u = c(s, "papercamp", "config.json"), { hasConfig: i, name: a } = await H(u, r.name);
178
181
  o.push({ path: s, name: a, hasConfig: i });
179
182
  }
180
183
  return o.sort((r, s) => r.name.localeCompare(s.name));
181
184
  }
182
- function mt() {
185
+ function ht() {
183
186
  return c(l(), "daemon.json");
184
187
  }
185
- function ht() {
188
+ function gt() {
186
189
  return c(l(), "daemon.log");
187
190
  }
188
- function H(t) {
191
+ function L(t) {
189
192
  return t === void 0 || typeof t == "string";
190
193
  }
191
- function L(t) {
194
+ function J(t) {
192
195
  const n = t;
193
196
  if (typeof n != "object" || n === null) return !1;
194
197
  switch (n.kind) {
@@ -202,11 +205,11 @@ function L(t) {
202
205
  return !1;
203
206
  }
204
207
  }
205
- function J(t) {
208
+ function U(t) {
206
209
  const n = t;
207
- 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 || L(n.updateEvent)) && (n.updatePendingVersion === void 0 || n.updatePendingVersion === null || typeof n.updatePendingVersion == "string") && H(n.tailnetName);
210
+ 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") && L(n.tailnetName);
208
211
  }
209
- async function U(t) {
212
+ async function B(t) {
210
213
  let n;
211
214
  try {
212
215
  n = await p(t, "utf-8");
@@ -215,7 +218,7 @@ async function U(t) {
215
218
  }
216
219
  try {
217
220
  const e = JSON.parse(n);
218
- return J(e) ? e : void 0;
221
+ return U(e) ? e : void 0;
219
222
  } catch {
220
223
  return;
221
224
  }
@@ -228,7 +231,7 @@ function V(t) {
228
231
  }
229
232
  }
230
233
  const T = 2e3;
231
- async function B(t) {
234
+ async function G(t) {
232
235
  try {
233
236
  const n = await fetch(`http://localhost:${t}${v}`, {
234
237
  signal: AbortSignal.timeout(T)
@@ -238,10 +241,10 @@ async function B(t) {
238
241
  return null;
239
242
  }
240
243
  }
241
- async function G(t) {
242
- return await B(t) !== null;
244
+ async function q(t) {
245
+ return await G(t) !== null;
243
246
  }
244
- async function gt(t) {
247
+ async function yt(t) {
245
248
  try {
246
249
  const n = await fetch(`http://localhost:${t}${D}`, {
247
250
  signal: AbortSignal.timeout(T)
@@ -251,75 +254,76 @@ async function gt(t) {
251
254
  return null;
252
255
  }
253
256
  }
254
- async function yt(t) {
255
- const n = await U(t);
256
- return n !== void 0 && V(n.pid) && await G(n.port) ? n : (await Y(t), null);
257
+ async function $t(t) {
258
+ const n = await B(t);
259
+ return n !== void 0 && V(n.pid) && await q(n.port) ? n : (await K(t), null);
257
260
  }
258
- function $t(t) {
261
+ function jt(t) {
259
262
  const n = M(Date.now() - Date.parse(t.startedAt)), e = [t.share && "share", t.tailnet && "tailnet"].filter(Boolean).join(", ");
260
263
  return `paper-camp: daemon running — pid ${t.pid}, port ${t.port}, v${t.version}, up ${n}${e ? `, ${e}` : ""}`;
261
264
  }
262
- function q(t) {
265
+ function z(t) {
263
266
  const n = new Date(t), e = (o) => String(o).padStart(2, "0");
264
267
  return `${e(n.getHours())}:${e(n.getMinutes())}`;
265
268
  }
266
- function jt(t) {
269
+ function wt(t) {
267
270
  if (t.updatePendingVersion)
268
271
  return `paper-camp: update to ${t.updatePendingVersion} pending, waiting for idle`;
269
272
  const n = t.updateEvent;
270
273
  if (!n) return "paper-camp: no update check yet";
271
274
  switch (n.kind) {
272
275
  case "hooked":
273
- return `paper-camp: hooked ${n.version} at ${q(n.at)}`;
276
+ return `paper-camp: hooked ${n.version} at ${z(n.at)}`;
274
277
  case "boot check current":
275
278
  return "paper-camp: boot check current";
276
279
  case "failed":
277
280
  return `paper-camp: ${n.version} installed but did not take effect — run \`paper-camp update\``;
278
281
  }
279
282
  }
280
- const z = "Run `paper-camp pair` to connect a device.";
281
- function wt(t) {
283
+ const Y = "Run `paper-camp pair` to connect a device.";
284
+ function Pt(t) {
282
285
  const n = t ? [`Tailnet ${t}`] : [];
283
- return n.push(z), n.join(`
286
+ return n.push(Y), n.join(`
284
287
  `);
285
288
  }
286
- async function Pt(t, n) {
289
+ async function kt(t, n) {
287
290
  await $(P(t), { recursive: !0 });
288
291
  const e = `${t}.${y(6).toString("hex")}.tmp`;
289
292
  await j(e, `${JSON.stringify(n, null, 2)}
290
293
  `, "utf-8"), await w(e, t);
291
294
  }
292
- async function Y(t) {
295
+ async function K(t) {
293
296
  await b(t, { force: !0 });
294
297
  }
295
298
  export {
296
- et as A,
297
- z as P,
298
- at as a,
299
- mt as b,
300
- ft as c,
301
- ht as d,
302
- ot as e,
303
- gt as f,
304
- B as g,
305
- $t as h,
306
- wt as i,
307
- jt as j,
299
+ nt as A,
300
+ ot as B,
301
+ Y as P,
302
+ it as a,
303
+ ht as b,
304
+ pt as c,
305
+ gt as d,
306
+ rt as e,
307
+ yt as f,
308
+ G as g,
309
+ jt as h,
310
+ Pt as i,
311
+ wt as j,
308
312
  V as k,
309
- lt as l,
310
- ct as m,
311
- rt as n,
313
+ dt as l,
314
+ ut as m,
315
+ st as n,
312
316
  l as o,
313
- G as p,
314
- Y as q,
315
- yt as r,
316
- it as s,
317
- st as t,
318
- dt as u,
319
- pt as v,
320
- ut as w,
321
- Pt as x,
322
- nt as y,
323
- tt as z
317
+ C as p,
318
+ q,
319
+ $t as r,
320
+ K as s,
321
+ ct as t,
322
+ at as u,
323
+ mt as v,
324
+ lt as w,
325
+ ft as x,
326
+ kt as y,
327
+ et as z
324
328
  };
325
- //# sourceMappingURL=daemon-state.Evil_jr0.js.map
329
+ //# sourceMappingURL=daemon-state.BEsOWFz5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-state.BEsOWFz5.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\n/** This machine and account's own state — `projects.json`, `pairing.json`,\n * `daemon.json`, `capacity.json` — none of it is a git repo. */\nexport function machineFile(name: string): string {\n return join(machineConfigDir(), name);\n}\n\nexport function defaultRegistryPath(): string {\n return machineFile('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 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 tailnetName?: string;\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 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 isOptionalString(v.tailnetName)\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\nexport const PAIR_HINT = 'Run `paper-camp pair` to connect a device.';\n\nexport function formatDaemonTailnetLine(tailnetName: string | undefined): string {\n const lines = tailnetName ? [`Tailnet ${tailnetName}`] : [];\n lines.push(PAIR_HINT);\n return lines.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","machineFile","name","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","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","daemonStatePath","daemonLogPath","isOptionalString","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","PAIR_HINT","formatDaemonTailnetLine","tailnetName","lines","writeDaemonState","rm"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { resolve as c, sep as l } from "node:path";
2
- import { n as d, e as f, r as g, b as m } from "./daemon-state.Evil_jr0.js";
2
+ import { n as d, e as f, r as g, b as m } from "./daemon-state.BEsOWFz5.js";
3
3
  import { readFile as h } from "node:fs/promises";
4
4
  function y(o, t) {
5
5
  return t === o || t.startsWith(o + l);
@@ -52,4 +52,4 @@ export {
52
52
  C as p,
53
53
  R as r
54
54
  };
55
- //# sourceMappingURL=dev-port.BLsETEnM.js.map
55
+ //# sourceMappingURL=dev-port.CKE4LWyl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev-port.BLsETEnM.js","sources":["../../src/core/daemon-target.ts","../../src/cli/dev-port.ts"],"sourcesContent":["import { resolve, sep } from 'node:path';\nimport { daemonStatePath, readRunningDaemonState } from './daemon-state';\nimport { defaultRegistryPath, loadRegistry } from './machine-registry';\n\nexport interface DaemonTarget {\n origin: string;\n slug: string;\n}\n\nfunction containsRoot(projectPath: string, root: string): boolean {\n return root === projectPath || root.startsWith(projectPath + sep);\n}\n\n/** A root the registry doesn't know, or no daemon actually answering on the\n * resolved port, both mean \"toolbar off\" — the caller can't tell them apart\n * and doesn't need to, `undefined` covers both. `portOverride` stands in for\n * a daemon started by hand, whose real port `daemon.json` may not reflect.\n * The Vite root of a monorepo app, e.g. `apps/admin`, sits inside its\n * registered project path rather than equalling it, so matching picks the\n * longest containing path in case projects are nested. */\nexport async function resolveDaemonTarget(\n root: string,\n portOverride?: number,\n): Promise<DaemonTarget | undefined> {\n const registry = await loadRegistry(defaultRegistryPath());\n const resolvedRoot = resolve(root);\n const project = registry.projects\n .filter((candidate) => containsRoot(candidate.path, resolvedRoot))\n .sort((a, b) => b.path.length - a.path.length)[0];\n if (!project) return undefined;\n\n const port = portOverride ?? (await readRunningDaemonState(daemonStatePath()))?.port;\n if (port === undefined) return undefined;\n\n return { origin: `http://localhost:${port}`, slug: project.slug };\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\nasync function readConfigJson(root: string): Promise<Record<string, unknown> | undefined> {\n const raw = await readFile(resolve(root, 'papercamp', 'config.json'), 'utf-8').catch(() => null);\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nexport async function readConfigPort(root: string): Promise<number | undefined> {\n const parsed = await readConfigJson(root);\n const port = parsed?.port;\n return typeof port === 'number' && Number.isFinite(port) ? port : undefined;\n}\n\nexport interface IntegrationDevConfig {\n enabled?: boolean;\n allowProduction?: boolean;\n}\n\nexport async function readConfigIntegration(\n root: string,\n): Promise<IntegrationDevConfig | undefined> {\n const parsed = await readConfigJson(root);\n const integration = parsed?.integration as\n | { toolbar?: { enabled?: unknown; allowProduction?: unknown } }\n | undefined;\n if (!integration) return undefined;\n const enabled = integration.toolbar?.enabled;\n const allowProduction = integration.toolbar?.allowProduction;\n return {\n enabled: typeof enabled === 'boolean' ? enabled : undefined,\n allowProduction: typeof allowProduction === 'boolean' ? allowProduction : undefined,\n };\n}\n\nexport function resolveDevPort(explicitPort: string | undefined, configPort: number | undefined) {\n return explicitPort ? Number(explicitPort) : (configPort ?? 3333);\n}\n\nexport function portInUseMessage(port: number, kind: 'dev' | 'daemon' = 'dev'): string {\n if (kind === 'daemon') {\n return `Port ${port} is already taken — a daemon may already be running; paper-camp status shows it, or pick another port with -p.`;\n }\n return [\n `Port ${port} is already taken — something else (maybe another paper-camp) is listening there.`,\n 'Pick a different port with -p, or set \"port\" in papercamp/config.json for this project.',\n ].join('\\n');\n}\n"],"names":["containsRoot","projectPath","root","sep","resolveDaemonTarget","portOverride","registry","loadRegistry","defaultRegistryPath","resolvedRoot","resolve","project","candidate","a","b","port","_a","readRunningDaemonState","daemonStatePath","readConfigJson","raw","readFile","readConfigPort","parsed","readConfigIntegration","integration","enabled","allowProduction","_b","resolveDevPort","explicitPort","configPort","portInUseMessage","kind"],"mappings":";;;AASA,SAASA,EAAaC,GAAqBC,GAAuB;AAChE,SAAOA,MAASD,KAAeC,EAAK,WAAWD,IAAcE,CAAG;AAClE;AASA,eAAsBC,EACpBF,GACAG,GACmC;;AACnC,QAAMC,IAAW,MAAMC,EAAaC,GAAqB,GACnDC,IAAeC,EAAQR,CAAI,GAC3BS,IAAUL,EAAS,SACtB,OAAO,CAACM,MAAcZ,EAAaY,EAAU,MAAMH,CAAY,CAAC,EAChE,KAAK,CAACI,GAAGC,MAAMA,EAAE,KAAK,SAASD,EAAE,KAAK,MAAM,EAAE,CAAC;AAClD,MAAI,CAACF,EAAS;AAEd,QAAMI,IAAOV,OAAiBW,IAAA,MAAMC,EAAuBC,EAAA,CAAiB,MAA9C,gBAAAF,EAAkD;AAChF,MAAID,MAAS;AAEb,WAAO,EAAE,QAAQ,oBAAoBA,CAAI,IAAI,MAAMJ,EAAQ,KAAA;AAC7D;AChCA,eAAeQ,EAAejB,GAA4D;AACxF,QAAMkB,IAAM,MAAMC,EAASX,EAAQR,GAAM,aAAa,aAAa,GAAG,OAAO,EAAE,MAAM,MAAM,IAAI;AAC/F,MAAKkB;AACL,QAAI;AACF,aAAO,KAAK,MAAMA,CAAG;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AACF;AAEA,eAAsBE,EAAepB,GAA2C;AAC9E,QAAMqB,IAAS,MAAMJ,EAAejB,CAAI,GAClCa,IAAOQ,KAAA,gBAAAA,EAAQ;AACrB,SAAO,OAAOR,KAAS,YAAY,OAAO,SAASA,CAAI,IAAIA,IAAO;AACpE;AAOA,eAAsBS,EACpBtB,GAC2C;;AAC3C,QAAMqB,IAAS,MAAMJ,EAAejB,CAAI,GAClCuB,IAAcF,KAAA,gBAAAA,EAAQ;AAG5B,MAAI,CAACE,EAAa;AAClB,QAAMC,KAAUV,IAAAS,EAAY,YAAZ,gBAAAT,EAAqB,SAC/BW,KAAkBC,IAAAH,EAAY,YAAZ,gBAAAG,EAAqB;AAC7C,SAAO;AAAA,IACL,SAAS,OAAOF,KAAY,YAAYA,IAAU;AAAA,IAClD,iBAAiB,OAAOC,KAAoB,YAAYA,IAAkB;AAAA,EAAA;AAE9E;AAEO,SAASE,EAAeC,GAAkCC,GAAgC;AAC/F,SAAOD,IAAe,OAAOA,CAAY,IAAKC,KAAc;AAC9D;AAEO,SAASC,EAAiBjB,GAAckB,IAAyB,OAAe;AACrF,SAAIA,MAAS,WACJ,QAAQlB,CAAI,mHAEd;AAAA,IACL,QAAQA,CAAI;AAAA,IACZ;AAAA,EAAA,EACA,KAAK;AAAA,CAAI;AACb;"}
1
+ {"version":3,"file":"dev-port.CKE4LWyl.js","sources":["../../src/core/daemon-target.ts","../../src/cli/dev-port.ts"],"sourcesContent":["import { resolve, sep } from 'node:path';\nimport { daemonStatePath, readRunningDaemonState } from './daemon-state';\nimport { defaultRegistryPath, loadRegistry } from './machine-registry';\n\nexport interface DaemonTarget {\n origin: string;\n slug: string;\n}\n\nfunction containsRoot(projectPath: string, root: string): boolean {\n return root === projectPath || root.startsWith(projectPath + sep);\n}\n\n/** A root the registry doesn't know, or no daemon actually answering on the\n * resolved port, both mean \"toolbar off\" — the caller can't tell them apart\n * and doesn't need to, `undefined` covers both. `portOverride` stands in for\n * a daemon started by hand, whose real port `daemon.json` may not reflect.\n * The Vite root of a monorepo app, e.g. `apps/admin`, sits inside its\n * registered project path rather than equalling it, so matching picks the\n * longest containing path in case projects are nested. */\nexport async function resolveDaemonTarget(\n root: string,\n portOverride?: number,\n): Promise<DaemonTarget | undefined> {\n const registry = await loadRegistry(defaultRegistryPath());\n const resolvedRoot = resolve(root);\n const project = registry.projects\n .filter((candidate) => containsRoot(candidate.path, resolvedRoot))\n .sort((a, b) => b.path.length - a.path.length)[0];\n if (!project) return undefined;\n\n const port = portOverride ?? (await readRunningDaemonState(daemonStatePath()))?.port;\n if (port === undefined) return undefined;\n\n return { origin: `http://localhost:${port}`, slug: project.slug };\n}\n","import { readFile } from 'node:fs/promises';\nimport { resolve } from 'node:path';\n\nasync function readConfigJson(root: string): Promise<Record<string, unknown> | undefined> {\n const raw = await readFile(resolve(root, 'papercamp', 'config.json'), 'utf-8').catch(() => null);\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nexport async function readConfigPort(root: string): Promise<number | undefined> {\n const parsed = await readConfigJson(root);\n const port = parsed?.port;\n return typeof port === 'number' && Number.isFinite(port) ? port : undefined;\n}\n\nexport interface IntegrationDevConfig {\n enabled?: boolean;\n allowProduction?: boolean;\n}\n\nexport async function readConfigIntegration(\n root: string,\n): Promise<IntegrationDevConfig | undefined> {\n const parsed = await readConfigJson(root);\n const integration = parsed?.integration as\n | { toolbar?: { enabled?: unknown; allowProduction?: unknown } }\n | undefined;\n if (!integration) return undefined;\n const enabled = integration.toolbar?.enabled;\n const allowProduction = integration.toolbar?.allowProduction;\n return {\n enabled: typeof enabled === 'boolean' ? enabled : undefined,\n allowProduction: typeof allowProduction === 'boolean' ? allowProduction : undefined,\n };\n}\n\nexport function resolveDevPort(explicitPort: string | undefined, configPort: number | undefined) {\n return explicitPort ? Number(explicitPort) : (configPort ?? 3333);\n}\n\nexport function portInUseMessage(port: number, kind: 'dev' | 'daemon' = 'dev'): string {\n if (kind === 'daemon') {\n return `Port ${port} is already taken — a daemon may already be running; paper-camp status shows it, or pick another port with -p.`;\n }\n return [\n `Port ${port} is already taken — something else (maybe another paper-camp) is listening there.`,\n 'Pick a different port with -p, or set \"port\" in papercamp/config.json for this project.',\n ].join('\\n');\n}\n"],"names":["containsRoot","projectPath","root","sep","resolveDaemonTarget","portOverride","registry","loadRegistry","defaultRegistryPath","resolvedRoot","resolve","project","candidate","a","b","port","_a","readRunningDaemonState","daemonStatePath","readConfigJson","raw","readFile","readConfigPort","parsed","readConfigIntegration","integration","enabled","allowProduction","_b","resolveDevPort","explicitPort","configPort","portInUseMessage","kind"],"mappings":";;;AASA,SAASA,EAAaC,GAAqBC,GAAuB;AAChE,SAAOA,MAASD,KAAeC,EAAK,WAAWD,IAAcE,CAAG;AAClE;AASA,eAAsBC,EACpBF,GACAG,GACmC;;AACnC,QAAMC,IAAW,MAAMC,EAAaC,GAAqB,GACnDC,IAAeC,EAAQR,CAAI,GAC3BS,IAAUL,EAAS,SACtB,OAAO,CAACM,MAAcZ,EAAaY,EAAU,MAAMH,CAAY,CAAC,EAChE,KAAK,CAACI,GAAGC,MAAMA,EAAE,KAAK,SAASD,EAAE,KAAK,MAAM,EAAE,CAAC;AAClD,MAAI,CAACF,EAAS;AAEd,QAAMI,IAAOV,OAAiBW,IAAA,MAAMC,EAAuBC,EAAA,CAAiB,MAA9C,gBAAAF,EAAkD;AAChF,MAAID,MAAS;AAEb,WAAO,EAAE,QAAQ,oBAAoBA,CAAI,IAAI,MAAMJ,EAAQ,KAAA;AAC7D;AChCA,eAAeQ,EAAejB,GAA4D;AACxF,QAAMkB,IAAM,MAAMC,EAASX,EAAQR,GAAM,aAAa,aAAa,GAAG,OAAO,EAAE,MAAM,MAAM,IAAI;AAC/F,MAAKkB;AACL,QAAI;AACF,aAAO,KAAK,MAAMA,CAAG;AAAA,IACvB,QAAQ;AACN;AAAA,IACF;AACF;AAEA,eAAsBE,EAAepB,GAA2C;AAC9E,QAAMqB,IAAS,MAAMJ,EAAejB,CAAI,GAClCa,IAAOQ,KAAA,gBAAAA,EAAQ;AACrB,SAAO,OAAOR,KAAS,YAAY,OAAO,SAASA,CAAI,IAAIA,IAAO;AACpE;AAOA,eAAsBS,EACpBtB,GAC2C;;AAC3C,QAAMqB,IAAS,MAAMJ,EAAejB,CAAI,GAClCuB,IAAcF,KAAA,gBAAAA,EAAQ;AAG5B,MAAI,CAACE,EAAa;AAClB,QAAMC,KAAUV,IAAAS,EAAY,YAAZ,gBAAAT,EAAqB,SAC/BW,KAAkBC,IAAAH,EAAY,YAAZ,gBAAAG,EAAqB;AAC7C,SAAO;AAAA,IACL,SAAS,OAAOF,KAAY,YAAYA,IAAU;AAAA,IAClD,iBAAiB,OAAOC,KAAoB,YAAYA,IAAkB;AAAA,EAAA;AAE9E;AAEO,SAASE,EAAeC,GAAkCC,GAAgC;AAC/F,SAAOD,IAAe,OAAOA,CAAY,IAAKC,KAAc;AAC9D;AAEO,SAASC,EAAiBjB,GAAckB,IAAyB,OAAe;AACrF,SAAIA,MAAS,WACJ,QAAQlB,CAAI,mHAEd;AAAA,IACL,QAAQA,CAAI;AAAA,IACZ;AAAA,EAAA,EACA,KAAK;AAAA,CAAI;AACb;"}