@kky42/pievo-server 3.0.0 → 4.1.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 (35) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/MarkdownView-BuFKr9Jg.js +66 -0
  3. package/.output/public/assets/app-x1CeeY7N.css +2 -0
  4. package/.output/public/assets/{index-Di_wpAtL.js → index-D0FIKiiW.js} +3 -3
  5. package/.output/public/assets/loops._loopId-DTkIz4C0.js +2 -0
  6. package/.output/public/assets/loops._loopId_.runs._runId-CsV2Ih4Z.js +3 -0
  7. package/.output/public/assets/{preload-helper-hRTYB_ju.js → preload-helper-BSxGu4d0.js} +1 -1
  8. package/.output/public/assets/routes-m4Z90DTR.js +1 -0
  9. package/.output/server/_ssr/{MachinesModal-CmVMec6B.mjs → MachinesModal-CLBZxZkq.mjs} +4 -4
  10. package/.output/server/_ssr/MarkdownView-D1J7ImYF.mjs +70 -0
  11. package/.output/server/_ssr/{artifactFiles-Di1xDKvX.mjs → artifactFiles-B0NPRDOR.mjs} +14 -19
  12. package/.output/server/_ssr/{artifactKind-DqpmtxDU.mjs → artifactKind-a2oxT2wQ.mjs} +4 -4
  13. package/.output/server/_ssr/{boot-CYRi-wez.mjs → boot-DmpKtb0A.mjs} +810 -842
  14. package/.output/server/_ssr/{lifecycleUi-BsbUsi5K.mjs → lifecycleUi-DEjM8Etm.mjs} +5 -5
  15. package/.output/server/_ssr/{loopApi-Bez1rHV0.mjs → loopApi-DK1lQPrx.mjs} +13 -13
  16. package/.output/server/_ssr/{loopProjection-esCjyZJg.mjs → loopProjection-DdFivf7-.mjs} +4 -3
  17. package/.output/server/_ssr/{loops._loopId-KUezNY69.mjs → loops._loopId-DVCvGSEc.mjs} +34 -99
  18. package/.output/server/_ssr/{loops._loopId_.runs._runId-DOkUEesG.mjs → loops._loopId_.runs._runId-BXbTfLlC.mjs} +20 -9
  19. package/.output/server/_ssr/{loops._loopId_.runs._runId-BFP9oMrp.mjs → loops._loopId_.runs._runId-Dr6E-FA5.mjs} +3 -3
  20. package/.output/server/_ssr/{machineFns-CniGcY8s.mjs → machineFns-DLRHgDdS.mjs} +2 -2
  21. package/.output/server/_ssr/{router-BFIH2UAE.mjs → router-BhHsTGqu.mjs} +95 -102
  22. package/.output/server/_ssr/{routes-BSVBANI3.mjs → routes-CCallyCT.mjs} +2 -2
  23. package/.output/server/_ssr/{routes-DnE7XDe_.mjs → routes-CL2Kef-Q.mjs} +4 -4
  24. package/.output/server/_ssr/ssr.mjs +22 -22
  25. package/.output/server/{_tanstack-start-manifest_v-DnwAupbZ.mjs → _tanstack-start-manifest_v-BPiJ4yWT.mjs} +8 -9
  26. package/.output/server/drizzle/0001_loop_files.sql +9 -0
  27. package/.output/server/drizzle/meta/_journal.json +8 -1
  28. package/.output/server/index.mjs +49 -42
  29. package/drizzle/0001_loop_files.sql +9 -0
  30. package/drizzle/meta/_journal.json +8 -1
  31. package/package.json +1 -1
  32. package/.output/public/assets/app-DXLuQNb9.css +0 -2
  33. package/.output/public/assets/loops._loopId-X3ClNPMY.js +0 -67
  34. package/.output/public/assets/loops._loopId_.runs._runId-ByU2BSyF.js +0 -3
  35. package/.output/public/assets/routes-K8D5uBiV.js +0 -1
@@ -1,13 +1,13 @@
1
- import { c as ensureServer, d as readJsonBody, f as validOptionalPollString, m as validPollWireId, p as validPollCurrentRun, r as POLL_HTTP_BODY_FIELDS, t as MACHINE_BODY_CAP, u as readByteBody } from "./boot-CYRi-wez.mjs";
1
+ import { d as validOptionalPollString, f as validPollCurrentRun, l as readByteBody, n as POLL_HTTP_BODY_FIELDS, p as validPollWireId, s as ensureServer, u as readJsonBody } from "./boot-DmpKtb0A.mjs";
2
2
  import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
3
  import { c as createFileRoute, i as HeadContent, l as createRootRoute, o as createRouter, r as Scripts } from "../_libs/@tanstack/react-router+[...].mjs";
