@kky42/pievo-server 2.0.4 → 2.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 (60) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{index-49hAH0gP.js → index-DT_reRxT.js} +3 -3
  3. package/.output/public/assets/{invite._token-C891oGkK.js → invite._token-5zhVSA26.js} +1 -1
  4. package/.output/public/assets/{lifecycleUi-C3k2MlX8.js → lifecycleUi-CMFw5Nlj.js} +1 -1
  5. package/.output/public/assets/{loops._loopId-DD4fKGMu.js → loops._loopId-6JlPOCsY.js} +1 -1
  6. package/.output/public/assets/{loops._loopId_.runs._runId-DoPcCQy7.js → loops._loopId_.runs._runId-wFUMHN9w.js} +2 -2
  7. package/.output/public/assets/{notifyFns-BaukhLAg.js → notifyFns-CF12Yboc.js} +1 -1
  8. package/.output/public/assets/{routes-BS4N7Lnf.js → routes-WVPuW976.js} +1 -1
  9. package/.output/public/assets/{t._teamId-DSYlMX_v.js → t._teamId-BdVLnwih.js} +1 -1
  10. package/.output/server/_ssr/{DashboardView-CQdjYy03.mjs → DashboardView-DJMpoucm.mjs} +4 -4
  11. package/.output/server/_ssr/{LoopPlaybook-C86vJIjZ.mjs → LoopPlaybook-WFNer22Y.mjs} +2 -2
  12. package/.output/server/_ssr/{LoopView-cDyjmf1B.mjs → LoopView-Dsc6oik9.mjs} +2 -2
  13. package/.output/server/_ssr/{SignIn-BQQiD3Ss.mjs → SignIn-2qr-vtR5.mjs} +2 -2
  14. package/.output/server/_ssr/{adapters-N4-yQ1vK.mjs → adapters-Bwuh6uek.mjs} +2 -2
  15. package/.output/server/_ssr/{artifactFiles-Dl1EaUtJ.mjs → artifactFiles-Cp1IBHne.mjs} +3 -3
  16. package/.output/server/_ssr/artifacts-9G_Ai7vO.mjs +2 -0
  17. package/.output/server/_ssr/{auth-CbAfO4Ne.mjs → auth-uQ19WsD1.mjs} +9 -9
  18. package/.output/server/_ssr/{boot-BZ-YyUiD.mjs → boot-DPoPmSLh.mjs} +76 -164
  19. package/.output/server/_ssr/{boot-BigKgB8p.mjs → boot-Zz5AJgfy.mjs} +1 -1
  20. package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-B67XLJZt.mjs → bun-sqlite-dialect-BW9W1_Ps-CqcLCApi.mjs} +2 -2
  21. package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-nff_yHzH.mjs → d1-sqlite-dialect-BLC8LXE6-AuWb61y8.mjs} +2 -2
  22. package/.output/server/_ssr/db-BMANvbZu.mjs +2 -0
  23. package/.output/server/_ssr/{dist-BGjVt6NE.mjs → dist-CtYTvPCD.mjs} +2 -2
  24. package/.output/server/_ssr/{factory-DNeo3vVt.mjs → factory-BtqxMS8a.mjs} +2 -2
  25. package/.output/server/_ssr/{invite._token-Bipap1cl.mjs → invite._token-DBttmaDb.mjs} +4 -4
  26. package/.output/server/_ssr/{invite._token-z3PzCMzb.mjs → invite._token-DtAfQyfP.mjs} +3 -3
  27. package/.output/server/_ssr/{kysely-adapter-C1ww7PKr.mjs → kysely-adapter-bSpTlW7Z.mjs} +1 -1
  28. package/.output/server/_ssr/{lifecycleUi-5jMhxINb.mjs → lifecycleUi-Djb44Aj3.mjs} +4 -4
  29. package/.output/server/_ssr/logger-CR1a0flR.mjs +2 -0
  30. package/.output/server/_ssr/{loopApi-JzGGZZp2.mjs → loopApi-BXRBFGWh.mjs} +14 -14
  31. package/.output/server/_ssr/{loops._loopId-CJxQ0EG4.mjs → loops._loopId-6Q0DMXU0.mjs} +3 -3
  32. package/.output/server/_ssr/{loops._loopId-DFkyTJR3.mjs → loops._loopId-C0x0SE8F.mjs} +9 -9
  33. package/.output/server/_ssr/{loops._loopId_.runs._runId-lTigSOmT.mjs → loops._loopId_.runs._runId-BOJBJu_a.mjs} +3 -3
  34. package/.output/server/_ssr/{loops._loopId_.runs._runId-DkG-ZCD1.mjs → loops._loopId_.runs._runId-CkM0-ckn.mjs} +6 -6
  35. package/.output/server/_ssr/{machineFns-Dda8-rBY.mjs → machineFns-CQuvvdXx.mjs} +3 -3
  36. package/.output/server/_ssr/{node-sqlite-dialect-BS2OAFJh.mjs → node-sqlite-dialect-ZOyD6D7F.mjs} +2 -2
  37. package/.output/server/_ssr/{notifyFns-C9N0QLe3.mjs → notifyFns-BOeYZDRp.mjs} +3 -3
  38. package/.output/server/_ssr/{notifyFns-C6eyIFZE.mjs → notifyFns-UFZ2j7Fv.mjs} +4 -4
  39. package/.output/server/_ssr/{router-DIfoLu1r.mjs → router-jnPelPNh.mjs} +28 -28
  40. package/.output/server/_ssr/{routes-DYJB0rKC.mjs → routes-CMAUcUsZ.mjs} +5 -5
  41. package/.output/server/_ssr/{routes-bWgX0tRE.mjs → routes-CXnbFjB_.mjs} +4 -4
  42. package/.output/server/_ssr/runDiff-CDPvl_cY.mjs +2 -0
  43. package/.output/server/_ssr/ssr.mjs +48 -48
  44. package/.output/server/_ssr/store-DDOk2Ty_.mjs +2 -0
  45. package/.output/server/_ssr/{t._teamId-C_KZZ4Xh.mjs → t._teamId-36z-mmyw.mjs} +5 -5
  46. package/.output/server/_ssr/{t._teamId-B_ieXBNF.mjs → t._teamId-Bsm4WrJl.mjs} +4 -4
  47. package/.output/server/_ssr/{teamFns-O3ZmtZL2.mjs → teamFns-DAx4a1z4.mjs} +3 -3
  48. package/.output/server/_ssr/{tokens-DI_pklQB.mjs → tokens-7KEKpLnu.mjs} +1 -1
  49. package/.output/server/{_tanstack-start-manifest_v-DKnfwHZr.mjs → _tanstack-start-manifest_v-5iQOchGB.mjs} +16 -16
  50. package/.output/server/drizzle/0016_plural_machine_runs.sql +4 -0
  51. package/.output/server/drizzle/meta/_journal.json +7 -0
  52. package/.output/server/index.mjs +105 -105
  53. package/drizzle/0016_plural_machine_runs.sql +4 -0
  54. package/drizzle/meta/_journal.json +7 -0
  55. package/package.json +1 -1
  56. package/.output/server/_ssr/artifacts-DzWJrBxK.mjs +0 -2
  57. package/.output/server/_ssr/db-BF8vSovA.mjs +0 -2
  58. package/.output/server/_ssr/logger-C7aewtve.mjs +0 -2
  59. package/.output/server/_ssr/runDiff-B9t7ouYj.mjs +0 -2
  60. package/.output/server/_ssr/store-Dw4LiFjE.mjs +0 -2
