@kky42/pievo-server 4.1.0 → 4.2.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 (43) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{MarkdownView-BuFKr9Jg.js → MarkdownView-C9-AzIkl.js} +1 -1
  3. package/.output/public/assets/{actionUi-BZrLpgHT.js → actionUi-D47jwMfh.js} +1 -1
  4. package/.output/public/assets/app-C5xfpeJe.css +2 -0
  5. package/.output/public/assets/index-BgNjFXWE.js +10 -0
  6. package/.output/public/assets/loops._loopId-Bo63FXPQ.js +2 -0
  7. package/.output/public/assets/loops._loopId_.runs._runId-DW2HPjtj.js +3 -0
  8. package/.output/public/assets/{preload-helper-BSxGu4d0.js → preload-helper-CbYqBpY9.js} +2 -2
  9. package/.output/public/assets/routes-C88oSApK.js +1 -0
  10. package/.output/public/assets/routes-CTCh8xYm.js +1 -0
  11. package/.output/server/_ssr/{MachinesModal-CLBZxZkq.mjs → MachinesModal-DwHy2cis.mjs} +43 -24
  12. package/.output/server/_ssr/{MarkdownView-D1J7ImYF.mjs → MarkdownView-BOe75tli.mjs} +3 -6
  13. package/.output/server/_ssr/{actionUi-DE-Pb2tv.mjs → actionUi-CszQXDSN.mjs} +20 -2
  14. package/.output/server/_ssr/artifactFiles-DJiK99sF.mjs +67 -0
  15. package/.output/server/_ssr/{artifactKind-a2oxT2wQ.mjs → artifactKind-DYMU0q3N.mjs} +2 -7
  16. package/.output/server/_ssr/{boot-DmpKtb0A.mjs → boot-CecCDRoH.mjs} +218 -204
  17. package/.output/server/_ssr/{lifecycleUi-DEjM8Etm.mjs → lifecycleUi-Bd7_sthp.mjs} +8 -15
  18. package/.output/server/_ssr/{loopApi-DK1lQPrx.mjs → loopApi-uEiBQ5YX.mjs} +12 -18
  19. package/.output/server/_ssr/{loopProjection-DdFivf7-.mjs → loopProjection-Bo54jjGd.mjs} +3 -2
  20. package/.output/server/_ssr/{loops._loopId-DVCvGSEc.mjs → loops._loopId-c1oRP7cr.mjs} +15 -30
  21. package/.output/server/_ssr/{loops._loopId_.runs._runId-BXbTfLlC.mjs → loops._loopId_.runs._runId-Dl0SwOlC.mjs} +28 -19
  22. package/.output/server/_ssr/loops._loopId_.runs._runId-czMVvNsk.mjs +11 -0
  23. package/.output/server/_ssr/{machineFns-DLRHgDdS.mjs → machineFns-aw9xe5oz.mjs} +6 -20
  24. package/.output/server/_ssr/{router-BhHsTGqu.mjs → router-3OQ849sN.mjs} +22 -31
  25. package/.output/server/_ssr/{routes-CCallyCT.mjs → routes-CL4y6AEv.mjs} +2 -2
  26. package/.output/server/_ssr/{routes-CL2Kef-Q.mjs → routes-CT5IdoiP.mjs} +6 -6
  27. package/.output/server/_ssr/{routes-ngpX7h8D.mjs → routes-nU2PDK3W.mjs} +2 -2
  28. package/.output/server/_ssr/ssr.mjs +22 -22
  29. package/.output/server/{_tanstack-start-manifest_v-BPiJ4yWT.mjs → _tanstack-start-manifest_v-_nMS2ozp.mjs} +8 -8
  30. package/.output/server/drizzle/0002_run_attention.sql +1 -0
  31. package/.output/server/drizzle/meta/_journal.json +7 -0
  32. package/.output/server/index.mjs +49 -49
  33. package/drizzle/0002_run_attention.sql +1 -0
  34. package/drizzle/meta/_journal.json +7 -0
  35. package/package.json +1 -1
  36. package/.output/public/assets/app-x1CeeY7N.css +0 -2
  37. package/.output/public/assets/index-D0FIKiiW.js +0 -10
  38. package/.output/public/assets/loops._loopId-DTkIz4C0.js +0 -2
  39. package/.output/public/assets/loops._loopId_.runs._runId-CsV2Ih4Z.js +0 -3
  40. package/.output/public/assets/routes-BIOJZsig.js +0 -1
  41. package/.output/public/assets/routes-m4Z90DTR.js +0 -1
  42. package/.output/server/_ssr/artifactFiles-B0NPRDOR.mjs +0 -52
  43. package/.output/server/_ssr/loops._loopId_.runs._runId-Dr6E-FA5.mjs +0 -16
@@ -11,14 +11,14 @@ import { fileURLToPath } from "node:url";
11
11
  import path from "node:path";
12
12
  import os from "node:os";
13
13
  import fs$1 from "node:fs/promises";