4
- import { r as imageMime, t as Route$10 } from "./artifactKind-DqpmtxDU.mjs";
5
- import { t as Route$11 } from "./loops._loopId_.runs._runId-BFP9oMrp.mjs";
6
- import { n as Route$12 } from "./routes-DnE7XDe_.mjs";
7
- //#region node_modules/.nitro/vite/services/ssr/assets/router-BFIH2UAE.js
4
+ import { r as imageMime, t as Route$9 } from "./artifactKind-a2oxT2wQ.mjs";
5
+ import { t as Route$10 } from "./loops._loopId_.runs._runId-Dr6E-FA5.mjs";
6
+ import { n as Route$11 } from "./routes-CL2Kef-Q.mjs";
7
+ //#region node_modules/.nitro/vite/services/ssr/assets/router-BhHsTGqu.js
8
8
  var import_jsx_runtime = require_jsx_runtime();
9
- var app_default = "/assets/app-DXLuQNb9.css";
10
- var Route$9 = createRootRoute({
9
+ var app_default = "/assets/app-x1CeeY7N.css";
10
+ var Route$8 = createRootRoute({
11
11
  head: () => ({
12
12
  meta: [
13
13
  { charSet: "utf-8" },
@@ -43,7 +43,7 @@ async function machineJsonRoute(request, options) {
43
43
  const auth = request.headers.get("authorization") ?? "";
44
44
  const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
45
45
  if (!token) return Response.json({ error: options.missingCredential }, { status: 401 });
46
- const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
46
+ const parsed = await readJsonBody(request, options.maxBytes ?? 2097152);
47
47
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
48
48
  if (parsed.kind !== "ok") {
49
49
  if (options.invalidBody === void 0) return Response.json({ error: options.invalidJsonError ?? "invalid JSON body" }, { status: 400 });
@@ -53,13 +53,13 @@ async function machineJsonRoute(request, options) {
53
53
  if (body === null) return Response.json({ error: options.invalidBodyError ?? "invalid request body" }, { status: 400 });
54
54
  return options.handle(token, body);
55
55
  }
56
- var Route$8 = createFileRoute("/machine/report")({ server: { handlers: { POST: async ({ request }) => {
56
+ var Route$7 = createFileRoute("/machine/report")({ server: { handlers: { POST: async ({ request }) => {
57
57
  return machineJsonRoute(request, {
58
58
  missingCredential: "missing token",
59
59
  invalidBody: {},
60
60
  parseBody: (value) => value && typeof value === "object" ? value : {},
61
61
  handle: async (token, body) => {
62
- const { getGateway } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
62
+ const { getGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
63
63
  const r = await (await getGateway()).report(token, body);
64
64
  return Response.json(r.body, { status: r.status });
65
65
  }
@@ -78,38 +78,13 @@ async function readyResponse(ensure = ensureServer, env = process.env) {
78
78
  nonce: env.PIEVO_SERVER_LAUNCH_NONCE ?? null
79
79
  });
80
80
  }
81
- var Route$7 = createFileRoute("/api/ready")({ server: { handlers: { GET: () => readyResponse() } } });
82
- var Route$6 = createFileRoute("/api/health")({ server: { handlers: { GET: async () => Response.json({ ok: true }) } } });
83
- /**
84
- * POST /api/machine/sync — exact artifact sync (Bearer DEVICE token). The daemon
85
- * posts the complete configured-path manifest after a run; the server reconciles
86
- * artifact_files and replies with needHashes for raw blob PUTs.
87
- * The manifest route retains its dedicated 32 MB JSON-body limit.
88
- *
89
- * This byte-ingress route is deliberately NOT rate limited (same rationale as the
90
- * blob PUT): it requires a valid registered device token (unknown ⇒ 401) and is
91
- * already bounded by the exact-path/hash handshake and 32MB sync-body cap, so a
92
- * limiter would only throttle a legitimate large sync.
93
- */
94
- var Route$5 = createFileRoute("/api/machine/sync")({ server: { handlers: { POST: async ({ request }) => {
95
- const auth = request.headers.get("authorization") ?? "";
96
- const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
97
- if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
98
- const { SYNC_BODY_CAP, parseArtifactSyncBody } = await import("./boot-CYRi-wez.mjs").then((n) => n.N).then((n) => n.v);
99
- const parsed = await readJsonBody(request, SYNC_BODY_CAP);
100
- if (parsed.kind === "too-large") return Response.json({ error: "sync body too large" }, { status: 413 });
101
- if (parsed.kind === "invalid") return Response.json({ error: "invalid JSON" }, { status: 400 });
102
- const body = parseArtifactSyncBody(parsed.body);
103
- if (!body) return Response.json({ error: "invalid sync body" }, { status: 400 });
104
- const { getArtifactSync } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
105
- const r = await (await getArtifactSync()).sync(token, body);
106
- return Response.json(r.body, { status: r.status });
107
- } } } });
81
+ var Route$6 = createFileRoute("/api/ready")({ server: { handlers: { GET: () => readyResponse() } } });
82
+ var Route$5 = createFileRoute("/api/health")({ server: { handlers: { GET: async () => Response.json({ ok: true }) } } });
108
83
  var Route$4 = createFileRoute("/api/machine/status")({ server: { handlers: { GET: async ({ request }) => {
109
84
  const auth = request.headers.get("authorization") ?? "";
110
85
  const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
111
86
  if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
112
- const { getGateway } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
87
+ const { getGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
113
88
  const r = await (await getGateway()).status(token);
114
89
  return Response.json(r.body, { status: r.status });
115
90
  } } } });
@@ -147,7 +122,7 @@ var Route$3 = createFileRoute("/api/machine/poll")({ server: { handlers: { POST:
147
122
  invalidJsonError: "invalid JSON body",
148
123
  parseBody: parsePollBody,
149
124
  handle: async (token, body) => {
150
- const { getGateway } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
125
+ const { getGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
151
126
  const r = await (await getGateway()).pollV4Wait(token, gatewayPollRequest(body));
152
127
  return Response.json(r.body, { status: r.status });
153
128
  }
@@ -163,17 +138,19 @@ function parseCliBody(value) {
163
138
  /**
164
139
  * POST /api/machine/cli — the ONE unified CLI dispatch (Bearer credential + `{argv}`).
165
140
  * `CliGateway.cli()` branches by credential type: a `dk_` device token takes owner
166
- * commands, while an `rk_` run credential can only report its run. Uses the standard
167
- * 2MB machine JSON body cap.
141
+ * commands; an `rk_` run credential is rejected. The 4 MB body cap fits
142
+ * `file set` carrying a 2 MB artifact as base64 (4/3 expansion) plus argv framing.
168
143
  */
144
+ var CLI_BODY_CAP = 4 * 1024 * 1024;
169
145
  var Route$2 = createFileRoute("/api/machine/cli")({ server: { handlers: { POST: async ({ request }) => {
170
146
  return machineJsonRoute(request, {
171
147
  missingCredential: "missing credential",
148
+ maxBytes: CLI_BODY_CAP,
172
149
  invalidJsonError: "body must be exactly {argv:string[]}",
173
150
  invalidBodyError: "body must be exactly {argv:string[]}",
174
151
  parseBody: parseCliBody,
175
152
  handle: async (token, body) => {
176
- const { getCliGateway } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
153
+ const { getCliGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
177
154
  const r = await (await getCliGateway()).cli(token, body.argv);
178
155
  return Response.json(r.body, { status: r.status });
179
156
  }
@@ -193,36 +170,59 @@ function safeDecode(s) {
193
170
  }
194
171
  }
195
172
  /**
196
- * PUT /api/machine/blob/:hash — upload one content-addressed blob's raw bytes
197
- * (Bearer DEVICE token). The server recomputes sha256(body) and rejects a
198
- * mismatch before storing in the byte store. The hash is read from the URL (the daemon PUTs
199
- * exactly the hashes the sync handshake returned in needHashes).
173
+ * GET|PUT /api/machine/run-files/:name — loop-file transfer for one run (Bearer
174
+ * RUN token). GET returns the version the run starts from, with its sha256 in
175
+ * `x-pievo-sha256`; PUT stores a version the run produced (the daemon sends the
176
+ * expected sha256 in the same header). A PUT never changes the loop: only the
177
+ * terminal report applies stored versions, under the loop lock.
200
178
  *
201
- * This byte-ingress route is deliberately NOT rate limited: it requires a valid
202
- * registered device token (unknown ⇒ 401, not an unauthenticated surface) and is
203
- * already bounded by the sync hash-handshake (the server only accepts hashes it
204
- * asked THIS machine for) plus the per-file 10MB byte cap. A
205
- * large first sync bursts many concurrent PUTs on one token, so any limiter would
206
- * only throttle legitimate uploads without adding real protection.
179
+ * Not rate limited: a live run token is required and every body is bounded by
180
+ * the per-file loop-file limit.
207
181
  */
208
- var Route$1 = createFileRoute("/api/machine/blob/$hash")({ server: { handlers: { PUT: async ({ request }) => {
182
+ function bearer(request) {
209
183
  const auth = request.headers.get("authorization") ?? "";
210
- const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
211
- if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
212
- const hash = safeDecode(new URL(request.url).pathname.split("/").pop() ?? "");
213
- if (hash === null) return Response.json({ error: "bad hash" }, { status: 400 });
214
- const { BLOB_CAP } = await import("./boot-CYRi-wez.mjs").then((n) => n.N).then((n) => n.v);
215
- const body = await readByteBody(request, BLOB_CAP);
216
- if (body.kind === "too-large") return Response.json({ error: "blob exceeds size cap" }, { status: 413 });
217
- if (body.kind === "invalid") return Response.json({ error: "could not read blob body" }, { status: 400 });
218
- const buf = Buffer.from(body.bytes.buffer, body.bytes.byteOffset, body.bytes.byteLength);
219
- const { getArtifactSync } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.t);
220
- const r = await (await getArtifactSync()).putBlob(token, hash, buf);
221
- return Response.json(r.body, { status: r.status });
222
- } } } });
184
+ return auth.startsWith("Bearer ") ? auth.slice(7) : "";
185
+ }
186
+ function fileName(request) {
187
+ return safeDecode(new URL(request.url).pathname.split("/").pop() ?? "");
188
+ }
189
+ var Route$1 = createFileRoute("/api/machine/run-files/$name")({ server: { handlers: {
190
+ GET: async ({ request }) => {
191
+ const token = bearer(request);
192
+ if (!token) return Response.json({ error: "missing run token" }, { status: 401 });
193
+ const name = fileName(request);
194
+ if (name === null) return Response.json({ error: "bad file name" }, { status: 400 });
195
+ const { getGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
196
+ const r = await (await getGateway()).readRunFile(token, name);
197
+ if (r.status !== 200 || !r.bytes || !r.hash) return Response.json(r.body, { status: r.status });
198
+ return new Response(new Uint8Array(r.bytes), {
199
+ status: 200,
200
+ headers: {
201
+ "content-type": "application/octet-stream",
202
+ "content-length": String(r.bytes.length),
203
+ "x-pievo-sha256": r.hash,
204
+ "cache-control": "private, no-store"
205
+ }
206
+ });
207
+ },
208
+ PUT: async ({ request }) => {
209
+ const token = bearer(request);
210
+ if (!token) return Response.json({ error: "missing run token" }, { status: 401 });
211
+ const name = fileName(request);
212
+ if (name === null) return Response.json({ error: "bad file name" }, { status: 400 });
213
+ const { LOOP_FILE_BYTE_CAP } = await import("./boot-DmpKtb0A.mjs").then((n) => n.M).then((n) => n.Vt);
214
+ const body = await readByteBody(request, LOOP_FILE_BYTE_CAP);
215
+ if (body.kind === "too-large") return Response.json({ error: "file exceeds the loop-file size limit" }, { status: 413 });
216
+ if (body.kind === "invalid") return Response.json({ error: "could not read file body" }, { status: 400 });
217
+ const bytes = Buffer.from(body.bytes.buffer, body.bytes.byteOffset, body.bytes.byteLength);
218
+ const { getGateway } = await import("./boot-DmpKtb0A.mjs").then((n) => n.r).then((n) => n.t);
219
+ const r = await (await getGateway()).storeRunFile(token, name, bytes, request.headers.get("x-pievo-sha256"));
220
+ return Response.json(r.body, { status: r.status });
221
+ }
222
+ } } });
223
223
  /**
224
- * GET /api/artifact/:loopId/:path - stream one of a loop's live-synced artifact
225
- * blobs. Two dispositions:
224
+ * GET /api/artifact/:loopId/:path - stream one of a loop's file blobs.
225
+ * Two dispositions:
226
226
  * - default: `attachment` (the download affordance for binary/oversize files;
227
227
  * text is shown inline via getArtifact).
228
228
  * - `?view=inline`: for a KNOWN image type only (the `imageMime` allowlist),
@@ -233,10 +233,9 @@ var Route$1 = createFileRoute("/api/machine/blob/$hash")({ server: { handlers: {
233
233
  * scripts - so an inline SVG can't run script against the session even if the
234
234
  * URL is opened directly. Non-image inline requests fall back to attachment.
235
235
  *
236
- * Served to dashboard callers like the server functions. Path-safe: the relative path is
237
- * normalized + traversal-rejected before it ever reaches a blob, and blob keys
238
- * are content hashes, never the user path. Reads stream from the local
239
- * BlobStore; the route never writes.
236
+ * Served to dashboard callers like the server functions. The path is matched
237
+ * exactly against a loop's stored file rows, and blob keys are content hashes,
238
+ * never the user path. Reads stream from the local BlobStore; the route never writes.
240
239
  */
241
240
  var PREFIX = "/api/artifact/";
242
241
  var Route = createFileRoute("/api/artifact/$loopId/$")({ server: { handlers: { GET: async ({ request }) => {
@@ -250,8 +249,8 @@ var Route = createFileRoute("/api/artifact/$loopId/$")({ server: { handlers: { G
250
249
  const segments = after.slice(slash + 1).split("/").map((s) => safeDecode(s));
251
250
  if (segments.some((s) => s === null)) return Response.json({ error: "bad path" }, { status: 400 });
252
251
  const relPath = segments.join("/");
253
- if (!await (await import("./boot-CYRi-wez.mjs").then((n) => n.N).then((n) => n.It)).getLoop(loopId)) return Response.json({ error: "not found" }, { status: 404 });
254
- const { readLoopArtifactBytes } = await import("./artifactFiles-Di1xDKvX.mjs");
252
+ if (!await (await import("./boot-DmpKtb0A.mjs").then((n) => n.M).then((n) => n.Dt)).getLoop(loopId)) return Response.json({ error: "not found" }, { status: 404 });
253
+ const { readLoopArtifactBytes } = await import("./artifactFiles-B0NPRDOR.mjs");
255
254
  const r = await readLoopArtifactBytes(loopId, relPath);
256
255
  if (r.status !== 200 || !r.bytes) return Response.json({ error: "not found" }, { status: r.status });
257
256
  const filename = (r.filename || "file").replace(/["\\\r\n]/g, "_");
@@ -277,60 +276,55 @@ var Route = createFileRoute("/api/artifact/$loopId/$")({ server: { handlers: { G
277
276
  }
278
277
  });
279
278
  } } } });
280
- var IndexRoute = Route$12.update({
279
+ var IndexRoute = Route$11.update({
281
280
  id: "/",
282
281
  path: "/",
283
- getParentRoute: () => Route$9
282
+ getParentRoute: () => Route$8
284
283
  });
285
- var MachineReportRoute = Route$8.update({
284
+ var MachineReportRoute = Route$7.update({
286
285
  id: "/machine/report",
287
286
  path: "/machine/report",
288
- getParentRoute: () => Route$9
287
+ getParentRoute: () => Route$8
289
288
  });
290
- var LoopsLoopIdRoute = Route$10.update({
289
+ var LoopsLoopIdRoute = Route$9.update({
291
290
  id: "/loops/$loopId",
292
291
  path: "/loops/$loopId",
293
- getParentRoute: () => Route$9
292
+ getParentRoute: () => Route$8
294
293
  });
295
- var ApiReadyRoute = Route$7.update({
294
+ var ApiReadyRoute = Route$6.update({
296
295
  id: "/api/ready",
297
296
  path: "/api/ready",
298
- getParentRoute: () => Route$9
297
+ getParentRoute: () => Route$8
299
298
  });
300
- var ApiHealthRoute = Route$6.update({
299
+ var ApiHealthRoute = Route$5.update({
301
300
  id: "/api/health",
302
301
  path: "/api/health",
303
- getParentRoute: () => Route$9
304
- });
305
- var ApiMachineSyncRoute = Route$5.update({
306
- id: "/api/machine/sync",
307
- path: "/api/machine/sync",
308
- getParentRoute: () => Route$9
302
+ getParentRoute: () => Route$8
309
303
  });
310
304
  var ApiMachineStatusRoute = Route$4.update({
311
305
  id: "/api/machine/status",
312
306
  path: "/api/machine/status",
313
- getParentRoute: () => Route$9
307
+ getParentRoute: () => Route$8
314
308
  });
315
309
  var ApiMachinePollRoute = Route$3.update({
316
310
  id: "/api/machine/poll",
317
311
  path: "/api/machine/poll",
318
- getParentRoute: () => Route$9
312
+ getParentRoute: () => Route$8
319
313
  });
320
314
  var ApiMachineCliRoute = Route$2.update({
321
315
  id: "/api/machine/cli",
322
316
  path: "/api/machine/cli",
323
- getParentRoute: () => Route$9
317
+ getParentRoute: () => Route$8
324
318
  });
325
- var LoopsLoopIdRunsRunIdRoute = Route$11.update({
319
+ var LoopsLoopIdRunsRunIdRoute = Route$10.update({
326
320
  id: "/loops/$loopId_/runs/$runId",
327
321
  path: "/loops/$loopId/runs/$runId",
328
- getParentRoute: () => Route$9
322
+ getParentRoute: () => Route$8
329
323
  });
330
- var ApiMachineBlobHashRoute = Route$1.update({
331
- id: "/api/machine/blob/$hash",
332
- path: "/api/machine/blob/$hash",
333
- getParentRoute: () => Route$9
324
+ var ApiMachineRunFilesNameRoute = Route$1.update({
325
+ id: "/api/machine/run-files/$name",
326
+ path: "/api/machine/run-files/$name",
327
+ getParentRoute: () => Route$8
334
328
  });
335
329
  var rootRouteChildren = {
336
330
  IndexRoute,
@@ -341,16 +335,15 @@ var rootRouteChildren = {
341
335
  ApiMachineCliRoute,
342
336
  ApiMachinePollRoute,
343
337
  ApiMachineStatusRoute,
344
- ApiMachineSyncRoute,
345
338
  ApiArtifactLoopIdSplatRoute: Route.update({
346
339
  id: "/api/artifact/$loopId/$",
347
340
  path: "/api/artifact/$loopId/$",
348
- getParentRoute: () => Route$9
341
+ getParentRoute: () => Route$8
349
342
  }),
350
- ApiMachineBlobHashRoute,
343
+ ApiMachineRunFilesNameRoute,
351
344
  LoopsLoopIdRunsRunIdRoute
352
345
  };
353
- var routeTree = Route$9._addFileChildren(rootRouteChildren)._addFileTypes();
346
+ var routeTree = Route$8._addFileChildren(rootRouteChildren)._addFileTypes();
354
347
  function getRouter() {
355
348
  return createRouter({
356
349
  routeTree,
@@ -1,6 +1,6 @@
1
1
  import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
- import { n as Route, t as DashboardView } from "./routes-DnE7XDe_.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-BSVBANI3.js
2
+ import { n as Route, t as DashboardView } from "./routes-CL2Kef-Q.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-CCallyCT.js
4
4
  var import_jsx_runtime = require_jsx_runtime();
5
5
  /** First-load failure screen — a calm retry instead of the router's default
6
6
  * error dump. Only the initial loader can land here; the in-page poll is
@@ -1,10 +1,10 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_react, h as require_jsx_runtime, s as TooltipProvider } from "../_libs/@base-ui/react+[...].mjs";
3
3
  import { c as createFileRoute, d as useNavigate, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
4
- import { c as getConfig, f as listLoops, m as mintConnectKey, p as loadOlderRuns } from "./lifecycleUi-BsbUsi5K.mjs";
4
+ import { c as getConfig, f as listLoops, m as mintConnectKey, p as loadOlderRuns } from "./lifecycleUi-DEjM8Etm.mjs";
5
5
  import { f as btnSm, y as focusRing } from "./actionUi-DE-Pb2tv.mjs";
6
- import { c as listMachines, i as ModalHead, l as mergeRuns, n as MachinesModal, o as connectServerUrl, r as Modal, s as daemonConnectCommand, t as LoopOverview } from "./MachinesModal-CmVMec6B.mjs";
7
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-DnE7XDe_.js
6
+ import { c as listMachines, i as ModalHead, l as mergeRuns, n as MachinesModal, o as connectServerUrl, r as Modal, s as daemonConnectCommand, t as LoopOverview } from "./MachinesModal-CLBZxZkq.mjs";
7
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-CL2Kef-Q.js
8
8
  var import_react = /* @__PURE__ */ __toESM(require_react());
9
9
  var import_jsx_runtime = require_jsx_runtime();
10
10
  function LoopCard({ loop, onOpen, onPickRun }) {
@@ -521,7 +521,7 @@ function DashboardView({ initial }) {
521
521
  var headerBtn = "inline-flex shrink-0 cursor-pointer items-center rounded-full px-3 py-1.5 text-meta font-medium text-secondary transition-colors hover:bg-raised hover:text-display";
522
522
  var headerIconBtn = "shrink-0 cursor-pointer items-center rounded-full p-1.5 text-secondary transition-colors hover:bg-raised hover:text-display";
523
523
  var $$splitErrorComponentImporter = () => import("./routes-ngpX7h8D.mjs");
524
- var $$splitComponentImporter = () => import("./routes-BSVBANI3.mjs");
524
+ var $$splitComponentImporter = () => import("./routes-CCallyCT.mjs");
525
525
  var Route = createFileRoute("/")({
526
526
  ssr: false,
527
527
  loader: () => fetchLiveData(),
@@ -3414,7 +3414,7 @@ var defaultSerovalPlugins = [
3414
3414
  * the dev styles URL for route-scoped CSS collection.
3415
3415
  */
3416
3416
  async function getStartManifest(matchedRoutes) {
3417
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-DnwAupbZ.mjs");
3417
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-BPiJ4yWT.mjs");
3418
3418
  const startManifest = tsrStartManifest();
3419
3419
  let routes = startManifest.routes;
3420
3420
  routes[rootRouteId];
@@ -3436,83 +3436,83 @@ async function getStartManifest(matchedRoutes) {
3436
3436
  var manifest = {
3437
3437
  "08565e35f6a3dd06ef25401de0343976c47f7ae319d3baed6320b56dd3718311": {
3438
3438
  functionName: "runLoop_createServerFn_handler",
3439
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3439
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3440
3440
  },
3441
3441
  "08c28b892712a1b491b120b74c7dcb81761988d31ccea60216d1807b73c1182c": {
3442
3442
  functionName: "getRunDiff_createServerFn_handler",
3443
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3443
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3444
3444
  },
3445
3445
  "169566e7637a22599b4eb32ee3775574e99677406922bbef7482a102036c33dd": {
3446
3446
  functionName: "machineStatus_createServerFn_handler",
3447
- importer: () => import("./machineFns-CniGcY8s.mjs")
3447
+ importer: () => import("./machineFns-DLRHgDdS.mjs")
3448
3448
  },
3449
3449
  "23e290b2b7483ceea6fe669024c35b12c2c4ddd76649f6fab21c958ceda02940": {
3450
3450
  functionName: "listLoops_createServerFn_handler",
3451
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3451
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3452
3452
  },
3453
3453
  "27d7eba0b6a2257949392fdd56057275a5c5366484ae01faf3b5897a225ecd83": {
3454
3454
  functionName: "finalizeMachine_createServerFn_handler",
3455
- importer: () => import("./machineFns-CniGcY8s.mjs")
3455
+ importer: () => import("./machineFns-DLRHgDdS.mjs")
3456
3456
  },
3457
3457
  "5660ea82ea5ff2549e0ce2f8f070c54f3e9e24fee84d547601ef5d6ef49a4016": {
3458
3458
  functionName: "startLoop_createServerFn_handler",
3459
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3459
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3460
3460
  },
3461
3461
  "5e0d6b55f5629faac2f55a68661eeb82668b2be752192b16264ffb5cd1e6fabe": {
3462
3462
  functionName: "deleteLoop_createServerFn_handler",
3463
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3463
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3464
3464
  },
3465
3465
  "6850ba403da9dec5aff45794eb52636ca540ddec2d9e59f5c75ccbb852bfeacb": {
3466
3466
  functionName: "stopRun_createServerFn_handler",
3467
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3467
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3468
3468
  },
3469
3469
  "85fdf73d4fee43aed762f93c5d47d33200fbff39e2d082647dc921f610d32698": {
3470
3470
  functionName: "loadOlderRuns_createServerFn_handler",
3471
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3471
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3472
3472
  },
3473
3473
  "95b7483b333d7649e70c848319417e83c2af6a0327bbcda2d0e331f626dffe05": {
3474
3474
  functionName: "pauseLoop_createServerFn_handler",
3475
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3475
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3476
3476
  },
3477
3477
  "9befe6b8d67ccbbd7aa9b538bde2a161a9894761c8936761a9503fda1a88c0fc": {
3478
3478
  functionName: "patchLoop_createServerFn_handler",
3479
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3479
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3480
3480
  },
3481
3481
  "a6384dc7154d9930422d29396f5de64b3ac69c62ad3824bc4a22d745fc07b293": {
3482
3482
  functionName: "deleteMachine_createServerFn_handler",
3483
- importer: () => import("./machineFns-CniGcY8s.mjs")
3483
+ importer: () => import("./machineFns-DLRHgDdS.mjs")
3484
3484
  },
3485
3485
  "aa46310016bb8a58b273a648ffd498c87f1f450d12827e30110a3b83ba6a27d9": {
3486
3486
  functionName: "listMachines_createServerFn_handler",
3487
- importer: () => import("./machineFns-CniGcY8s.mjs")
3487
+ importer: () => import("./machineFns-DLRHgDdS.mjs")
3488
3488
  },
3489
3489
  "b050455aacc84dd2a2c9a45517826ad10f91d8f1545e87cc7015784cc7116a97": {
3490
3490
  functionName: "getLoopDetail_createServerFn_handler",
3491
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3491
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3492
3492
  },
3493
3493
  "b18bbec3d06dfc77714e1e527dfb9172fd7575a64a6c0d6e73ba6dc658dccf0d": {
3494
3494
  functionName: "getArtifacts_createServerFn_handler",
3495
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3495
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3496
3496
  },
3497
3497
  "cbb6a1b09b309459bbba3dc3851ae85fc468658b3cda77e22b6c6f3e28b65af4": {
3498
3498
  functionName: "getConfig_createServerFn_handler",
3499
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3499
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3500
3500
  },
3501
3501
  "ce43dcb9366e7c8f7338a6ad28e4290b75a5ee3b13d0d2c9cb585020008f12c6": {
3502
3502
  functionName: "mintConnectKey_createServerFn_handler",
3503
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3503
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3504
3504
  },
3505
3505
  "e233a461e4526dec3cc4cbaa891a7c3621d5967ce7f32b4fb17e9fb645857b9a": {
3506
3506
  functionName: "stopLoop_createServerFn_handler",
3507
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3507
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3508
3508
  },
3509
3509
  "ed10d5fe79208e5e0e4e18e4a17b18d7f7db4dd16204c00c3ac90c4644668841": {
3510
3510
  functionName: "getArtifact_createServerFn_handler",
3511
- importer: () => import("./loopApi-Bez1rHV0.mjs")
3511
+ importer: () => import("./loopApi-DK1lQPrx.mjs")
3512
3512
  },
3513
3513
  "ed679b4e1e05e903a5d4ba4a70d9b9d883991ab22ed59b4d2d69078941818415": {
3514
3514
  functionName: "createMachine_createServerFn_handler",
3515
- importer: () => import("./machineFns-CniGcY8s.mjs")
3515
+ importer: () => import("./machineFns-DLRHgDdS.mjs")
3516
3516
  }
3517
3517
  };
3518
3518
  async function getServerFnById(id, access) {
@@ -5344,7 +5344,7 @@ var getBaseManifest = getProdBaseManifest;
5344
5344
  var createEarlyHintsForRequest = createEarlyHintsCollector;
5345
5345
  async function loadEntries() {
5346
5346
  const [routerEntry, startEntry, pluginAdapters] = await Promise.all([
5347
- import("./router-BFIH2UAE.mjs"),
5347
+ import("./router-BhHsTGqu.mjs"),
5348
5348
  import("./start-B5_9Z5W-.mjs"),
5349
5349
  import("./empty-plugin-adapters-DKUlnwwl.mjs")
5350
5350
  ]);
@@ -1,4 +1,4 @@
1
- //#region node_modules/.nitro/vite/services/ssr/assets/_tanstack-start-manifest_v-DnwAupbZ.js
1
+ //#region node_modules/.nitro/vite/services/ssr/assets/_tanstack-start-manifest_v-BPiJ4yWT.js
2
2
  var tsrStartManifest = () => ({ routes: {
3
3
  __root__: {
4
4
  filePath: "/home/runner/work/pievo/pievo/packages/server/src/routes/__root.tsx",
@@ -11,36 +11,35 @@ var tsrStartManifest = () => ({ routes: {
11
11
  "/api/machine/cli",
12
12
  "/api/machine/poll",
13
13
  "/api/machine/status",
14
- "/api/machine/sync",
15
14
  "/api/artifact/$loopId/$",
16
- "/api/machine/blob/$hash",
15
+ "/api/machine/run-files/$name",
17
16
  "/loops/$loopId_/runs/$runId"
18
17
  ],
19
18
  preloads: [
20
- "/assets/index-Di_wpAtL.js",
19
+ "/assets/index-D0FIKiiW.js",
21
20
  "/assets/actionUi-BZrLpgHT.js",
22
- "/assets/preload-helper-hRTYB_ju.js"
21
+ "/assets/preload-helper-BSxGu4d0.js"
23
22
  ],
24
23
  scripts: [{ attrs: {
25
24
  type: "module",
26
25
  async: !0,
27
- src: "/assets/index-Di_wpAtL.js"
26
+ src: "/assets/index-D0FIKiiW.js"
28
27
  } }]
29
28
  },
30
29
  "/": {
31
30
  filePath: "/home/runner/work/pievo/pievo/packages/server/src/routes/index.tsx",
32
31
  children: void 0,
33
- preloads: ["/assets/routes-BIOJZsig.js", "/assets/routes-K8D5uBiV.js"]
32
+ preloads: ["/assets/routes-BIOJZsig.js", "/assets/routes-m4Z90DTR.js"]
34
33
  },
35
34
  "/loops/$loopId": {
36
35
  filePath: "/home/runner/work/pievo/pievo/packages/server/src/routes/loops.$loopId.tsx",
37
36
  children: void 0,
38
- preloads: ["/assets/loops._loopId-X3ClNPMY.js"]
37
+ preloads: ["/assets/loops._loopId-DTkIz4C0.js", "/assets/MarkdownView-BuFKr9Jg.js"]
39
38
  },
40
39
  "/loops/$loopId_/runs/$runId": {
41
40
  filePath: "/home/runner/work/pievo/pievo/packages/server/src/routes/loops.$loopId_.runs.$runId.tsx",
42
41
  children: void 0,
43
- preloads: ["/assets/loops._loopId_.runs._runId-ByU2BSyF.js"]
42
+ preloads: ["/assets/loops._loopId_.runs._runId-CsV2Ih4Z.js", "/assets/MarkdownView-BuFKr9Jg.js"]
44
43
  }
45
44
  } });
46
45
  //#endregion
@@ -0,0 +1,9 @@
1
+ -- Loop files replace workdir-relative artifact sync (protocol v5).
2
+ -- DATA LOSS (intentional): previously synced workdir artifacts, their per-run
3
+ -- snapshots, and every loop's configured artifact paths are dropped. Old paths
4
+ -- are not valid loop file names; orphaned blob bytes are reclaimed by the next
5
+ -- storage-maintenance pass. Run history and loop configuration are otherwise kept.
6
+ DELETE FROM "artifact_files";--> statement-breakpoint
7
+ DELETE FROM "run_snapshots";--> statement-breakpoint
8
+ UPDATE "loops" SET "artifacts" = '[]'::jsonb;--> statement-breakpoint
9
+ ALTER TABLE "runs" ADD COLUMN "file_notices" jsonb;
@@ -8,6 +8,13 @@
8
8
  "when": 1792651729223,
9
9
  "tag": "0000_baseline",
10
10
  "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "7",
15
+ "when": 1792900000000,
16
+ "tag": "0001_loop_files",
17
+ "breakpoints": true
11
18
  }
12
19
  ]
13
- }
20
+ }