@@ -1,4 +1,4 @@
1
- //#region node_modules/.nitro/vite/services/ssr/assets/lifecycleUi-5jMhxINb.js
1
+ //#region node_modules/.nitro/vite/services/ssr/assets/lifecycleUi-Djb44Aj3.js
2
2
  var DAEMON_UPGRADE_REQUIRED = "Daemon upgrade required to stop a running process. Run `npm install -g @kky42/pievo@latest`, then `pievo daemon restart`.";
3
3
  /** Derive product lifecycle state only from durable server facts. */
4
4
  function deriveLoopLifecycle(job) {
@@ -10,9 +10,9 @@ function deriveLoopLifecycle(job) {
10
10
  return "active";
11
11
  }
12
12
  function daemonStopSupport(protocol) {
13
- return protocol === 2 ? {
13
+ return protocol === 3 ? {
14
14
  supported: true,
15
- label: `Daemon protocol 2 · Stop supported`
15
+ label: `Daemon protocol 3 · Stop supported`
16
16
  } : {
17
17
  supported: false,
18
18
  label: `Daemon protocol ${protocol ?? "unknown"} · upgrade required`
@@ -22,7 +22,7 @@ function daemonStopSupport(protocol) {
22
22
  function lifecycleDisplay(detail) {
23
23
  const state = deriveLoopLifecycle(detail.summary);
24
24
  const running = detail.summary.runs.find((run) => run.running);
25
- if (running && detail.machine.daemonProtocol !== 2) return DAEMON_UPGRADE_REQUIRED;
25
+ if (running && detail.machine.daemonProtocol !== 3) return DAEMON_UPGRADE_REQUIRED;
26
26
  if (state === "stopping" && running && !detail.machine.online) return `Stopping · waiting for ${detail.machine.name || "machine"}`;
27
27
  switch (state) {
28
28
  case "deleting": return "Deleting";
@@ -0,0 +1,2 @@
1
+ import { kt as logger } from "./boot-DPoPmSLh.mjs";
2
+ export { logger };
@@ -1,9 +1,9 @@
1
- import { $ as getMachine, $t as tryDeleteLoop, Et as listRunsBefore, It as normalizeProviderSetting, K as getChannel, L as ensureServer, Lt as pauseLoop, Nt as machinePresence, Ot as listTeamsForUser, Q as getLoop, Ut as requestDeleteLoop, V as forceDeleteLoop, Wt as requestRunCancel, Xt as stopLoop, Yt as startLoop, _ as canEvolve, b as coerceUi, en as updateLoop, in as validateSteerInstruction, it as getTeamMember, nt as getRun, ot as hasRunningRun, rn as validateSchema, rt as getTeam, xt as listLoops, y as coerceCodingAgent } from "./boot-BZ-YyUiD.mjs";
1
+ import { $ as getMachine, $t as tryDeleteLoop, Et as listRunsBefore, It as normalizeProviderSetting, K as getChannel, L as ensureServer, Lt as pauseLoop, Nt as machinePresence, Ot as listTeamsForUser, Q as getLoop, Ut as requestDeleteLoop, V as forceDeleteLoop, Wt as requestRunCancel, Xt as stopLoop, Yt as startLoop, _ as canEvolve, b as coerceUi, en as updateLoop, in as validateSteerInstruction, it as getTeamMember, nt as getRun, ot as hasRunningRun, rn as validateSchema, rt as getTeam, xt as listLoops, y as coerceCodingAgent } from "./boot-DPoPmSLh.mjs";
2
2
  import { n as createServerFn } from "./ssr.mjs";
3
- import { i as toRunSummary, n as toJobDetail, r as toJobSummary } from "./adapters-N4-yQ1vK.mjs";
4
- import { canAccessLoop, requestScope } from "./auth-CbAfO4Ne.mjs";
3
+ import { i as toRunSummary, n as toJobDetail, r as toJobSummary } from "./adapters-Bwuh6uek.mjs";
4
+ import { canAccessLoop, requestScope } from "./auth-uQ19WsD1.mjs";
5
5
  import { t as createServerRpc } from "./createServerRpc-BD8Xn_0_.mjs";
6
- //#region node_modules/.nitro/vite/services/ssr/assets/loopApi-JzGGZZp2.js
6
+ //#region node_modules/.nitro/vite/services/ssr/assets/loopApi-BXRBFGWh.js
7
7
  var meta_default$6 = {
8
8
  name: "dependency-triage",
9
9
  label: "Dependency Triage",
@@ -135,7 +135,7 @@ var getAuthState_createServerFn_handler = createServerRpc({
135
135
  filename: "src/server/loopApi.ts"
136
136
  }, (opts) => getAuthState.__executeServer(opts));
137
137
  var getAuthState = createServerFn({ method: "GET" }).handler(getAuthState_createServerFn_handler, async () => {
138
- const { authEnabled } = await import("./auth-CbAfO4Ne.mjs");
138
+ const { authEnabled } = await import("./auth-uQ19WsD1.mjs");
139
139
  return { enabled: authEnabled };
140
140
  });
141
141
  var getConfig_createServerFn_handler = createServerRpc({
@@ -244,7 +244,7 @@ var getArtifacts_createServerFn_handler = createServerRpc({
244
244
  var getArtifacts = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifacts_createServerFn_handler, async ({ data }) => {
245
245
  await backend();
246
246
  if (!await ownedLoop(data.loopId)) return [];
247
- const { listLoopArtifacts } = await import("./artifactFiles-Dl1EaUtJ.mjs");
247
+ const { listLoopArtifacts } = await import("./artifactFiles-Cp1IBHne.mjs");
248
248
  return listLoopArtifacts(data.loopId);
249
249
  });
250
250
  var getArtifact_createServerFn_handler = createServerRpc({
@@ -255,7 +255,7 @@ var getArtifact_createServerFn_handler = createServerRpc({
255
255
  var getArtifact = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifact_createServerFn_handler, async ({ data }) => {
256
256
  await backend();
257
257
  if (!await ownedLoop(data.loopId)) return { error: "file not found" };
258
- const { readLoopArtifact } = await import("./artifactFiles-Dl1EaUtJ.mjs");
258
+ const { readLoopArtifact } = await import("./artifactFiles-Cp1IBHne.mjs");
259
259
  return readLoopArtifact(data.loopId, data.path);
260
260
  });
261
261
  var getRunDiff_createServerFn_handler = createServerRpc({
@@ -274,7 +274,7 @@ var getRunDiff = createServerFn({ method: "GET" }).validator((d) => d).handler(g
274
274
  hasSnapshot: false,
275
275
  files: []
276
276
  };
277
- const { computeRunDiff } = await import("./runDiff-B9t7ouYj.mjs");
277
+ const { computeRunDiff } = await import("./runDiff-CDPvl_cY.mjs");
278
278
  return computeRunDiff(data.runId);
279
279
  });
280
280
  var listTemplates_createServerFn_handler = createServerRpc({
@@ -367,7 +367,7 @@ var stopJob = createServerFn({ method: "POST" }).validator((id) => id).handler(s
367
367
  const owned = await ownedLoop(id);
368
368
  if (!owned) return { error: "not found" };
369
369
  if (await hasRunningRun(id)) {
370
- if ((await getMachine(owned.loop.machineId))?.daemonProtocol !== 2) return { error: "Daemon upgrade required to stop a running process" };
370
+ if ((await getMachine(owned.loop.machineId))?.daemonProtocol !== 3) return { error: "Daemon upgrade required to stop a running process" };
371
371
  }
372
372
  const stopped = await stopLoop(id);
373
373
  if (!stopped) return { error: "not found" };
@@ -390,12 +390,12 @@ var deleteJob = createServerFn({ method: "POST" }).validator((id) => id).handler
390
390
  const unreachable = machinePresence(machine?.online, machine?.lastSeen) !== "online";
391
391
  const actor = await requestScope();
392
392
  const mayRetireAuthority = !owned.enforce || !!(actor.userId && owned.loop.teamId && (await getTeamMember(owned.loop.teamId, actor.userId))?.role === "owner");
393
- if (!unreachable && await hasRunningRun(id) && machine?.daemonProtocol !== 2) return { error: "Daemon upgrade required to stop a running process" };
393
+ if (!unreachable && await hasRunningRun(id) && machine?.daemonProtocol !== 3) return { error: "Daemon upgrade required to stop a running process" };
394
394
  scheduler.removeLoop(id);
395
395
  if (!await requestDeleteLoop(id)) return { error: "not found" };
396
396
  if (unreachable && mayRetireAuthority) {
397
397
  if (!await forceDeleteLoop(id)) return { error: "delete failed; server data was not deleted" };
398
- const { logger } = await import("./logger-C7aewtve.mjs");
398
+ const { logger } = await import("./logger-CR1a0flR.mjs");
399
399
  logger.child({ mod: "loop-lifecycle" }).warn({
400
400
  action: "unreachable-delete",
401
401
  loopId: id,
@@ -435,7 +435,7 @@ var forceDeleteJob = createServerFn({ method: "POST" }).validator((d) => d).hand
435
435
  }
436
436
  scheduler.removeLoop(data.id);
437
437
  if (!await forceDeleteLoop(data.id)) return { error: "force delete failed; server data was not deleted" };
438
- const { logger } = await import("./logger-C7aewtve.mjs");
438
+ const { logger } = await import("./logger-CR1a0flR.mjs");
439
439
  logger.child({ mod: "loop-lifecycle" }).warn({
440
440
  action: "force-delete",
441
441
  loopId: data.id,
@@ -512,7 +512,7 @@ var stopRun = createServerFn({ method: "POST" }).validator((id) => id).handler(s
512
512
  const run = await getRun(id);
513
513
  const owned = run ? await ownedLoop(run.loopId) : void 0;
514
514
  if (!run || !owned) return { error: "run not found" };
515
- if (run.phase === "running" && (await getMachine(owned.loop.machineId))?.daemonProtocol !== 2) return { error: "Daemon upgrade required to stop a running process" };
515
+ if (run.phase === "running" && (await getMachine(owned.loop.machineId))?.daemonProtocol !== 3) return { error: "Daemon upgrade required to stop a running process" };
516
516
  const result = await requestRunCancel(run.loopId, id);
517
517
  return result ? {
518
518
  ok: true,
@@ -526,7 +526,7 @@ var mintClaim_createServerFn_handler = createServerRpc({
526
526
  }, (opts) => mintClaim.__executeServer(opts));
527
527
  var mintClaim = createServerFn({ method: "POST" }).validator((teamId) => teamId).handler(mintClaim_createServerFn_handler, async ({ data: teamId }) => {
528
528
  await backend();
529
- const { mintDeviceToken, rememberConnectKey } = await import("./tokens-DI_pklQB.mjs");
529
+ const { mintDeviceToken, rememberConnectKey } = await import("./tokens-7KEKpLnu.mjs");
530
530
  const { userId, teamId: active } = await requestScope(teamId);
531
531
  const owner = userId ?? "shared";
532
532
  const token = mintDeviceToken();
@@ -1,8 +1,8 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
2
  import { c as getAuthState } from "./loopApi-7MTSs6hy.mjs";
3
- import { a as authClient } from "./LoopPlaybook-C86vJIjZ.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-CJxQ0EG4.js
5
- var $$splitComponentImporter = () => import("./loops._loopId-DFkyTJR3.mjs");
3
+ import { a as authClient } from "./LoopPlaybook-WFNer22Y.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-6Q0DMXU0.js
5
+ var $$splitComponentImporter = () => import("./loops._loopId-C0x0SE8F.mjs");
6
6
  /**
7
7
  * Loop detail PAGE — `/loops/$loopId`. The dedicated page that replaced the old
8
8
  * dashboard modal: a loop header + action toolbar, the unified Files panel (task
@@ -1,18 +1,18 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/react+[...].mjs";
3
- import { c as CODING_AGENTS, g as buildFileEntries, mt as isTaskEntry } from "./boot-BZ-YyUiD.mjs";
3
+ import { c as CODING_AGENTS, g as buildFileEntries, mt as isTaskEntry } from "./boot-DPoPmSLh.mjs";
4
4
  import { A as tsShort, D as runPulseStyle, O as sectionHeadCls, S as labelCls, T as rel, _ as dur, b as humanBytes, c as btnDanger, d as btnQuiet, h as dotLabel, i as Pre, j as until, k as selectCls, l as btnPrimary, m as dotColor, n as Loading, o as btn, p as cronText, r as Pill, s as btnCost, t as ErrorBanner, v as fmt, x as inputCls } from "./ui-B6mE5-5v.mjs";
5
5
  import { d as useNavigate, u as Link } from "../_libs/@tanstack/react-router+[...].mjs";
6
6
  import { C as stopJob, S as startJob, a as evolveJob, b as requestSteer, d as getJobDetail, g as loadOlderRuns, i as deleteJob, s as getArtifacts, v as patchJob, x as runJob, y as pauseJob } from "./loopApi-7MTSs6hy.mjs";
7
7
  import { n as TaskFileView, r as ViewerHead, t as ArtifactBody } from "./artifactView-DX4P3Krh.mjs";
8
- import { s as useSession } from "./LoopPlaybook-C86vJIjZ.mjs";
9
- import { t as setActiveTeamCookie } from "./teamCookie-B7hLOIie.mjs";
10
- import { t as SignIn } from "./SignIn-BQQiD3Ss.mjs";
11
8
  import { i as useFlash, n as FlashLine, r as LoadErrorCard, t as ConfirmBar } from "./actionUi-BKF6xI3d.mjs";
12
- import { i as lifecycleDisplay, n as daemonStopSupport, r as deriveLoopLifecycle, t as DAEMON_UPGRADE_REQUIRED } from "./lifecycleUi-5jMhxINb.mjs";
13
- import { a as listChannels, n as Timeline, s as mergeRuns, t as MachinesModal } from "./notifyFns-C6eyIFZE.mjs";
14
- import { t as Route } from "./loops._loopId-CJxQ0EG4.mjs";
15
- //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-DFkyTJR3.js
9
+ import { s as useSession } from "./LoopPlaybook-WFNer22Y.mjs";
10
+ import { t as setActiveTeamCookie } from "./teamCookie-B7hLOIie.mjs";
11
+ import { t as SignIn } from "./SignIn-2qr-vtR5.mjs";
12
+ import { i as lifecycleDisplay, n as daemonStopSupport, r as deriveLoopLifecycle, t as DAEMON_UPGRADE_REQUIRED } from "./lifecycleUi-Djb44Aj3.mjs";
13
+ import { a as listChannels, n as Timeline, s as mergeRuns, t as MachinesModal } from "./notifyFns-UFZ2j7Fv.mjs";
14
+ import { t as Route } from "./loops._loopId-6Q0DMXU0.mjs";
15
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-C0x0SE8F.js
16
16
  var import_react = /* @__PURE__ */ __toESM(require_react());
17
17
  var import_jsx_runtime = require_jsx_runtime();
18
18
  /**
@@ -556,7 +556,7 @@ var STEER_SEEDS = [
556
556
  seed: "Give this loop a standing objective to optimize toward: "
557
557
  }
558
558
  ];
559
- var LoopView = (0, import_react.lazy)(() => import("./LoopView-cDyjmf1B.mjs").then((m) => ({ default: m.LoopView })));
559
+ var LoopView = (0, import_react.lazy)(() => import("./LoopView-Dsc6oik9.mjs").then((m) => ({ default: m.LoopView })));
560
560
  /**
561
561
  * Loop detail PAGE body (`/loops/$loopId`) — the redesign of the former modal.
562
562
  * One scrolling page: a loop header (name / status / schedule / agent / machine +
@@ -1,8 +1,8 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
2
  import { c as getAuthState } from "./loopApi-7MTSs6hy.mjs";
3
- import { a as authClient } from "./LoopPlaybook-C86vJIjZ.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId_.runs._runId-lTigSOmT.js
5
- var $$splitComponentImporter = () => import("./loops._loopId_.runs._runId-DkG-ZCD1.mjs");
3
+ import { a as authClient } from "./LoopPlaybook-WFNer22Y.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId_.runs._runId-BOJBJu_a.js
5
+ var $$splitComponentImporter = () => import("./loops._loopId_.runs._runId-CkM0-ckn.mjs");
6
6
  /**
7
7
  * Run detail PAGE — `/loops/$loopId/runs/$runId`. A standalone page (the trailing
8
8
  * `_` on the `$loopId` segment opts it out of the loop page's component so the run
@@ -3,11 +3,11 @@ import { g as require_jsx_runtime, h as require_react } from "../_libs/@base-ui/
3
3
  import { D as runPulseStyle, O as sectionHeadCls, _ as dur, a as StatusPill, b as humanBytes, c as btnDanger, n as Loading, o as btn, r as Pill, v as fmt, y as fnum } from "./ui-B6mE5-5v.mjs";
4
4
  import { u as Link } from "../_libs/@tanstack/react-router+[...].mjs";
5
5
  import { d as getJobDetail, f as getRunDiff, g as loadOlderRuns, w as stopRun } from "./loopApi-7MTSs6hy.mjs";
6
- import { s as useSession } from "./LoopPlaybook-C86vJIjZ.mjs";
7
- import { t as SignIn } from "./SignIn-BQQiD3Ss.mjs";
8
6
  import { r as LoadErrorCard } from "./actionUi-BKF6xI3d.mjs";
9
- import { t as Route } from "./loops._loopId_.runs._runId-lTigSOmT.mjs";
10
- //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId_.runs._runId-DkG-ZCD1.js
7
+ import { s as useSession } from "./LoopPlaybook-WFNer22Y.mjs";
8
+ import { t as SignIn } from "./SignIn-2qr-vtR5.mjs";
9
+ import { t as Route } from "./loops._loopId_.runs._runId-BOJBJu_a.mjs";
10
+ //#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId_.runs._runId-CkM0-ckn.js
11
11
  var import_react = /* @__PURE__ */ __toESM(require_react());
12
12
  var import_jsx_runtime = require_jsx_runtime();
13
13
  /**
@@ -504,8 +504,8 @@ function RunDetailView({ loopId, runId }) {
504
504
  type: "button",
505
505
  onClick: onStop,
506
506
  className: btnDanger,
507
- disabled: !!run.running && detail.machine.daemonProtocol !== 2,
508
- title: run.running && detail.machine.daemonProtocol !== 2 ? "Daemon upgrade required to stop a running process. Run `npm install -g @kky42/pievo@latest`, then `pievo daemon restart`." : void 0,
507
+ disabled: !!run.running && detail.machine.daemonProtocol !== 3,
508
+ title: run.running && detail.machine.daemonProtocol !== 3 ? "Daemon upgrade required to stop a running process. Run `npm install -g @kky42/pievo@latest`, then `pievo daemon restart`." : void 0,
509
509
  children: "Stop run"
510
510
  })]
511
511
  })]
@@ -1,6 +1,6 @@
1
- import { $ as getMachine, A as daemonNeedsUpdate, Bt as rememberConnectKey, Ct as listMachinesForTeam, F as deleteMachine$1, Jt as sha256, L as ensureServer, Mt as machineIdFromToken, O as createMachine$1, Pt as mintDeviceToken, St as listMachines$1, d as MIN_DAEMON_VERSION, jt as loopsForMachine, tn as updateMachine } from "./boot-BZ-YyUiD.mjs";
1
+ import { $ as getMachine, A as daemonNeedsUpdate, Bt as rememberConnectKey, Ct as listMachinesForTeam, F as deleteMachine$1, Jt as sha256, L as ensureServer, Mt as machineIdFromToken, O as createMachine$1, Pt as mintDeviceToken, St as listMachines$1, d as MIN_DAEMON_VERSION, jt as loopsForMachine, tn as updateMachine } from "./boot-DPoPmSLh.mjs";
2
2
  import { n as createServerFn } from "./ssr.mjs";
3
- import { requestScope } from "./auth-CbAfO4Ne.mjs";
3
+ import { requestScope } from "./auth-uQ19WsD1.mjs";
4
4
  import { t as createServerRpc } from "./createServerRpc-BD8Xn_0_.mjs";
5
5
  //#region node_modules/.nitro/vite/services/ssr/assets/machineScope-2h-fcKmG.js
6
6
  /**
@@ -28,7 +28,7 @@ function tokenVisibleTo(m, scope) {
28
28
  return !scope.enforce || m.userId === scope.userId;
29
29
  }
30
30
  //#endregion
31
- //#region node_modules/.nitro/vite/services/ssr/assets/machineFns-Dda8-rBY.js
31
+ //#region node_modules/.nitro/vite/services/ssr/assets/machineFns-CQuvvdXx.js
32
32
  /**
33
33
  * Latest published @kky42/pievo version — a cached, fail-silent lookup of the
34
34
  * npm dist-tag `latest`, so the web can tell a user their daemon is outdated and
@@ -1,6 +1,6 @@
1
- import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-CbAfO4Ne.mjs";
1
+ import { n as DefaultQueryCompiler, o as CompiledQuery, s as sql$1 } from "./auth-uQ19WsD1.mjs";
2
2
  import { n as DEFAULT_MIGRATION_TABLE, t as DEFAULT_MIGRATION_LOCK_TABLE } from "./kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/node-sqlite-dialect-BS2OAFJh.js
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/node-sqlite-dialect-ZOyD6D7F.js
4
4
  var NodeSqliteAdapter = class {
5
5
  get supportsCreateIfNotExists() {
6
6
  return true;
@@ -1,8 +1,8 @@
1
- import { K as getChannel, L as ensureServer, N as deleteChannel$1, bt as listChannels$1, s as CHANNELS, w as createChannel$1 } from "./boot-BZ-YyUiD.mjs";
1
+ import { K as getChannel, L as ensureServer, N as deleteChannel$1, bt as listChannels$1, s as CHANNELS, w as createChannel$1 } from "./boot-DPoPmSLh.mjs";
2
2
  import { n as createServerFn } from "./ssr.mjs";
3
- import { requestScope } from "./auth-CbAfO4Ne.mjs";
3
+ import { requestScope } from "./auth-uQ19WsD1.mjs";
4
4
  import { t as createServerRpc } from "./createServerRpc-BD8Xn_0_.mjs";
5
- //#region node_modules/.nitro/vite/services/ssr/assets/notifyFns-C9N0QLe3.js
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/notifyFns-BOeYZDRp.js
6
6
  /**
7
7
  * Notification-channel server functions. Channels are per-team push targets a
8
8
  * loop can route its run messages to. Secrets (bot token / chat id) live in the
@@ -1,12 +1,12 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { a as TooltipTrigger, g as require_jsx_runtime, h as require_react, i as TooltipPortal, n as TooltipPopup, o as TooltipRoot, r as TooltipPositioner } from "../_libs/@base-ui/react+[...].mjs";
3
- import { Nt as machinePresence, lt as isOutdated } from "./boot-BZ-YyUiD.mjs";
3
+ import { Nt as machinePresence, lt as isOutdated } from "./boot-DPoPmSLh.mjs";
4
4
  import { E as runPulseAnim, M as useHydrated, S as labelCls, T as rel, _ as dur, c as btnDanger, g as dotOpacity, h as dotLabel, j as until, l as btnPrimary, m as dotColor, o as btn, t as ErrorBanner, v as fmt, x as inputCls } from "./ui-B6mE5-5v.mjs";
5
5
  import { n as createServerFn } from "./ssr.mjs";
6
6
  import { l as getConfig, r as createSsrRpc } from "./loopApi-7MTSs6hy.mjs";
7
7
  import { n as ModalHead, r as ModalSection, t as Modal } from "./Modal-Bc_5TYGr.mjs";
8
- import { n as daemonStopSupport } from "./lifecycleUi-5jMhxINb.mjs";
9
- //#region node_modules/.nitro/vite/services/ssr/assets/notifyFns-C6eyIFZE.js
8
+ import { n as daemonStopSupport } from "./lifecycleUi-Djb44Aj3.mjs";
9
+ //#region node_modules/.nitro/vite/services/ssr/assets/notifyFns-UFZ2j7Fv.js
10
10
  var import_react = /* @__PURE__ */ __toESM(require_react());
11
11
  var import_jsx_runtime = require_jsx_runtime();
12
12
  /**
@@ -457,7 +457,7 @@ function MachinesModal({ open, onClose, teamId }) {
457
457
  className: "text-label text-secondary",
458
458
  children: daemonStopSupport(m.daemonProtocol).label
459
459
  }),
460
- m.daemonProtocol !== 2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
460
+ !daemonStopSupport(m.daemonProtocol).supported && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
461
461
  className: "text-label text-accent",
462
462
  children: "Daemon upgrade required to stop a running process"
463
463
  }),
@@ -1,14 +1,14 @@
1
1
  import { A as sql } from "../_libs/drizzle-orm+postgres.mjs";
2
2
  import { g as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- import { B as evolve_default, L as ensureServer, Rt as readJsonBody, u as MACHINE_BODY_CAP } from "./boot-BZ-YyUiD.mjs";
3
+ import { B as evolve_default, L as ensureServer, Rt as readJsonBody, u as MACHINE_BODY_CAP } from "./boot-DPoPmSLh.mjs";
4
4
  import { c as createFileRoute, i as HeadContent, l as createRootRoute, o as createRouter, r as Scripts } from "../_libs/@tanstack/react-router+[...].mjs";
5
5
  import { n as imageMime } from "./artifactKind-BW0isV8L.mjs";
6
- import { t as Route$17 } from "./invite._token-z3PzCMzb.mjs";
7
- import { t as Route$18 } from "./loops._loopId-CJxQ0EG4.mjs";
8
- import { t as Route$19 } from "./loops._loopId_.runs._runId-lTigSOmT.mjs";
9
- import { t as Route$20 } from "./routes-bWgX0tRE.mjs";
10
- import { t as Route$21 } from "./t._teamId-B_ieXBNF.mjs";
11
- //#region node_modules/.nitro/vite/services/ssr/assets/router-DIfoLu1r.js
6
+ import { t as Route$17 } from "./invite._token-DtAfQyfP.mjs";
7
+ import { t as Route$18 } from "./loops._loopId-6Q0DMXU0.mjs";
8
+ import { t as Route$19 } from "./loops._loopId_.runs._runId-BOJBJu_a.mjs";
9
+ import { t as Route$20 } from "./routes-CXnbFjB_.mjs";
10
+ import { t as Route$21 } from "./t._teamId-Bsm4WrJl.mjs";
11
+ //#region node_modules/.nitro/vite/services/ssr/assets/router-jnPelPNh.js
12
12
  var import_jsx_runtime = require_jsx_runtime();
13
13
  var app_default = "/assets/app-CStTBRt2.css";
14
14
  var Route$16 = createRootRoute({
@@ -176,7 +176,7 @@ var Route$15 = createFileRoute("/machine/report")({ server: { handlers: { POST:
176
176
  const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
177
177
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
178
178
  const body = parsed.kind === "ok" && parsed.body && typeof parsed.body === "object" ? parsed.body : {};
179
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
179
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
180
180
  const r = await (await getGateway()).report(token, body);
181
181
  return Response.json(r.body, { status: r.status });
182
182
  } } } });
@@ -223,7 +223,7 @@ var Route$11 = createFileRoute("/agent-api/loop")({ server: { handlers: { POST:
223
223
  exitCode: 1
224
224
  }, { status: 413 });
225
225
  const body = parsed.kind === "ok" ? parsed.body : {};
226
- const { getCliGateway } = await import("./boot-BigKgB8p.mjs");
226
+ const { getCliGateway } = await import("./boot-Zz5AJgfy.mjs");
227
227
  const r = await (await getCliGateway()).agentApi(token, Array.isArray(body.argv) ? body.argv : []);
228
228
  return Response.json(r.body, { status: r.status });
229
229
  } } } });
@@ -242,11 +242,11 @@ var Route$10 = createFileRoute("/api/machine/sync")({ server: { handlers: { POST
242
242
  const auth = request.headers.get("authorization") ?? "";
243
243
  const token = auth.startsWith("Bearer ") ? auth.slice(7) : "";
244
244
  if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
245
- const { SYNC_BODY_CAP } = await import("./artifacts-DzWJrBxK.mjs");
245
+ const { SYNC_BODY_CAP } = await import("./artifacts-9G_Ai7vO.mjs");
246
246
  const parsed = await readJsonBody(request, SYNC_BODY_CAP);
247
247
  if (parsed.kind === "too-large") return Response.json({ error: "sync body too large" }, { status: 413 });
248
248
  if (parsed.kind === "invalid") return Response.json({ error: "invalid JSON" }, { status: 400 });
249
- const { getArtifactSync } = await import("./boot-BigKgB8p.mjs");
249
+ const { getArtifactSync } = await import("./boot-Zz5AJgfy.mjs");
250
250
  const r = await (await getArtifactSync()).sync(token, parsed.body);
251
251
  return Response.json(r.body, { status: r.status });
252
252
  } } } });
@@ -257,7 +257,7 @@ var Route$9 = createFileRoute("/api/machine/status")({ server: { handlers: { GET
257
257
  const limited = machineRouteLimit(request, token || void 0);
258
258
  if (limited) return limited;
259
259
  if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
260
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
260
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
261
261
  const r = await (await getGateway()).status(token);
262
262
  return Response.json(r.body, { status: r.status });
263
263
  } } } });
@@ -271,10 +271,10 @@ var Route$8 = createFileRoute("/api/machine/poll")({ server: { handlers: { POST:
271
271
  const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
272
272
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
273
273
  const body = parsed.kind === "ok" ? parsed.body : {};
274
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
275
- const r = await (await getGateway()).pollV2Wait(token, {
274
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
275
+ const r = await (await getGateway()).pollV3Wait(token, {
276
276
  protocolVersion: body.protocolVersion,
277
- currentRun: body.currentRun,
277
+ currentRuns: body.currentRuns,
278
278
  watchDigest: typeof body.watchDigest === "string" ? body.watchDigest : void 0,
279
279
  info: body
280
280
  });
@@ -300,7 +300,7 @@ var Route$7 = createFileRoute("/api/machine/loop")({ server: { handlers: {
300
300
  const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
301
301
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
302
302
  const body = parsed.kind === "ok" ? parsed.body : {};
303
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
303
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
304
304
  const r = await (await getGateway()).createLoop(token, body);
305
305
  return Response.json(r.body, { status: r.status });
306
306
  },
@@ -309,7 +309,7 @@ var Route$7 = createFileRoute("/api/machine/loop")({ server: { handlers: {
309
309
  const limited = machineRouteLimit(request, token || void 0);
310
310
  if (limited) return limited;
311
311
  if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
312
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
312
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
313
313
  const r = await (await getGateway()).listLoops(token);
314
314
  return Response.json(r.body, { status: r.status });
315
315
  },
@@ -321,7 +321,7 @@ var Route$7 = createFileRoute("/api/machine/loop")({ server: { handlers: {
321
321
  const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
322
322
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
323
323
  const body = parsed.kind === "ok" ? parsed.body : {};
324
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
324
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
325
325
  const r = await (await getGateway()).editLoop(token, body.id, body.patch ?? {}, body.dryRun === true);
326
326
  return Response.json(r.body, { status: r.status });
327
327
  }
@@ -337,7 +337,7 @@ var Route$6 = createFileRoute("/api/machine/log")({ server: { handlers: { GET: a
337
337
  const url = new URL(request.url);
338
338
  const loopId = url.searchParams.get("loopId") ?? "";
339
339
  const limit = url.searchParams.get("limit") ?? void 0;
340
- const { getGateway } = await import("./boot-BigKgB8p.mjs");
340
+ const { getGateway } = await import("./boot-Zz5AJgfy.mjs");
341
341
  const r = await (await getGateway()).loopLog(token, loopId, limit);
342
342
  return Response.json(r.body, { status: r.status });
343
343
  } } } });
@@ -360,7 +360,7 @@ var Route$5 = createFileRoute("/api/machine/cli")({ server: { handlers: { POST:
360
360
  const parsed = await readJsonBody(request, MACHINE_BODY_CAP);
361
361
  if (parsed.kind === "too-large") return Response.json({ error: "body too large" }, { status: 413 });
362
362
  const body = parsed.kind === "ok" ? parsed.body : {};
363
- const { getCliGateway } = await import("./boot-BigKgB8p.mjs");
363
+ const { getCliGateway } = await import("./boot-Zz5AJgfy.mjs");
364
364
  const r = await (await getCliGateway()).cli(token, Array.isArray(body.argv) ? body.argv : []);
365
365
  return Response.json(r.body, { status: r.status });
366
366
  } } } });
@@ -389,7 +389,7 @@ var Route$5 = createFileRoute("/api/machine/cli")({ server: { handlers: { POST:
389
389
  var PROBE_TIMEOUT_MS = 5e3;
390
390
  var Route$4 = createFileRoute("/api/health/db")({ server: { handlers: { GET: async () => {
391
391
  try {
392
- const { db } = await import("./db-BF8vSovA.mjs");
392
+ const { db } = await import("./db-BMANvbZu.mjs");
393
393
  const ping = db.execute(sql`select 1`);
394
394
  const timeout = new Promise((_, reject) => {
395
395
  setTimeout(() => reject(/* @__PURE__ */ new Error(`db ping timed out after ${PROBE_TIMEOUT_MS}ms`)), PROBE_TIMEOUT_MS).unref?.();
@@ -409,8 +409,8 @@ var Route$4 = createFileRoute("/api/health/db")({ server: { handlers: { GET: asy
409
409
  } } } });
410
410
  /** Better Auth handler — GET/POST /api/auth/* (OAuth callbacks, session, sign-out). */
411
411
  var Route$3 = createFileRoute("/api/auth/$")({ server: { handlers: {
412
- GET: async ({ request }) => (await import("./auth-CbAfO4Ne.mjs")).auth.handler(request),
413
- POST: async ({ request }) => (await import("./auth-CbAfO4Ne.mjs")).auth.handler(request)
412
+ GET: async ({ request }) => (await import("./auth-uQ19WsD1.mjs")).auth.handler(request),
413
+ POST: async ({ request }) => (await import("./auth-uQ19WsD1.mjs")).auth.handler(request)
414
414
  } } });
415
415
  var REFERENCES = {
416
416
  "create.md": "# Create a loop\n\nThis machine is already connected — `pievo daemon start` on first capture (see `bootstrap.md`) or the daemon that's been running since. Decide what to build, author it, create it. Use the **pievo-cli** prefix the user pasted (default `pievo`) and, on the first-capture path, the **connect-key** from the capture snippet.\n\n## 1 · Decide what to build\n\nA loop only makes sense with a real task behind it. Read the session you're in and pick the starting point:\n\n- **The user already did a clear task this session**: turn that task into the loop, grounded in the real URLs, paths, commands, and thresholds from the session.\n- **The capture snippet carries a task description**: that description is the intent. Build exactly that loop, grounded in this project's real paths and commands, and confirm anything it leaves open.\n- **There's no task yet**: don't invent a loop. Inspect what this project is, propose a few concrete loops that would be useful FOR IT, and let the user pick.\n\nOnly continue once there's a real intent.\n\n## 2 · Settle cadence, output, and the objective\n\nNever silently guess how often the loop runs or what each run produces: propose → confirm → build. Propose sensible defaults for this specific task, in one short message, and get a yes or adjustment before creating.\n\n- **Cadence.** Choose **cron** for wall-clock work (for example, every day at 9am your time, every hour, or Monday morning) or **continuous** when the next exec should become ready a fixed number of minutes after the previous exec ends. Continuous delay is at least 1 minute.\n- **Per-run output.** Propose the concrete artifact or message format, e.g. a short markdown summary in `report.md`, a dated markdown product, or a one-line status.\n- **Cheap checks**: if the loop needs a cheap deterministic check, put it in the task file SOP. The exec agent runs the check first; if nothing changed, it reports `no-change` and stops.\n- **Markdown products**: if runs write markdown products, choose a small fixed `type:` vocabulary up front and use flat front matter (`type:`, `title:`, `date:`) so dashboard primitives can index them.\n- **Standing objective — when useful**: optimization tasks may get a one-line `goal` that guides every run. It never stops the loop; all loops run until the owner pauses or deletes them.\n\n## 3 · Create README.md and COOKBOOK.md\n\nEvery loop gets its own folder under the project: `<project>/pievo/<slug>/`. It contains the authoritative standing instructions, bounded learned context, and lightweight products.\n\nThis folder is a synced content home, not a scratch workspace. Heavy work products — repo checkouts, git worktrees, `node_modules`, build output, caches — must live outside the loop folder. Write only finished reports/artifacts back into the loop folder.\n\nWrite `<project>/pievo/<slug>/README.md` with standing instructions only. It has one required section:\n\n```markdown\n# <Loop name>\n\n## Spec\n<What this loop checks or does and why; its concrete SOP, commands, endpoints, files, output and notification rules, cheap early checks, and product conventions. State mode: maintenance|optimization|mixed when that distinction helps interpret no-change evidence.>\n```\n\nWrite its sibling `<project>/pievo/<slug>/COOKBOOK.md` exactly as the initial bounded learned-context shell:\n\n```markdown\n# Cookbook\nConsolidated through: #0\n\n## Knowledge\n\n## Timeline\n```\n\nKnowledge will hold durable facts plus reusable positive and negative lessons. Timeline is reserved for evolve/steer decision boundaries, never one entry per exec. Keep the absolute path to `README.md`; it goes in config as `taskFile`. The Cookbook path is inferred beside it and is not a config field.\n\n## 4 · Author the loop config\n\nA loop uses `scheduleMode: \"cron\" | \"continuous\"`. Cron fires at wall-clock occurrences. Continuous enqueues its next exec only after an exec ends (`done` or `error`) plus `continuousDelayMinutes`; canceled runs, paused loops, and steer/evolve runs do not continue it.\n\nAuthor the config inline and pass it to `pievo new --json`:\n\n```json\n{\n \"name\": \"short human name\",\n \"cron\": \"m h dom mon dow\",\n \"scheduleMode\": \"cron\",\n \"continuousDelayMinutes\": 1,\n \"goal\": \"<optional one-line standing objective>\",\n \"workdir\": \"<absolute project dir>\",\n \"taskFile\": \"<absolute path to the task file above>\",\n \"model\": \"<optional coding-agent model id>\",\n \"reasoningEffort\": \"<optional provider effort value>\",\n \"metricSchema\": [{ \"key\": \"x\", \"label\": \"X\", \"unit\": \"\" }],\n \"ui\": \"<small dashboard HTML — optional>\",\n \"notify\": \"auto\"\n}\n```\n\nRules:\n\n- Include `taskFile`. There is no `task` field; the agent's standing brief is the task file. Its parent directory becomes the synced **loop content home** for Cookbook, reports, dashboard UI, and small artifacts.\n- Set `workdir` to the absolute project directory when the loop should run in that project. This is the provider's **execution workspace (cwd)**, not the artifact root; it can differ from the loop content home.\n- `scheduleMode` defaults to `cron`. For continuous work set `scheduleMode: \"continuous\"` and choose `continuousDelayMinutes` (integer >= 1). Keep a valid `cron`; continuous ignores it but Pievo retains it so switching back restores the prior cadence.\n- `goal` is an optional standing objective. It never changes lifecycle state.\n- `model` and `reasoningEffort` are optional arbitrary strings. Include them only when the owner explicitly requests it.\n- `metricSchema` is optional; declare numeric per-run metrics to get a chart. Every exec report then supplies all values with `--metrics` (number or `null`).\n- `ui` is optional; include a day-one dashboard only when the product/metric shape is already settled.\n\n### Dashboard at create\n\nWhen the product shape is already known, author the initial `ui` now so the loop has a day-one dashboard. Use the primitives from `evolve.md` §3 and bind only declared metrics / documented product types. The common exact forms are `<loop-chart series=\"score:Score\"></loop-chart>` and `<loop-embed file=\"latest.md\"></loop-embed>`; artifact paths are relative to the loop folder. Never substitute `metric`, `src`, or `name` for those attributes — dry-run rejects broken primitives.\n- `notify`: `auto` (only when there's something to say) | `always` | `never`.\n- Don't add `timezone`, `claim`, or auth fields — `pievo new` injects the timezone, connect-key claim, and device token.\n\n## 5 · Validate, then create\n\nPreview first:\n\n```bash\n<pievo-cli> new --json '<config>' --dry-run\n```\n\nCheck the normalized objective and fire times look right. If you authored a `ui` and the preview warns that it was not applied, fix the HTML before creating.\n\nThen create for real:\n\n```bash\n<pievo-cli> new \\\n --json '<config>' \\\n --connect-key <connect-key> \\\n --agent claude-code\n```\n\n`pievo new` detects timezone, injects the claim, records the coding agent, authenticates, validates, and POSTs it. On success, tell the user the loop name + cadence and that the first run will come automatically shortly.\n",
@@ -468,12 +468,12 @@ var Route$1 = createFileRoute("/api/machine/blob/$hash")({ server: { handlers: {
468
468
  if (!token) return Response.json({ error: "missing device token" }, { status: 401 });
469
469
  const hash = safeDecode(new URL(request.url).pathname.split("/").pop() ?? "");
470
470
  if (hash === null) return Response.json({ error: "bad hash" }, { status: 400 });
471
- const { BLOB_CAP } = await import("./artifacts-DzWJrBxK.mjs");
471
+ const { BLOB_CAP } = await import("./artifacts-9G_Ai7vO.mjs");
472
472
  const declared = Number(request.headers.get("content-length") ?? "");
473
473
  if (Number.isFinite(declared) && declared > BLOB_CAP) return Response.json({ error: "blob exceeds size cap" }, { status: 413 });
474
474
  const buf = Buffer.from(await request.arrayBuffer());
475
475
  if (buf.length > BLOB_CAP) return Response.json({ error: "blob exceeds size cap" }, { status: 413 });
476
- const { getArtifactSync } = await import("./boot-BigKgB8p.mjs");
476
+ const { getArtifactSync } = await import("./boot-Zz5AJgfy.mjs");
477
477
  const r = await (await getArtifactSync()).putBlob(token, hash, buf);
478
478
  return Response.json(r.body, { status: r.status });
479
479
  } } } });
@@ -508,11 +508,11 @@ var Route = createFileRoute("/api/artifact/$loopId/$")({ server: { handlers: { G
508
508
  const segments = after.slice(slash + 1).split("/").map((s) => safeDecode(s));
509
509
  if (segments.some((s) => s === null)) return Response.json({ error: "bad path" }, { status: 400 });
510
510
  const relPath = segments.join("/");
511
- const loop = await (await import("./store-Dw4LiFjE.mjs")).getLoop(loopId);
511
+ const loop = await (await import("./store-DDOk2Ty_.mjs")).getLoop(loopId);
512
512
  if (!loop) return Response.json({ error: "not found" }, { status: 404 });
513
- const { requestScope, canAccessLoop } = await import("./auth-CbAfO4Ne.mjs");
513
+ const { requestScope, canAccessLoop } = await import("./auth-uQ19WsD1.mjs");
514
514
  if (!await canAccessLoop(loop.teamId, await requestScope())) return Response.json({ error: "not found" }, { status: 404 });
515
- const { readLoopArtifactBytes } = await import("./artifactFiles-Dl1EaUtJ.mjs");
515
+ const { readLoopArtifactBytes } = await import("./artifactFiles-Cp1IBHne.mjs");
516
516
  const r = await readLoopArtifactBytes(loopId, relPath);
517
517
  if (r.status !== 200 || !r.bytes) return Response.json({ error: "not found" }, { status: r.status });
518
518
  const filename = (r.filename || "file").replace(/["\\\r\n]/g, "_");
@@ -1,9 +1,9 @@
1
1
  import { g as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
- import { s as useSession } from "./LoopPlaybook-C86vJIjZ.mjs";
3
- import { t as SignIn } from "./SignIn-BQQiD3Ss.mjs";
4
- import { t as DashboardView } from "./DashboardView-CQdjYy03.mjs";
5
- import { t as Route } from "./routes-bWgX0tRE.mjs";
6
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-DYJB0rKC.js
2
+ import { s as useSession } from "./LoopPlaybook-WFNer22Y.mjs";
3
+ import { t as SignIn } from "./SignIn-2qr-vtR5.mjs";
4
+ import { t as DashboardView } from "./DashboardView-DJMpoucm.mjs";
5
+ import { t as Route } from "./routes-CXnbFjB_.mjs";
6
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-CMAUcUsZ.js
7
7
  var import_jsx_runtime = require_jsx_runtime();
8
8
  /**
9
9
  * The home route. Under the auth gate it is now a THIN redirect to the explicit
@@ -1,10 +1,10 @@
1
1
  import { c as createFileRoute, p as redirect, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
2
  import { c as getAuthState, h as listTemplates, u as getDefaultTeam } from "./loopApi-7MTSs6hy.mjs";
3
- import { a as authClient } from "./LoopPlaybook-C86vJIjZ.mjs";
4
- import { n as fetchLiveData } from "./DashboardView-CQdjYy03.mjs";
5
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-bWgX0tRE.js
3
+ import { a as authClient } from "./LoopPlaybook-WFNer22Y.mjs";
4
+ import { n as fetchLiveData } from "./DashboardView-DJMpoucm.mjs";
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-CXnbFjB_.js
6
6
  var $$splitErrorComponentImporter = () => import("./routes-Bx0bRxt9.mjs");
7
- var $$splitComponentImporter = () => import("./routes-DYJB0rKC.mjs");
7
+ var $$splitComponentImporter = () => import("./routes-CMAUcUsZ.mjs");
8
8
  /**
9
9
  * The home route. Under the auth gate it is now a THIN redirect to the explicit
10
10
  * team URL (`/t/<lastUsed|personal>`) so the dashboard's team lives in the path
@@ -0,0 +1,2 @@
1
+ import { x as computeRunDiff } from "./boot-DPoPmSLh.mjs";
2
+ export { computeRunDiff };