14
- //#region node_modules/.nitro/vite/services/ssr/assets/loopTags-CnVLi70h.js
15
- var loopTags_CnVLi70h_exports = /* @__PURE__ */ __exportAll$1({
14
+ //#region node_modules/.nitro/vite/services/ssr/assets/loopTags-Bi7Bm7v8.js
15
+ var loopTags_Bi7Bm7v8_exports = /* @__PURE__ */ __exportAll$1({
16
16
  $: () => loopIdsWithSnapshots,
17
- $t: () => BLOB_GC_GRACE_MS,
17
+ $t: () => logger_exports,
18
18
  A: () => enqueueRun,
19
19
  At: () => updateMachine,
20
20
  B: () => getRun,
21
- Bt: () => loopFileNames,
21
+ Bt: () => loopFileIssue,
22
22
  C: () => buildLoopManifest,
23
23
  Ct: () => setMachineOnline,
24
24
  D: () => createLoop,
@@ -26,47 +26,47 @@ var loopTags_CnVLi70h_exports = /* @__PURE__ */ __exportAll$1({
26
26
  E: () => countRuns,
27
27
  Et: () => stopLoop,
28
28
  F: () => getArtifactFile,
29
- Ft: () => MEMORY_CHAR_CAP,
29
+ Ft: () => LoopFiles,
30
30
  G: () => initializeCronCadence,
31
- Gt: () => closeClient,
31
+ Gt: () => createBlobStore,
32
32
  H: () => getTerminalReportIncidents,
33
- Ht: () => sha256Buf,
33
+ Ht: () => loopFiles_exports,
34
34
  I: () => getExactTerminalReportIncident,
35
- It: () => MEMORY_FILE,
35
+ It: () => MEMORY_CHAR_CAP,
36
36
  J: () => listLoops,
37
- Jt: () => runs,
37
+ Jt: () => runMigrations,
38
38
  K: () => lastRun,
39
- Kt: () => db,
39
+ Kt: () => closeClient,
40
40
  L: () => getLoop,
41
- Lt: () => fileLimitLabel,
41
+ Lt: () => MEMORY_FILE,
42
42
  M: () => finalizeRunningRun,
43
- Mt: () => EMPTY_SHA256,
43
+ Mt: () => ARTIFACT_EXTENSIONS,
44
44
  N: () => forceDeleteLoop,
45
- Nt: () => LOOP_FILE_BYTE_CAP,
45
+ Nt: () => EMPTY_SHA256,
46
46
  O: () => createMachine,
47
47
  Ot: () => tryDeleteLoop,
48
48
  P: () => forceDeleteMachine,
49
- Pt: () => LoopFiles,
49
+ Pt: () => LOOP_FILE_BYTE_CAP,
50
50
  Q: () => liveBlobRefs,
51
- Qt: () => logger_exports,
51
+ Qt: () => logger,
52
52
  R: () => getMachine,
53
- Rt: () => isValidHash,
53
+ Rt: () => fileLimitLabel,
54
54
  S: () => blobSizes,
55
55
  St: () => runningRunsForMachine,
56
56
  T: () => countRunSnapshots,
57
57
  Tt: () => startLoop,
58
58
  U: () => hasPendingRun,
59
- Ut: () => validArtifactName,
59
+ Ut: () => sha256Buf,
60
60
  V: () => getRunSnapshot,
61
- Vt: () => loopFiles_exports,
61
+ Vt: () => loopFileNames,
62
62
  W: () => hasRunningRun,
63
- Wt: () => createBlobStore,
63
+ Wt: () => validArtifactName,
64
64
  X: () => listRuns,
65
- Xt: () => coerceCodingAgent,
65
+ Xt: () => CODING_AGENTS,
66
66
  Y: () => listMachines,
67
- Yt: () => CODING_AGENTS,
67
+ Yt: () => runs,
68
68
  Z: () => listRunsBefore,
69
- Zt: () => logger,
69
+ Zt: () => coerceCodingAgent,
70
70
  _: () => acknowledgeRetiredReport,
71
71
  _t: () => releaseAbsentReconciliations,
72
72
  a: () => TERMINAL_GRACE_MS,
@@ -77,7 +77,7 @@ var loopTags_CnVLi70h_exports = /* @__PURE__ */ __exportAll$1({
77
77
  ct: () => putRunSnapshot,
78
78
  d: () => readNewIdempotency,
79
79
  dt: () => reclaimRun,
80
- en: () => GC_INTERVAL_MS,
80
+ en: () => BLOB_GC_GRACE_MS,
81
81
  et: () => loopsForMachine,
82
82
  f: () => recordNewIdempotency,
83
83
  ft: () => reconcileReclaimedRun,
@@ -96,19 +96,20 @@ var loopTags_CnVLi70h_exports = /* @__PURE__ */ __exportAll$1({
96
96
  m: () => retireLease,
97
97
  mt: () => recordBlob,
98
98
  n: () => isOutdated,
99
+ nn: () => __exportAll,
99
100
  nt: () => pauseLoop,
100
101
  o: () => connectKeyValid,
101
102
  ot: () => pruneRunSnapshots,
102
103
  p: () => resolveLease,
103
104
  pt: () => reconciliationStatesForRuns,
104
105
  q: () => listArtifacts,
105
- qt: () => runMigrations,
106
+ qt: () => db,
106
107
  r: () => isValidSemver,
107
108
  rt: () => pauseLoopState,
108
109
  s: () => isDeviceTokenShape,
109
110
  st: () => putReportReceiptIfAbsent,
110
111
  t: () => validateLoopTags,
111
- tn: () => __exportAll,
112
+ tn: () => GC_INTERVAL_MS,
112
113
  tt: () => openRuns,
113
114
  u: () => pruneExpiredLeases,
114
115
  ut: () => recentLoopUsage,
@@ -121,7 +122,7 @@ var loopTags_CnVLi70h_exports = /* @__PURE__ */ __exportAll$1({
121
122
  y: () => advanceDueSchedules,
122
123
  yt: () => requestDeleteLoop,
123
124
  z: () => getReportReceipt,
124
- zt: () => loopFileIssue
125
+ zt: () => isValidHash
125
126
  });
126
127
  var import_pino = /* @__PURE__ */ __toESM(require_pino());
127
128
  var import_pino_pretty = /* @__PURE__ */ __toESM(require_pino_pretty());
@@ -153,9 +154,9 @@ var BLOB_GC_GRACE_MS = 3600 * 1e3;
153
154
  /** Storage-maintenance cadence (prune snapshots, then GC blobs). 15 minutes. */
154
155
  var GC_INTERVAL_MS = 900 * 1e3;
155
156
  /**
156
- * Uses pino-pretty as a *synchronous* destination stream (not a worker-thread
157
- * transport) so logs flush before process.exit() in the one-shot CLIs. Writes to
158
- * stderr (fd 2) to keep stdout clean for QR codes and human CLI output.
157
+ * pino-pretty as a synchronous destination stream (not a worker-thread transport)
158
+ * so logs flush before process.exit() in the one-shot CLIs. Writes to stderr so
159
+ * stdout carries only CLI output.
159
160
  */
160
161
  var logger_exports = /* @__PURE__ */ __exportAll({ logger: () => logger });
161
162
  var level = (process.env.PIEVO_LOG_LEVEL || "info").toLowerCase();
@@ -166,17 +167,9 @@ var stream = (0, import_pino_pretty.default)({
166
167
  ignore: "pid,hostname"
167
168
  });
168
169
  var logger = (0, import_pino.default)({ level }, stream);
169
- /** The coding agent a loop is bound to AND executed with (BYOA on the owner's
170
- * machine): `claude-code` → Claude Code, `codex` → `codex exec`, `pi` → Pi.
171
- * Non-Claude agents may still have thinner daemon telemetry until stream
172
- * integration lands; execution itself is real for every value.
173
- *
174
- * Runtime SINGLE SOURCE (anti-drift): every server consumer DERIVES from this
175
- * array — the `CodingAgent` type here, the `db/schema.ts` `CodingAgent` type AND
176
- * the `loops.agent` column enum, the edit validator (`coerceCodingAgent`), and the
177
- * web agent `<select>` (LoopForm). So widening the set is a one-line edit HERE with
178
- * no other server change (the daemon's own enum in `packages/daemon/src/create.ts`
179
- * is a separate package, widened alongside). */
170
+ /** Single source for coding agents: server types, the `loops.agent` column enum,
171
+ * validators, and the dashboard select all derive from this array. The daemon
172
+ * keeps its own copy in `packages/daemon/src/create.ts`; widen both together. */
180
173
  var CODING_AGENTS = [
181
174
  "claude-code",
182
175
  "codex",
@@ -196,10 +189,6 @@ var RESERVED_LOOP_TAGS = [
196
189
  * Pievo is single-user: no row carries an owner. Timestamp values are ISO
197
190
  * strings; JSON columns use `jsonb().$type<>()`.
198
191
  */
199
- /** `skipped`: a pending run retired without executing (pause/retention cleanup,
200
- * queue coalescing, or the offline catch-up window elapsed).
201
- * Neither success nor failure — excluded from the failure streak (it rides
202
- * phase `canceled`, and the streak counts only phase `error`). */
203
192
  var machines = pgTable("machines", {
204
193
  id: text("id").primaryKey(),
205
194
  name: text("name").notNull(),
@@ -231,8 +220,8 @@ var loops = pgTable("loops", {
231
220
  statusKeep: text("status_keep").notNull(),
232
221
  statusNoChange: text("status_no_change").notNull(),
233
222
  statusBlock: text("status_block").notNull(),
234
- /** Configured artifact file names (`.md`/`.html`), in addition to the
235
- * always-present MEMORY.md. See `gateway/loopFiles.ts`. */
223
+ /** Configured artifact names, in addition to the always-present MEMORY.md.
224
+ * See `gateway/loopFiles.ts`. */
236
225
  artifacts: jsonb("artifacts").$type().notNull().default([]),
237
226
  cron: text("cron").notNull(),
238
227
  scheduleMode: text("schedule_mode", { enum: ["cron", "continuous"] }).notNull(),
@@ -249,11 +238,8 @@ var loops = pgTable("loops", {
249
238
  pauseCause: jsonb("pause_cause").$type(),
250
239
  model: text("model"),
251
240
  reasoningEffort: text("reasoning_effort"),
252
- /** Coding agent this loop is BOUND TO and EXECUTED with: the daemon's
253
- * `buildAgentSpawn` branches on this value (`claude-code` → claude,
254
- * `codex` → `codex exec`, `pi` → Pi print mode). Measured from the creating CLI's env when
255
- * detectable, else the declared/selected value. The text column carries
256
- * both a TypeScript enum and a database CHECK constraint. */
241
+ /** The daemon launches this agent for every run (`buildAgentSpawn`). Enforced by
242
+ * both the TypeScript enum and a database CHECK constraint. */
257
243
  agent: text("agent", { enum: CODING_AGENTS }).notNull(),
258
244
  enabled: boolean("enabled").notNull().default(true),
259
245
  nextRunAt: text("next_run_at"),
@@ -281,6 +267,9 @@ var runs = pgTable("runs", {
281
267
  model: text("model"),
282
268
  reasoningEffort: text("reasoning_effort"),
283
269
  runIndex: integer("run_index"),
270
+ /** A pending run retired without executing (pause, retention cleanup, queue
271
+ * coalescing, or an elapsed offline catch-up window) is `canceled`, not `error`,
272
+ * so it never counts toward the failure streak. */
284
273
  phase: text("phase", { enum: [
285
274
  "pending",
286
275
  "running",
@@ -300,6 +289,9 @@ var runs = pgTable("runs", {
300
289
  "block"
301
290
  ] }),
302
291
  message: text("message"),
292
+ /** Owner-facing reason from the final response's ATTENTION line. Independent
293
+ * of status: it never pauses the loop. */
294
+ attention: text("attention"),
303
295
  durationMs: integer("duration_ms"),
304
296
  exitCode: integer("exit_code"),
305
297
  finalText: text("final_text"),
@@ -403,7 +395,6 @@ var blobs = pgTable("blobs", {
403
395
  var artifactFiles = pgTable("artifact_files", {
404
396
  id: text("id").primaryKey(),
405
397
  loopId: text("loop_id").notNull(),
406
- /** Loop file name: MEMORY.md or a configured artifact name. */
407
398
  path: text("path").notNull(),
408
399
  hash: text("hash"),
409
400
  size: integer("size"),
@@ -486,7 +477,6 @@ function migrationsDir() {
486
477
  if (fs.existsSync(builtDir)) return builtDir;
487
478
  return devDir;
488
479
  }
489
- /** Apply generated migrations in-process (idempotent). */
490
480
  async function runMigrations() {
491
481
  const dir = migrationsDir();
492
482
  if (!fs.existsSync(dir)) return;
@@ -637,7 +627,7 @@ function createBlobStore() {
637
627
  * Loop files: a loop's server-owned memory and display artifacts.
638
628
  *
639
629
  * Every loop has the required `MEMORY.md` plus up to MAX_ARTIFACTS configured
640
- * `.md`/`.html` artifact names. The server is authoritative: bytes live in the
630
+ * text/code artifact names. The server is authoritative: bytes live in the
641
631
  * content-addressed BlobStore and the current version of each name is an
642
632
  * `artifact_files` row. For each run the daemon downloads the current files into
643
633
  * a private run directory, and the terminal report carries the changed versions
@@ -651,6 +641,7 @@ function createBlobStore() {
651
641
  */
652
642
  var loopFiles_exports = /* @__PURE__ */ __exportAll({
653
643
  ARTIFACT_BYTE_CAP: () => ARTIFACT_BYTE_CAP,
644
+ ARTIFACT_EXTENSIONS: () => ARTIFACT_EXTENSIONS,
654
645
  EMPTY_SHA256: () => EMPTY_SHA256,
655
646
  LOOP_FILE_BYTE_CAP: () => LOOP_FILE_BYTE_CAP,
656
647
  LoopFiles: () => LoopFiles,
@@ -668,26 +659,107 @@ var MEMORY_FILE = "MEMORY.md";
668
659
  /** Memory is re-read by every run, so it is bounded in characters (Unicode code
669
660
  * points), roughly 2k tokens of prompt context per run. */
670
661
  var MEMORY_CHAR_CAP = 8e3;
671
- /** HTML reports are bulky; 2 MB keeps a run's upload and the dashboard iframe cheap. */
672
- var ARTIFACT_BYTE_CAP = 2 * 1024 * 1024;
662
+ /** 256 KB bounds a run's upload and keeps dashboard rendering smooth. */
663
+ var ARTIFACT_BYTE_CAP = 256 * 1024;
664
+ var ARTIFACT_LIMIT_LABEL = `${ARTIFACT_BYTE_CAP / 1024} KB`;
673
665
  /** sha256 of zero bytes: the version of a loop file that has never been written. */
674
666
  var EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
675
- var ARTIFACT_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\.(md|html)$/;
667
+ /** Text/code formats accepted as artifacts. Loop files are NUL-free text, so
668
+ * binary formats (images, PDFs, archives) are deliberately absent; `.svg` is
669
+ * text and renders through the hardened inline image route. */
670
+ var ARTIFACT_EXTENSIONS = [
671
+ "md",
672
+ "markdown",
673
+ "mdx",
674
+ "html",
675
+ "htm",
676
+ "txt",
677
+ "text",
678
+ "rst",
679
+ "adoc",
680
+ "org",
681
+ "sh",
682
+ "bash",
683
+ "zsh",
684
+ "fish",
685
+ "ps1",
686
+ "bat",
687
+ "cmd",
688
+ "py",
689
+ "rb",
690
+ "pl",
691
+ "lua",
692
+ "r",
693
+ "js",
694
+ "mjs",
695
+ "cjs",
696
+ "ts",
697
+ "tsx",
698
+ "jsx",
699
+ "go",
700
+ "rs",
701
+ "java",
702
+ "kt",
703
+ "kts",
704
+ "scala",
705
+ "c",
706
+ "h",
707
+ "cc",
708
+ "cpp",
709
+ "hpp",
710
+ "cs",
711
+ "php",
712
+ "swift",
713
+ "dart",
714
+ "ex",
715
+ "exs",
716
+ "erl",
717
+ "hs",
718
+ "clj",
719
+ "cljs",
720
+ "json",
721
+ "jsonl",
722
+ "yaml",
723
+ "yml",
724
+ "toml",
725
+ "xml",
726
+ "csv",
727
+ "tsv",
728
+ "svg",
729
+ "css",
730
+ "scss",
731
+ "sass",
732
+ "less",
733
+ "sql",
734
+ "ini",
735
+ "conf",
736
+ "cfg",
737
+ "env",
738
+ "properties",
739
+ "diff",
740
+ "patch",
741
+ "tex",
742
+ "log"
743
+ ];
744
+ var ARTIFACT_EXTENSION_SET = new Set(ARTIFACT_EXTENSIONS);
745
+ var ARTIFACT_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\.([A-Za-z0-9]{1,16})$/;
676
746
  function sha256Buf(bytes) {
677
747
  return createHash("sha256").update(bytes).digest("hex");
678
748
  }
679
749
  function isValidHash(hash) {
680
750
  return typeof hash === "string" && /^[0-9a-f]{64}$/.test(hash);
681
751
  }
682
- /** A plain file name (no directories) ending in .md or .html, other than MEMORY.md. */
752
+ /** A plain text/code file name (no directories) other than MEMORY.md. */
683
753
  function validArtifactName(name) {
684
- return typeof name === "string" && ARTIFACT_NAME_RE.test(name) && name.toLowerCase() !== "MEMORY.md".toLowerCase();
754
+ if (typeof name !== "string" || name.toLowerCase() === "MEMORY.md".toLowerCase()) return false;
755
+ const match = ARTIFACT_NAME_RE.exec(name);
756
+ return match !== null && ARTIFACT_EXTENSION_SET.has(match[1].toLowerCase());
685
757
  }
686
758
  function loopFileNames(loop) {
687
759
  return [MEMORY_FILE, ...loop.artifacts];
688
760
  }
689
761
  function fileLimitLabel(name) {
690
- return name === "MEMORY.md" ? `${MEMORY_CHAR_CAP} characters` : "2 MB";
762
+ return name === "MEMORY.md" ? `${MEMORY_CHAR_CAP} characters` : ARTIFACT_LIMIT_LABEL;
691
763
  }
692
764
  /** Why `bytes` cannot become the next version of `name`, or undefined if it can. */
693
765
  function loopFileIssue(name, bytes) {
@@ -697,7 +769,7 @@ function loopFileIssue(name, bytes) {
697
769
  if (chars > 8e3) return `${name}: ${chars} characters exceeds the ${MEMORY_CHAR_CAP}-character limit`;
698
770
  return;
699
771
  }
700
- if (bytes.length > 2097152) return `${name}: ${(bytes.length / 1024 / 1024).toFixed(1)} MB exceeds the 2 MB limit`;
772
+ if (bytes.length > 262144) return `${name}: ${(bytes.length / 1024).toFixed(1)} KB exceeds the ${ARTIFACT_LIMIT_LABEL} limit`;
701
773
  }
702
774
  /** The largest byte size any loop file can have (a code point is at most 4 bytes). */
703
775
  var LOOP_FILE_BYTE_CAP = Math.max(ARTIFACT_BYTE_CAP, MEMORY_CHAR_CAP * 4);
@@ -721,10 +793,7 @@ var LoopFiles = class {
721
793
  return hash === "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" || this.blobStore.has(hash);
722
794
  }
723
795
  };
724
- /**
725
- * Data-access layer over Drizzle. Loop-locked state transitions live here; every
726
- * DB-touching function is async, while the pure helpers stay sync.
727
- */
796
+ /** Data-access layer over Drizzle. Loop-locked state transitions live here. */
728
797
  var store_exports = /* @__PURE__ */ __exportAll({
729
798
  TERMINAL_REPORT_GRACE_MS: () => TERMINAL_REPORT_GRACE_MS,
730
799
  acknowledgeRetiredReport: () => acknowledgeRetiredReport,
@@ -1928,19 +1997,15 @@ async function countRunSnapshots() {
1928
1997
  return Number(r?.n ?? 0);
1929
1998
  }
1930
1999
  /**
1931
- * Machine + run credential helpers. Device tokens (`dk_…`) identify a machine
1932
- * (its id is derived from the token: `m-sha256(token)[:16]`). A run
1933
- * LEASE (`rk_…`) is minted per delivery, bound to one run, and carries the
1934
- * run's least-privilege caps — the CLI dispatch authorizes the `pievo` shim
1935
- * against it. Its lifecycle is a small state machine (`active` →
1936
- * `terminal-grace` → `reconciliation-only`/`retired`), not a mint→revoke pair;
1937
- * see `RunLease` below.
2000
+ * Machine and run credentials. A device token (`dk_…`) identifies a machine whose
2001
+ * id is derived from it (`m-sha256(token)[:16]`). A run lease (`rk_…`) is minted per
2002
+ * delivery and authorizes only that run's loop-file transfer and terminal report;
2003
+ * its lifecycle is the state machine on `RunLease`.
1938
2004
  *
1939
- * Leases and connect-key bindings are DURABLE (run_leases / connect_keys
1940
- * tables): they must survive a deploy, or every restart 401s the in-flight
1941
- * runs' callbacks/finalize and prevents a freshly connected machine from
1942
- * enrolling. The 15-minute `new` idempotency window stays in-process;
1943
- * losing it only degrades retry deduplication, never persisted data.
2005
+ * Leases and connect-key bindings are durable so a restart neither rejects
2006
+ * in-flight reports nor blocks a just-connected machine from enrolling. The
2007
+ * 15-minute `new` idempotency window stays in memory; losing it on restart only
2008
+ * weakens retry deduplication.
1944
2009
  */
1945
2010
  var tokens_exports = /* @__PURE__ */ __exportAll({
1946
2011
  CONNECT_KEY_TTL_MS: () => CONNECT_KEY_TTL_MS,
@@ -2203,8 +2268,8 @@ function validateLoopTags(value) {
2203
2268
  };
2204
2269
  }
2205
2270
  //#endregion
2206
- //#region node_modules/.nitro/vite/services/ssr/assets/boot-DmpKtb0A.js
2207
- var boot_DmpKtb0A_exports = /* @__PURE__ */ __exportAll$1({
2271
+ //#region node_modules/.nitro/vite/services/ssr/assets/boot-CecCDRoH.js
2272
+ var boot_CecCDRoH_exports = /* @__PURE__ */ __exportAll$1({
2208
2273
  _: () => validOptionalPollString,
2209
2274
  a: () => POLL_HTTP_BODY_FIELDS,
2210
2275
  c: () => MIN_DAEMON_VERSION,
@@ -2296,11 +2361,8 @@ function validOptionalPollString(value, cap) {
2296
2361
  function nowIso() {
2297
2362
  return (/* @__PURE__ */ new Date()).toISOString();
2298
2363
  }
2299
- /** Strip NUL (U+0000) from a wire string: Postgres text/jsonb columns REJECT the
2300
- * NUL byte (SQLite tolerated it), so a daemon-supplied string carrying one would
2301
- * throw mid-finalize on the DB write. The single sanitizing primitive behind
2302
- * `clipText` - and used directly by `cli.ts`
2303
- * (parseFlags/validateState, the same one-chokepoint discipline). */
2364
+ /** Postgres text/jsonb columns reject NUL, so a daemon-supplied string carrying
2365
+ * one would fail mid-finalize. The single sanitizer behind `clipText` and `cli.ts`. */
2304
2366
  function stripNul(s) {
2305
2367
  return s.replace(/\u0000/g, "");
2306
2368
  }
@@ -2311,13 +2373,14 @@ function clipText(s, cap) {
2311
2373
  * directory before launch (and exports as an env var of the same name). */
2312
2374
  var LOOP_DIR_PLACEHOLDER = "$PIEVO_LOOP_DIR";
2313
2375
  var STATUS_LINE_RE = /^STATUS:\s*(keep|no-change|block)\.?$/i;
2376
+ var ATTENTION_LINE_RE = /^ATTENTION:\s*(.*)$/i;
2314
2377
  /**
2315
2378
  * Deliver the user's prompt unchanged, followed by the status definitions, the
2316
2379
  * loop-file contract, and the final-line status contract. The run index
2317
2380
  * intentionally remains an internal history fact.
2318
2381
  */
2319
2382
  function buildRunTask(loop, previousNotices = []) {
2320
- const files = [`- ${MEMORY_FILE}: this loop's memory, kept across runs (max ${MEMORY_CHAR_CAP} characters). Read it before you start. Before finishing, update it with anything that would help future runs avoid mistakes or work faster. Keep it concise: merge similar notes, delete stale or wrong ones, no run logs.`, ...loop.artifacts.map((name) => `- ${name}: artifact shown on the Pievo dashboard (max 2 MB). Update it only as the task above asks.`)];
2383
+ const files = [`- ${MEMORY_FILE}: this loop's long-term experience (max ${MEMORY_CHAR_CAP} characters). Read it first and follow it. Before finishing, record only lessons this run learned the hard way that make later runs faster or safer: a pitfall hit, a workaround found, an environment fact discovered. One line each; correct or delete lessons that proved wrong. Never restate the task or these instructions, and never store state, results, baselines, trends, or run logs (those go in an artifact). Most runs add nothing.`, ...loop.artifacts.map((name) => `- ${name}: artifact shown on the Pievo dashboard (max ${fileLimitLabel(name)}). Update it only as the task above asks.`)];
2321
2384
  const notices = previousNotices.length ? `\n\nNotices from the previous run:\n${previousNotices.map((notice) => `- ${notice}`).join("\n")}` : "";
2322
2385
  return `${loop.prompt}
2323
2386
 
@@ -2325,18 +2388,23 @@ Status definitions:
2325
2388
  - keep: ${loop.statusKeep}
2326
2389
  - no-change: ${loop.statusNoChange}
2327
2390
  - block: ${loop.statusBlock}
2391
+ A block pauses the loop until the owner restarts it.
2328
2392
 
2329
2393
  Loop files in ${LOOP_DIR_PLACEHOLDER}:
2330
2394
  ${files.join("\n")}
2331
2395
  A file over its limit is rejected and its previous version kept. Other files in that directory are discarded.${notices}
2332
2396
 
2333
- End your final response with a short summary, then exactly one last line:
2397
+ Be concise in everything you write: lead with what changed or needs action; prefer tables and short lists; no filler or restated instructions.
2398
+
2399
+ Your final response is only: a summary of at most five short lines (no headings, no repeated tables or file contents); if the owner should look at something, one line \`ATTENTION: <reason>\`; then exactly one last line:
2334
2400
  STATUS: keep|no-change|block`;
2335
2401
  }
2402
+ var bareLine = (line) => line.trim().replace(/^[*_`>\s]+|[*_`\s]+$/g, "");
2336
2403
  /**
2337
- * Split a provider's final response into the reported status and summary. The
2338
- * final non-empty line must be the status line; markdown emphasis or code ticks
2339
- * around it are tolerated because models add them unprompted.
2404
+ * Split a provider's final response into the reported status, an optional
2405
+ * attention reason from the ATTENTION lines just above it, and the summary. The final
2406
+ * non-empty line must be the status line; markdown emphasis or code ticks around
2407
+ * either line are tolerated because models add them unprompted.
2340
2408
  */
2341
2409
  function parseFinalStatus(finalText) {
2342
2410
  if (!finalText) return void 0;
@@ -2344,12 +2412,26 @@ function parseFinalStatus(finalText) {
2344
2412
  let index = lines.length - 1;
2345
2413
  while (index >= 0 && lines[index].trim() === "") index--;
2346
2414
  if (index < 0) return void 0;
2347
- const bare = lines[index].trim().replace(/^[*_`>\s]+|[*_`\s]+$/g, "");
2348
- const match = STATUS_LINE_RE.exec(bare);
2415
+ const match = STATUS_LINE_RE.exec(bareLine(lines[index]));
2349
2416
  if (!match) return void 0;
2417
+ const status = match[1].toLowerCase();
2418
+ const reasons = [];
2419
+ let end = index;
2420
+ for (;;) {
2421
+ let previous = end;
2422
+ while (previous > 0 && lines[previous - 1].trim() === "") previous--;
2423
+ const attentionMatch = previous > 0 ? ATTENTION_LINE_RE.exec(bareLine(lines[previous - 1])) : null;
2424
+ if (!attentionMatch) break;
2425
+ end = previous - 1;
2426
+ const reason = attentionMatch[1].trim();
2427
+ if (reason && !/^(none|n\/a|-)$/i.test(reason)) reasons.unshift(reason);
2428
+ }
2429
+ const joined = reasons.join("; ");
2430
+ const attention = joined ? joined.length > 200 ? `${joined.slice(0, 199)}…` : joined : null;
2350
2431
  return {
2351
- status: match[1].toLowerCase(),
2352
- message: lines.slice(0, index).join("\n").trim()
2432
+ status,
2433
+ message: lines.slice(0, end).join("\n").trim(),
2434
+ attention
2353
2435
  };
2354
2436
  }
2355
2437
  async function buildDelivery(loop, queuedRun, runToken, roots) {
@@ -2373,31 +2455,11 @@ async function buildDelivery(loop, queuedRun, runToken, roots) {
2373
2455
  };
2374
2456
  }
2375
2457
  /**
2376
- * Loop-file storage retention + garbage collection — the policy that keeps the
2377
- * local byte store from growing monotonically.
2378
- *
2379
- * The loop-file pipeline is content-addressed: blob BYTES are keyed by sha256 and
2380
- * deduped across every loop/run. When a file is deleted or its content changes,
2381
- * the OLD blob is no longer pointed at by the current file row — but nothing was
2382
- * reclaiming it, so the byte store grew forever. This module closes that gap with two pieces:
2383
- *
2384
- * 1. pruneSnapshots() — bound the per-loop run-snapshot history to a window, so
2385
- * old snapshots stop pinning the blobs they referenced for diffs.
2386
- * 2. gcBlobs() — delete blob bytes no LIVE row needs: a blob is collected
2387
- * only when NO artifact_files row AND NO retained run_snapshot references its
2388
- * hash. CORRECTNESS over aggressiveness — a still-referenced blob is never
2389
- * deleted; a leaked blob is only a cost bug the next pass reclaims.
2390
- *
2391
- * Concurrency: gcBlobs is safe alongside owner writes and run uploads. Three guards
2392
- * combine — a grace window (a blob whose metadata row is younger than the window is
2393
- * never collected, so a blob a run just uploaded is untouchable), a point re-check
2394
- * of each candidate immediately before its bytes are deleted (so a blob
2395
- * re-referenced before we touch it keeps both its bytes and metadata), and a
2396
- * bytes-before-metadata delete ordering: each candidate's bytes are reclaimed
2397
- * FIRST, then its metadata row is dropped unconditionally — so blobExists() goes
2398
- * false and any writer that re-references the hash (even one that raced the byte
2399
- * delete) re-uploads the bytes (self-healing). We never leave a live blobs row
2400
- * pointing at deleted bytes.
2458
+ * Loop-file storage retention. Blob bytes are content-addressed and shared, so
2459
+ * replacing a file never frees its old blob by itself. pruneSnapshots() bounds
2460
+ * per-loop snapshot history; gcBlobs() then deletes bytes no file row and no
2461
+ * retained snapshot references. Correctness wins over aggressiveness: a leaked
2462
+ * blob is a storage cost the next pass reclaims, a deleted live blob is data loss.
2401
2463
  */
2402
2464
  var log$2 = logger.child({ mod: "retention" });
2403
2465
  /**
@@ -2411,28 +2473,14 @@ async function pruneSnapshots(keep = 20) {
2411
2473
  return pruned;
2412
2474
  }
2413
2475
  /**
2414
- * Reclaim unreferenced blob bytes. Returns the number of blobs collected.
2415
- *
2416
- * Algorithm:
2417
- * 1. Compute the live keep-set (all hashes any artifact_files row / retained
2418
- * snapshot references) and the grace-windowed candidate list — both reads are
2419
- * synchronous (interleave-free under the single-threaded event loop).
2420
- * 2. Garbage = candidates not in the keep-set.
2421
- * 3. For each garbage hash, in order:
2422
- * a. Pre-delete guard: if a sync re-referenced it since the keep-set was
2423
- * computed, skip it — leaving both its bytes AND metadata row intact
2424
- * (a consistent live blob, nothing to heal). The guard is two O(1) checks:
2425
- * an indexed artifact_files point query (always fresh) plus membership in a
2426
- * snapshot-hash Set deserialized ONCE per pass and rebuilt only when the
2427
- * snapshot row count changes (a report() raced us) — never the old
2428
- * per-candidate full snapshot scan (which was O(garbage × snapshots), since
2429
- * genuine garbage always misses the file check and fell through to it).
2430
- * b. Otherwise delete the BYTES (the await), then drop the metadata row
2431
- * UNCONDITIONALLY. Bytes-before-metadata is the data-loss fix: if a sync
2432
- * raced the byte delete (re-referencing the hash + recreating the blobs
2433
- * row mid-await), dropping the metadata still leaves blobExists()=false,
2434
- * so that file re-uploads its bytes on the next sync. We never leave a
2435
- * live blobs row pointing at deleted bytes.
2476
+ * Reclaim unreferenced blob bytes; returns the number collected. Safe alongside
2477
+ * owner writes and run uploads because of three guards:
2478
+ * - grace window: blobs whose metadata row is younger than `graceMs` are skipped;
2479
+ * - per-candidate re-check right before deletion: an indexed file-row lookup plus
2480
+ * a snapshot-hash set rebuilt only when the snapshot count changes (a concurrent
2481
+ * report), instead of an O(garbage x snapshots) scan;
2482
+ * - bytes before metadata: the metadata row is dropped after the bytes even if a
2483
+ * writer raced the delete, so blobExists() is false and that writer re-uploads.
2436
2484
  */
2437
2485
  async function gcBlobs(blobStore, graceMs = BLOB_GC_GRACE_MS) {
2438
2486
  const refs = await liveBlobRefs();
@@ -2816,7 +2864,7 @@ function validateArtifactNames(value) {
2816
2864
  for (const entry of value) {
2817
2865
  if (!validArtifactName(entry)) return {
2818
2866
  ok: false,
2819
- detail: `artifact must be a plain .md or .html file name other than ${MEMORY_FILE} (letters, digits, . _ -; at most 64 characters before the extension): ${JSON.stringify(entry)}`
2867
+ detail: `artifact must be a plain text/code file name other than ${MEMORY_FILE} (supported extensions: ${ARTIFACT_EXTENSIONS.join(", ")}; letters, digits, . _ -; at most 64 characters before the extension): ${JSON.stringify(entry)}`
2820
2868
  };
2821
2869
  const key = entry.toLowerCase();
2822
2870
  if (seen.has(key)) return {
@@ -3077,22 +3125,16 @@ var validPollWireId = (value) => typeof value === "string" && value.length <= 20
3077
3125
  var validPollCurrentRun = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && Object.prototype.hasOwnProperty.call(value, "runId") && Object.prototype.hasOwnProperty.call(value, "stage") && validPollWireId(value.runId) && (value.stage === "executing" || value.stage === "reporting");
3078
3126
  var validPollInfo = (value) => value === void 0 || value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every((key) => POLL_INFO_FIELDS.has(key)) && validOptionalPollString(value.host, 524288) && validOptionalPollString(value.platform, 524288) && validOptionalPollString(value.arch, 524288) && validOptionalPollString(value.version, 64);
3079
3127
  /**
3080
- * Machine gateway - the run-lifecycle core of the HTTP surface the daemon talks
3081
- * to (poll transport: short-poll while a run is in flight, opt-in server-held
3082
- * long-poll while idle). Framework-agnostic like the rest of the gateway
3083
- * (return `{ status, body }` so the methods can be mounted on a plain http
3084
- * server or TanStack server routes):
3128
+ * Machine gateway: the run-lifecycle core the daemon talks to. Methods return
3129
+ * transport-free `{ status, body }` results for the thin route shells:
3085
3130
  *
3086
- * POST /api/machine/poll (Bearer device token) → claim pending runs, deliver
3087
- * POST /machine/report (Bearer run token) → finalize a run
3088
- * GET|PUT /api/machine/run-files/:name (Bearer run token) → loop-file transfer
3131
+ * POST /api/machine/poll (device token) claim and deliver runs
3132
+ * POST /machine/report (run token) finalize a run
3133
+ * GET|PUT /api/machine/run-files/:name (run token) loop-file transfer
3089
3134
  *
3090
- * plus owner create/list/edit methods and retention.
3091
- * Also exposes `dispatcher` (a `Dispatcher` for the Scheduler: "is the machine
3092
- * online?") and `sweep()` (mark stale machines offline, reclaim stuck runs).
3093
- * CLI verb dispatch at `/api/machine/cli` lives in `gateway/cli.ts`
3094
- * (`CliGateway`), which reuses this class's owner methods;
3095
- * canonical loop configuration validation lives in `gateway/loopConfig.ts`.
3135
+ * Idle polls may be held open (long-poll) until the scheduler's dispatcher wakes
3136
+ * them. `sweep()` marks stale machines offline and reclaims silent runs. CLI verbs
3137
+ * live in `cli.ts`; loop config validation lives in `loopConfig.ts`.
3096
3138
  */
3097
3139
  var log$1 = logger.child({ mod: "gateway" });
3098
3140
  var ONLINE_TTL_MS = 3e4;
@@ -3269,6 +3311,7 @@ function reportOutcome(body) {
3269
3311
  patch: {
3270
3312
  status: parsed.status,
3271
3313
  message: clipText(parsed.message, 2e3) || null,
3314
+ attention: parsed.attention,
3272
3315
  error: null
3273
3316
  }
3274
3317
  };
@@ -3352,7 +3395,6 @@ var MachineGateway = class {
3352
3395
  this.blobStore = blobStore;
3353
3396
  this.loopFiles = new LoopFiles(blobStore);
3354
3397
  }
3355
- /** Loop-file bytes over the same blob store that maintenance garbage-collects. */
3356
3398
  loopFiles;
3357
3399
  /** In-flight latch: the maintenance pass is sequential and the first post-deploy
3358
3400
  * backlog reclamation can overrun the interval, so a fresh tick skips rather than
@@ -3430,20 +3472,12 @@ var MachineGateway = class {
3430
3472
  await pruneExpiredLeases(now);
3431
3473
  for (const loop of await listLoops()) if (loop.deleteRequestedAt) await tryDeleteLoop(loop.id);
3432
3474
  }
3433
- /** Finalize one stuck run as an error (the sweep's reclaim path): persist the
3434
- * failure, TERMINALIZE its run lease (flip it to `terminal-grace` rather than
3435
- * retiring it outright), while preserving a bounded reconciliation window.
3436
- *
3437
- * Why terminalize, not retire: the usual cause is a laptop that merely fell
3438
- * ASLEEP mid-run. When it wakes, claude finishes and the daemon delivers the real
3439
- * (often SUCCESSFUL) result. Retiring the lease here would 401 that late report
3440
- * and strand the run as a permanent false failure with its message lost (the
3441
- * investigated bug). So the lease survives a bounded grace window
3442
- * (`TERMINAL_GRACE_MS`) during which exactly ONE late wake-report may reconcile
3443
- * the run — see `report()`'s terminal-grace branch. The credential is still
3444
- * bounded: CLI mutations are refused while terminal-grace, and the
3445
- * reconciliation retires the lease single-shot. Pending rows are durable inbox
3446
- * entries and are never reclaimed by this path. */
3475
+ /** Reclaim one silent running run as an error, but terminalize its lease instead
3476
+ * of retiring it. The usual cause is a laptop that fell asleep mid-run; on wake
3477
+ * the daemon delivers the real (often successful) result, and a retired lease
3478
+ * would 401 it and leave a false failure. During TERMINAL_GRACE_MS exactly one
3479
+ * late report may reconcile the run (see `report()`); CLI mutations stay refused.
3480
+ * Pending rows are durable queue entries and never reach this path. */
3447
3481
  async reclaimRun(run, reason) {
3448
3482
  if (run.phase !== "running") return;
3449
3483
  const at = nowIso();
@@ -3629,11 +3663,8 @@ var MachineGateway = class {
3629
3663
  waiter.cancel();
3630
3664
  }
3631
3665
  }
3632
- /**
3633
- * Whether this machine (by device token) currently has a live daemon — so
3634
- * Claude Code can avoid starting a duplicate. `online` is fresh-checked against
3635
- * the poll TTL, not just the stored flag.
3636
- */
3666
+ /** Whether this machine has a live daemon. `online` is fresh-checked against the
3667
+ * poll TTL, not just the stored flag. */
3637
3668
  async status(deviceToken) {
3638
3669
  const auth = await authenticateDeviceToken(deviceToken, { allowUnknown: true });
3639
3670
  if (!auth.ok) return auth.response;
@@ -4694,6 +4725,7 @@ function normalizedListRun(run) {
4694
4725
  terminalAt: run.ts,
4695
4726
  phase: run.phase,
4696
4727
  status: run.status ?? null,
4728
+ attention: run.attention ?? null,
4697
4729
  durationMs: run.durationMs ?? null,
4698
4730
  tokenUsage: totalTokenUsage(run.usage ?? null),
4699
4731
  message: message.value,
@@ -4748,6 +4780,7 @@ async function listHistory(loop, q) {
4748
4780
  "terminal",
4749
4781
  "phase",
4750
4782
  "status",
4783
+ "attention",
4751
4784
  "durationMs",
4752
4785
  "tokenUsage",
4753
4786
  "message",
@@ -4757,6 +4790,7 @@ async function listHistory(loop, q) {
4757
4790
  fmt(run.ts),
4758
4791
  run.phase,
4759
4792
  run.status ?? null,
4793
+ run.attention ?? null,
4760
4794
  run.durationMs ?? null,
4761
4795
  totalTokenUsage(run.usage ?? null),
4762
4796
  run.message ? truncate(run.message, 500, "use --run for detail").value : null,
@@ -4804,6 +4838,7 @@ async function detailHistory(loop, q) {
4804
4838
  terminalAt: TERMINAL_PHASES.includes(run.phase) ? run.ts : null,
4805
4839
  phase: run.phase,
4806
4840
  status: run.status ?? null,
4841
+ attention: run.attention ?? null,
4807
4842
  durationMs: run.durationMs ?? null,
4808
4843
  tokenUsage: totalTokenUsage(run.usage ?? null),
4809
4844
  message: message.value,
@@ -4830,6 +4865,7 @@ async function detailHistory(loop, q) {
4830
4865
  ["terminalAt", detail.terminalAt],
4831
4866
  ["phase", detail.phase],
4832
4867
  ["status", detail.status],
4868
+ ["attention", detail.attention],
4833
4869
  ["durationMs", detail.durationMs],
4834
4870
  ["tokenUsage", detail.tokenUsage],
4835
4871
  ["message", detail.message],
@@ -4853,18 +4889,10 @@ async function readLoopHistory(loop, flags) {
4853
4889
  return parsed.value.mode === "detail" ? detailHistory(loop, parsed.value) : listHistory(loop, parsed.value);
4854
4890
  }
4855
4891
  /**
4856
- * CLI dispatch - the credential-keyed verb router half of the machine gateway,
4857
- * split out of `MachineGateway` (which keeps poll/report/sweep/owner verbs).
4858
- * Same wire surface, framework-agnostic like the rest of the gateway
4859
- * (`{ status, body }` results):
4860
- *
4861
- * POST /api/machine/cli (Bearer device OR run credential) → unified dispatch
4862
- *
4863
- * The verb router keys authority on credential type first (`dk_` device prefix
4864
- * vs `rk_` run lease) and reuses the core gateway
4865
- * methods (`createLoop`/`editLoop`) through the injected `MachineGateway`,
4866
- * plus the credential-neutral history module. Run credentials authorize no CLI
4867
- * verb: a run reports through its final response, not a callback.
4892
+ * `/api/machine/cli` verb router. Authority keys on credential type: a device
4893
+ * (`dk_`) token gets owner verbs over loops bound to its machine, reusing
4894
+ * `MachineGateway`'s owner methods; a run (`rk_`) token gets no verb, because a
4895
+ * run reports only through its final response.
4868
4896
  */
4869
4897
  var cliLog = logger.child({ mod: "cli" });
4870
4898
  var CliGateway = class {
@@ -4878,14 +4906,6 @@ var CliGateway = class {
4878
4906
  this.forceDeleteLoop = deps.forceDeleteLoop ?? forceDeleteLoop;
4879
4907
  this.destructiveLog = deps.destructiveLog ?? ((event) => cliLog.warn(event, "force-delete: destructive server authority removal"));
4880
4908
  }
4881
- /**
4882
- * The unified CLI endpoint. It is a ROUTER in front of the gateway logic that
4883
- * already exists — never a rewrite — that keys authority on the credential type:
4884
- * · DEVICE credential (`dk_`-prefixed) → owner authority over any loop bound to
4885
- * the machine: `new`→createLoop, `loops`→listLoops, `edit`→editLoop,
4886
- * `log`→readLoopHistory, `show`→describe, `file`→loop files.
4887
- * · RUN credential (`rk_` run lease) → rejected; runs have no CLI.
4888
- */
4889
4909
  async cli(token, argv) {
4890
4910
  return finalizeCli(token.startsWith("dk_") ? await this.deviceCli(token, argv) : await this.runCli(token, argv));
4891
4911
  }
@@ -5648,14 +5668,8 @@ var Scheduler = class {
5648
5668
  function msg(err) {
5649
5669
  return err instanceof Error ? err.message : String(err);
5650
5670
  }
5651
- /**
5652
- * Server boot — idempotent one-time init of the in-process backend: apply
5653
- * migrations, wire the machine gateway's dispatcher into the Scheduler, start
5654
- * the Scheduler + an offline-sweep interval. Guarded on `globalThis` so it
5655
- * survives dev HMR and runs at most once per process. Call `ensureServer()`
5656
- * from any server-side entry (the standalone machine server / TanStack server
5657
- * fns); the first call boots, the rest share the same instance.
5658
- */
5671
+ /** One-time, idempotent in-process backend boot (migrations, scheduler, sweep and
5672
+ * storage-maintenance intervals). Guarded on `globalThis` to survive dev HMR. */
5659
5673
  var boot_exports = /* @__PURE__ */ __exportAll({
5660
5674
  ensureServer: () => ensureServer,
5661
5675
  getCliGateway: () => getCliGateway,
@@ -5713,4 +5727,4 @@ async function getCliGateway() {
5713
5727
  return (await ensureServer()).cliGateway;
5714
5728
  }
5715
5729
  //#endregion
5716
- export { listRuns as A, requestDeleteLoop as B, getRun as C, listArtifacts as D, isOutdated as E, machinePresence as F, tryDeleteLoop as G, sha256 as H, mintDeviceToken as I, validateLoopTags as J, updateLoop as K, pauseLoop as L, loopTags_CnVLi70h_exports as M, loopsForMachine as N, listLoops as O, machineIdFromToken as P, recentLoopUsage as R, getMachine as S, hasRunningRun as T, startLoop as U, requestRunCancel as V, stopLoop as W, createMachine as _, canonicalLoopSummary as a, getArtifactFile as b, getLoopFiles as c, validOptionalPollString as d, validPollCurrentRun as f, countRuns as g, CODING_AGENTS as h, canonicalLoopEnvelope as i, listRunsBefore as j, listMachines as k, readByteBody as l, validateLoopEdit as m, POLL_HTTP_BODY_FIELDS as n, daemonNeedsUpdate as o, validPollWireId as p, updateMachine as q, boot_DmpKtb0A_exports as r, ensureServer as s, MIN_DAEMON_VERSION as t, readJsonBody as u, forceDeleteLoop as v, hasPendingRun as w, getLoop as x, forceDeleteMachine as y, reconciliationStatesForRuns as z };
5730
+ export { listRuns as A, reconciliationStatesForRuns as B, getRun as C, listArtifacts as D, isOutdated as E, machineIdFromToken as F, stopLoop as G, requestRunCancel as H, machinePresence as I, updateMachine as J, tryDeleteLoop as K, mintDeviceToken as L, loopFileNames as M, loopTags_Bi7Bm7v8_exports as N, listLoops as O, loopsForMachine as P, pauseLoop as R, getMachine as S, hasRunningRun as T, sha256 as U, requestDeleteLoop as V, startLoop as W, validateLoopTags as Y, createMachine as _, canonicalLoopSummary as a, getArtifactFile as b, getLoopFiles as c, validOptionalPollString as d, validPollCurrentRun as f, countRuns as g, CODING_AGENTS as h, canonicalLoopEnvelope as i, listRunsBefore as j, listMachines as k, readByteBody as l, validateLoopEdit as m, POLL_HTTP_BODY_FIELDS as n, daemonNeedsUpdate as o, validPollWireId as p, updateLoop as q, boot_CecCDRoH_exports as r, ensureServer as s, MIN_DAEMON_VERSION as t, readJsonBody as u, forceDeleteLoop as v, hasPendingRun as w, getLoop as x, forceDeleteMachine as y, recentLoopUsage as z };