@kky42/pievo-server 2.4.2 → 2.4.4

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 (55) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/MachinesModal-Ci18Bitd.js +1 -0
  3. package/.output/public/assets/{SignIn-0Tjqs-Ma.js → SignIn-Czy-XJou.js} +1 -1
  4. package/.output/public/assets/{actionUi-DpwGIGpw.js → actionUi-DGJmNwsD.js} +1 -1
  5. package/.output/public/assets/app-CuZ0I3Mb.css +2 -0
  6. package/.output/public/assets/index-gJavUZIA.js +10 -0
  7. package/.output/public/assets/{invite._token-KMD2JAgE.js → invite._token-BQUbjPMM.js} +1 -1
  8. package/.output/public/assets/{invite._token-Btg_0aLp.js → invite._token-BUYUsIBj.js} +1 -1
  9. package/.output/public/assets/lifecycleUi-C0DaC6NM.js +1 -0
  10. package/.output/public/assets/loops._loopId-BkEPvT1q.js +67 -0
  11. package/.output/public/assets/{loops._loopId_.runs._runId-DRCgXaCq.js → loops._loopId_.runs._runId-SM4sD1xB.js} +2 -2
  12. package/.output/public/assets/{preload-helper-DsxECZIS.js → preload-helper-D1jXs0sN.js} +1 -1
  13. package/.output/public/assets/routes-4mIvs8LG.js +1 -0
  14. package/.output/public/assets/{routes-LDbnnQ3f.js → routes-B0svLfFq.js} +1 -1
  15. package/.output/public/assets/{t._teamId-DUena1pV.js → t._teamId-BLO_bz6b.js} +1 -1
  16. package/.output/public/assets/t._teamId-D-wGh4mo.js +1 -0
  17. package/.output/public/assets/{ui-Do4gqMyP.js → ui-DGHTxOhC.js} +1 -1
  18. package/.output/server/_ssr/{DashboardView-C2LdV6J0.mjs → DashboardView-DqZLADCp.mjs} +14 -93
  19. package/.output/server/_ssr/{MachinesModal-BjkcVjjx.mjs → MachinesModal-BsCfGuwp.mjs} +140 -5
  20. package/.output/server/_ssr/{SignIn-DEGrvJvb.mjs → SignIn-ffgDY0yf.mjs} +3 -3
  21. package/.output/server/_ssr/{SocialLinks-Cm4H8pUJ.mjs → SocialLinks-Bt7huqfS.mjs} +3 -2
  22. package/.output/server/_ssr/{actionUi-DJBWuNwr.mjs → actionUi-DD7Cd7Le.mjs} +2 -2
  23. package/.output/server/_ssr/{artifactFiles-DtpRidFZ.mjs → artifactFiles-DHBXTtZn.mjs} +2 -2
  24. package/.output/server/_ssr/{artifactKind-FBYbgSuf.mjs → artifactKind-CwQ_Ddj6.mjs} +3 -3
  25. package/.output/server/_ssr/{invite._token-CJ6-H-s3.mjs → invite._token-AvtAuDKv.mjs} +2 -2
  26. package/.output/server/_ssr/{invite._token-l1SjouDz.mjs → invite._token-CHR5K84a.mjs} +4 -4
  27. package/.output/server/_ssr/{invite._token-dLKDJKVs.mjs → invite._token-tw3mgvEo.mjs} +6 -6
  28. package/.output/server/_ssr/lifecycleUi-DOr6Af13.mjs +51 -0
  29. package/.output/server/_ssr/{loopApi-BKyFB4KM.mjs → loopApi-7YHXDl5g.mjs} +7 -7
  30. package/.output/server/_ssr/{loopProjection-B8a829ij.mjs → loopProjection-eZvVobW7.mjs} +29 -4
  31. package/.output/server/_ssr/{loops._loopId-DS16Phmq.mjs → loops._loopId-TEIcuqZU.mjs} +60 -104
  32. package/.output/server/_ssr/{loops._loopId_.runs._runId-CduETLqH.mjs → loops._loopId_.runs._runId-B4jXeonc.mjs} +3 -3
  33. package/.output/server/_ssr/{loops._loopId_.runs._runId-BEJI6iK5.mjs → loops._loopId_.runs._runId-BVQKe8xT.mjs} +6 -6
  34. package/.output/server/_ssr/{router-CXyrnvx-.mjs → router-DyhWcIzt.mjs} +8 -8
  35. package/.output/server/_ssr/{routes-DD94baie.mjs → routes-BWLQNDn5.mjs} +2 -2
  36. package/.output/server/_ssr/{routes-Wjexi35W.mjs → routes-Cz49hLy6.mjs} +5 -5
  37. package/.output/server/_ssr/{routes-BulNEUEE.mjs → routes-DqIGr7p0.mjs} +5 -5
  38. package/.output/server/_ssr/ssr.mjs +21 -21
  39. package/.output/server/_ssr/{t._teamId-COuMKQ4r.mjs → t._teamId-COoQSQtH.mjs} +5 -5
  40. package/.output/server/_ssr/{t._teamId-Bd6-zZsy.mjs → t._teamId-Dms0PTMu.mjs} +2 -2
  41. package/.output/server/_ssr/{t._teamId-1CreIlPV.mjs → t._teamId-xFPYdSPu.mjs} +5 -5
  42. package/.output/server/_ssr/{teamFns-j2JKjorZ.mjs → teamFns-gilVwh7z.mjs} +2 -2
  43. package/.output/server/_ssr/{ui-D5KWstlb.mjs → ui-dMEI4sHj.mjs} +12 -7
  44. package/.output/server/_tanstack-start-manifest_v-UkU-Jq6w.mjs +86 -0
  45. package/.output/server/index.mjs +86 -86
  46. package/package.json +1 -1
  47. package/.output/public/assets/MachinesModal-CSbnrUER.js +0 -1
  48. package/.output/public/assets/app-CaZpuwOS.css +0 -2
  49. package/.output/public/assets/index-CaS_SmDq.js +0 -10
  50. package/.output/public/assets/lifecycleUi-C7dwHtbw.js +0 -1
  51. package/.output/public/assets/loops._loopId-D5usF3DO.js +0 -67
  52. package/.output/public/assets/routes-CtFgwdgW.js +0 -1
  53. package/.output/public/assets/t._teamId-D41xcbsF.js +0 -1
  54. package/.output/server/_ssr/lifecycleUi-Dad3hvhm.mjs +0 -37
  55. package/.output/server/_tanstack-start-manifest_v-3H7yBKLz.mjs +0 -85
@@ -1,11 +1,11 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { St as machinePresence, tt as isOutdated } from "./boot-sNlIkoLe.mjs";
3
3
  import { a as DialogClose, c as TooltipPopup, d as TooltipTrigger, f as TooltipRoot, g as require_react, h as require_jsx_runtime, i as DialogPopup, l as TooltipPositioner, n as DialogRoot, o as DialogBackdrop, r as DialogPortal, t as DialogTitle, u as TooltipPortal } from "../_libs/@base-ui/react+[...].mjs";
4
- import { D as until, O as useHydrated, S as runPulseAnim, a as btn, d as dotColor, f as dotLabel, h as fmt, m as dur, o as btnDanger, p as dotOpacity, s as btnPrimary, t as ErrorBanner, v as inputCls, w as sectionHeadCls, x as rel, y as labelCls } from "./ui-D5KWstlb.mjs";
4
+ import { C as scheduleText, D as until, O as useHydrated, _ as inputCls, a as btn, b as rel, d as dotLabel, f as dotOpacity, m as fmt, o as btnDanger, p as dur, r as Pill, s as btnPrimary, t as ErrorBanner, u as dotColor, v as labelCls, w as sectionHeadCls, x as runPulseAnim, y as lastRunOf } from "./ui-dMEI4sHj.mjs";
5
5
  import { n as createServerFn } from "./ssr.mjs";
6
- import { d as getConfig, o as createSsrRpc } from "./SocialLinks-Cm4H8pUJ.mjs";
7
- import { n as daemonStopSupport } from "./lifecycleUi-Dad3hvhm.mjs";
8
- //#region node_modules/.nitro/vite/services/ssr/assets/MachinesModal-BjkcVjjx.js
6
+ import { d as getConfig, o as createSsrRpc } from "./SocialLinks-Bt7huqfS.mjs";
7
+ import { i as lifecyclePresentation, n as daemonStopSupport } from "./lifecycleUi-DOr6Af13.mjs";
8
+ //#region node_modules/.nitro/vite/services/ssr/assets/MachinesModal-BsCfGuwp.js
9
9
  var import_react = /* @__PURE__ */ __toESM(require_react());
10
10
  var import_jsx_runtime = require_jsx_runtime();
11
11
  /**
@@ -73,6 +73,66 @@ function mergeRuns(primary, secondary) {
73
73
  out.sort((a, b) => a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0);
74
74
  return out;
75
75
  }
76
+ function LoopMeta({ schedule, nextRun, enabled, machine, workdir, model, reasoningEffort }) {
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
78
+ className: "min-w-0 text-right text-meta text-secondary",
79
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
80
+ className: "flex flex-wrap items-center justify-end gap-x-2.5 gap-y-1",
81
+ children: [
82
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
83
+ title: schedule.mode === "cron" ? schedule.cron : void 0,
84
+ children: scheduleText(schedule)
85
+ }),
86
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
87
+ className: "text-wire",
88
+ children: "·"
89
+ }),
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: ["next ", fmt(nextRun)] }),
91
+ nextRun && enabled && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
92
+ className: "text-disabled",
93
+ children: [
94
+ "(",
95
+ until(nextRun),
96
+ ")"
97
+ ]
98
+ }),
99
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
100
+ className: "text-wire",
101
+ children: "·"
102
+ }),
103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
104
+ className: "inline-flex items-center gap-1.5",
105
+ title: `${machine.name || "machine"} · ${machine.presence}`,
106
+ children: [
107
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
108
+ className: `size-1.5 rounded-full ${machine.presence === "online" ? "bg-rubik-green" : machine.presence === "asleep" ? "bg-rubik-yellow" : "bg-disabled"}`,
109
+ "aria-hidden": "true"
110
+ }),
111
+ machine.name || "machine",
112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
113
+ className: "sr-only",
114
+ children: [
115
+ "(",
116
+ machine.presence,
117
+ ")"
118
+ ]
119
+ })
120
+ ]
121
+ })
122
+ ]
123
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
124
+ className: "mt-1 truncate",
125
+ title: workdir,
126
+ children: [
127
+ workdir,
128
+ " · Model: ",
129
+ model || "default",
130
+ " · Reasoning: ",
131
+ reasoningEffort || "default"
132
+ ]
133
+ })]
134
+ });
135
+ }
76
136
  var PAGE = 16;
77
137
  var RAD = "rounded-[4px]";
78
138
  var SEG = `h-5 w-[18px] shrink-0 ${RAD}`;
@@ -197,6 +257,81 @@ function Timeline({ loop, runs, total, onLoadMore, onPickRun }) {
197
257
  ]
198
258
  });
199
259
  }
260
+ var AGENT_LABEL = {
261
+ "claude-code": "Claude Code",
262
+ codex: "Codex"
263
+ };
264
+ var titleCls = "rounded-sm text-left text-[17px] font-semibold tracking-[-0.01em] text-display outline-none";
265
+ /** The shared loop summary shown on both the dashboard and loop detail page. */
266
+ function LoopOverview({ loop, runs, onLoadMore, onPickRun, onOpen, extraPill }) {
267
+ const last = lastRunOf({
268
+ ...loop,
269
+ runs
270
+ });
271
+ const lifecycle = lifecyclePresentation(loop);
272
+ const hydrated = useHydrated();
273
+ const newestRun = runs.at(-1);
274
+ const latestIncidentRun = newestRun?.reportIncident ? newestRun : void 0;
275
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
277
+ className: "mb-6 flex flex-wrap items-center gap-3",
278
+ children: [
279
+ onOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
280
+ type: "button",
281
+ onClick: (event) => {
282
+ event.stopPropagation();
283
+ onOpen();
284
+ },
285
+ className: `${titleCls} cursor-pointer focus-visible:ring-2 focus-visible:ring-interactive focus-visible:ring-offset-4 focus-visible:ring-offset-surface`,
286
+ children: loop.name
287
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
288
+ className: titleCls,
289
+ children: loop.name
290
+ }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
292
+ tone: lifecycle.tone,
293
+ children: lifecycle.label
294
+ }),
295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, {
296
+ tone: "outline",
297
+ children: AGENT_LABEL[loop.agent]
298
+ }),
299
+ extraPill,
300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
301
+ className: "ml-auto min-w-0",
302
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopMeta, {
303
+ schedule: loop.schedule,
304
+ nextRun: loop.nextRun,
305
+ enabled: loop.enabled,
306
+ machine: loop.machine,
307
+ workdir: loop.workdir,
308
+ model: loop.model,
309
+ reasoningEffort: loop.reasoningEffort
310
+ })
311
+ })
312
+ ]
313
+ }),
314
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Timeline, {
315
+ loop,
316
+ runs,
317
+ total: loop.runCount,
318
+ onLoadMore,
319
+ onPickRun
320
+ }),
321
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
322
+ className: "mt-[18px] flex items-center gap-2 text-meta text-secondary",
323
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [loop.runCount, " runs"] }), last && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
324
+ "· last ",
325
+ dotLabel(last),
326
+ hydrated && ` · ${rel(last.ts)}`
327
+ ] })]
328
+ }),
329
+ latestIncidentRun?.reportIncident && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
330
+ className: "mt-1.5 text-meta text-secondary",
331
+ children: latestIncidentRun.phase === "error" ? "Last run failed · Terminal report rejected" : "Last run telemetry warning · Terminal report rejected"
332
+ })
333
+ ] });
334
+ }
200
335
  /** Shared modal shell — Base UI Dialog handles focus trap, Esc, and scroll lock. */
201
336
  function Modal({ open, onClose, children, wide = false }) {
202
337
  const pos = `-translate-y-1/2 max-h-[calc(100dvh-4rem)] ${wide ? "top-1/2 max-w-[62rem]" : "top-[46%] max-w-160"}`;
@@ -586,4 +721,4 @@ function MachinesModal({ open, onClose, teamId }) {
586
721
  });
587
722
  }
588
723
  //#endregion
589
- export { Timeline as a, mergeRuns as c, ModalSection as i, Modal as n, daemonConnectCommand as o, ModalHead as r, listMachines as s, MachinesModal as t };
724
+ export { ModalSection as a, listMachines as c, ModalHead as i, mergeRuns as l, MachinesModal as n, Timeline as o, Modal as r, daemonConnectCommand as s, LoopOverview as t };
@@ -1,7 +1,7 @@
1
1
  import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
- import { s as btnPrimary } from "./ui-D5KWstlb.mjs";
3
- import { S as signIn, n as GitHubIcon, r as PievoLogo, t as GITHUB_URL } from "./SocialLinks-Cm4H8pUJ.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/SignIn-DEGrvJvb.js
2
+ import { s as btnPrimary } from "./ui-dMEI4sHj.mjs";
3
+ import { S as signIn, n as GitHubIcon, r as PievoLogo, t as GITHUB_URL } from "./SocialLinks-Bt7huqfS.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/SignIn-ffgDY0yf.js
5
5
  var import_jsx_runtime = require_jsx_runtime();
6
6
  /**
7
7
  * Sign-in CTA — shown by the auth gate when a GitHub OAuth app is configured and
@@ -2,7 +2,7 @@ import { o as __toESM } from "../_runtime.mjs";
2
2
  import { D as defu, Gt as toKebabCase, L as getBaseURL, at as isSafeUrlScheme, g as capitalizeFirstLetter, x as createFetch } from "./boot-sNlIkoLe.mjs";
3
3
  import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
4
4
  import { n as createServerFn, r as getServerFnById, t as TSS_SERVER_FUNCTION } from "./ssr.mjs";
5
- //#region node_modules/.nitro/vite/services/ssr/assets/SocialLinks-Cm4H8pUJ.js
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/SocialLinks-Bt7huqfS.js
6
6
  var import_react = /* @__PURE__ */ __toESM(require_react());
7
7
  var import_jsx_runtime = require_jsx_runtime();
8
8
  var createSsrRpc = (functionId) => {
@@ -57,7 +57,8 @@ var canViewTeam = createServerFn({ method: "GET" }).validator((teamId) => teamId
57
57
  /** GET — the caller's default dashboard team as an id: the last-used cookie,
58
58
  * validated, else the personal team. Backs the `/` → `/t/<id>` redirect. */
59
59
  var getDefaultTeam = createServerFn({ method: "GET" }).handler(createSsrRpc("dc0ec955d0d53a150a3e9a4673f98f3509cfb4bd411c512079ae4e94c561b70c"));
60
- /** GET — the signed-in user's loops as compact summaries (newest first).
60
+ /** GET — the signed-in user's loops as compact summaries (most recently run first;
61
+ * never-run loops remain newest-created first).
61
62
  * Gate on ⇒ only the given/active team's loops; open mode ⇒ the full shared list.
62
63
  * An explicit `teamId` (the `/t/<id>` route) scopes this request independent of
63
64
  * the cookie, so different tabs on /t/A and /t/B list different teams at once. */
@@ -1,7 +1,7 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- import { a as btn, o as btnDanger, s as btnPrimary } from "./ui-D5KWstlb.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-DJBWuNwr.js
3
+ import { a as btn, o as btnDanger, s as btnPrimary } from "./ui-dMEI4sHj.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/actionUi-DD7Cd7Le.js
5
5
  var import_react = /* @__PURE__ */ __toESM(require_react());
6
6
  var import_jsx_runtime = require_jsx_runtime();
7
7
  /**
@@ -1,6 +1,6 @@
1
1
  import { F as getArtifactFile, I as getArtifactSync, Lt as safeRelPath, lt as listArtifacts } from "./boot-sNlIkoLe.mjs";
2
- import { t as toArtifactSummary } from "./loopProjection-B8a829ij.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/artifactFiles-DtpRidFZ.js
2
+ import { n as toArtifactSummary } from "./loopProjection-eZvVobW7.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/artifactFiles-DHBXTtZn.js
4
4
  /**
5
5
  * Server-side reads over a loop's current exact artifacts. Pure helpers
6
6
  * (no request/session context) so they're shared by the lazy server fns
@@ -1,7 +1,7 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
- import { i as authClient, u as getAuthState } from "./SocialLinks-Cm4H8pUJ.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/artifactKind-FBYbgSuf.js
4
- var $$splitComponentImporter = () => import("./loops._loopId-DS16Phmq.mjs");
2
+ import { i as authClient, u as getAuthState } from "./SocialLinks-Bt7huqfS.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/artifactKind-CwQ_Ddj6.js
4
+ var $$splitComponentImporter = () => import("./loops._loopId-TEIcuqZU.mjs");
5
5
  /**
6
6
  * Loop detail page — `/loops/$loopId`: a loop header and action toolbar, the
7
7
  * exact artifact Files panel, and the runs timeline. The view owns its own
@@ -1,7 +1,7 @@
1
1
  import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
- import { r as LoadErrorCard } from "./actionUi-DJBWuNwr.mjs";
2
+ import { r as LoadErrorCard } from "./actionUi-DD7Cd7Le.mjs";
3
3
  import { f as useRouter } from "../_libs/@tanstack/react-router+[...].mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-CJ6-H-s3.js
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-AvtAuDKv.js
5
5
  var import_jsx_runtime = require_jsx_runtime();
6
6
  /** Redeem a team invite after normal gated sign-in. Invites grant membership but
7
7
  * never bypass the login allowlist; open mode has no invite identity to redeem. */
@@ -1,8 +1,8 @@
1
1
  import { c as createFileRoute, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
2
- import { i as authClient, u as getAuthState } from "./SocialLinks-Cm4H8pUJ.mjs";
3
- //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-l1SjouDz.js
4
- var $$splitErrorComponentImporter = () => import("./invite._token-CJ6-H-s3.mjs");
5
- var $$splitComponentImporter = () => import("./invite._token-dLKDJKVs.mjs");
2
+ import { i as authClient, u as getAuthState } from "./SocialLinks-Bt7huqfS.mjs";
3
+ //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-CHR5K84a.js
4
+ var $$splitErrorComponentImporter = () => import("./invite._token-AvtAuDKv.mjs");
5
+ var $$splitComponentImporter = () => import("./invite._token-tw3mgvEo.mjs");
6
6
  /** Redeem a team invite after normal gated sign-in. Invites grant membership but
7
7
  * never bypass the login allowlist; open mode has no invite identity to redeem. */
8
8
  var Route = createFileRoute("/invite/$token")({
@@ -1,13 +1,13 @@
1
1
  import { o as __toESM } from "../_runtime.mjs";
2
2
  import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
- import { s as btnPrimary } from "./ui-D5KWstlb.mjs";
3
+ import { s as btnPrimary } from "./ui-dMEI4sHj.mjs";
4
4
  import { d as useNavigate } from "../_libs/@tanstack/react-router+[...].mjs";
5
- import { E as useSession, r as PievoLogo } from "./SocialLinks-Cm4H8pUJ.mjs";
5
+ import { E as useSession, r as PievoLogo } from "./SocialLinks-Bt7huqfS.mjs";
6
6
  import { t as setActiveTeamCookie } from "./teamCookie-B7hLOIie.mjs";
7
- import { c as redeemTeamInvite } from "./teamFns-j2JKjorZ.mjs";
8
- import { t as Route } from "./invite._token-l1SjouDz.mjs";
9
- import { t as SignIn } from "./SignIn-DEGrvJvb.mjs";
10
- //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-dLKDJKVs.js
7
+ import { c as redeemTeamInvite } from "./teamFns-gilVwh7z.mjs";
8
+ import { t as Route } from "./invite._token-CHR5K84a.mjs";
9
+ import { t as SignIn } from "./SignIn-ffgDY0yf.mjs";
10
+ //#region node_modules/.nitro/vite/services/ssr/assets/invite._token-tw3mgvEo.js
11
11
  var import_react = /* @__PURE__ */ __toESM(require_react());
12
12
  var import_jsx_runtime = require_jsx_runtime();
13
13
  /** Redeem a team invite after normal gated sign-in. Invites grant membership but
@@ -0,0 +1,51 @@
1
+ //#region node_modules/.nitro/vite/services/ssr/assets/lifecycleUi-DOr6Af13.js
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
+ /** Derive product lifecycle state only from durable server facts. */
4
+ function deriveLoopLifecycle(loop) {
5
+ if (loop.deleteRequestedAt != null) return "deleting";
6
+ const running = loop.runs.find((run) => run.phase === "running");
7
+ if (!loop.enabled && running?.cancelRequested) return "stopping";
8
+ if (!loop.enabled && (loop.running || running)) return "paused-finishing";
9
+ if (!loop.enabled) return "paused";
10
+ return "active";
11
+ }
12
+ /** Stable lifecycle badge shared by dashboard cards and loop detail. It shows
13
+ * only scheduling state and its durable pause cause; execution transients
14
+ * (queued/running/stopping) stay in the runs timeline and never replace it. */
15
+ function lifecyclePresentation(loop) {
16
+ if (loop.deleteRequestedAt != null) return {
17
+ label: "Deleting",
18
+ tone: "accent"
19
+ };
20
+ if (loop.enabled) return {
21
+ label: "Active",
22
+ tone: "success"
23
+ };
24
+ if (loop.pauseCause?.kind === "blocked") return {
25
+ label: "Paused · blocked",
26
+ tone: "attention"
27
+ };
28
+ if (loop.pauseCause?.kind === "failure-streak") return {
29
+ label: "Paused · failure streak",
30
+ tone: "attention"
31
+ };
32
+ if (loop.pauseCause?.kind === "owner") return {
33
+ label: "Paused · owner",
34
+ tone: "neutral"
35
+ };
36
+ return {
37
+ label: "Paused",
38
+ tone: "neutral"
39
+ };
40
+ }
41
+ function daemonStopSupport(protocol) {
42
+ return protocol === 4 ? {
43
+ supported: true,
44
+ label: `Daemon protocol 4 · Stop supported`
45
+ } : {
46
+ supported: false,
47
+ label: `Daemon protocol ${protocol ?? "unknown"} · upgrade required`
48
+ };
49
+ }
50
+ //#endregion
51
+ export { lifecyclePresentation as i, daemonStopSupport as n, deriveLoopLifecycle as r, DAEMON_UPGRADE_REQUIRED as t };
@@ -1,9 +1,9 @@
1
- import { $t as validateLoopEdit, Et as pauseLoop$1, Ft as requestRunCancel, G as getMachine, J as getRun, Kt as tryDeleteLoop, P as forceDeleteLoop, Pt as requestDeleteLoop, Q as hasRunningRun, St as machinePresence, Ut as stopLoop$1, Vt as startLoop$1, W as getLoop, X as getTeamMember, Y as getTeam, _t as listTeamsForUser, ht as listRunsBefore, j as ensureServer, qt as updateLoop, ut as listLoops$1 } from "./boot-sNlIkoLe.mjs";
2
- import { i as toRunSummaries, n as toLoopDetail, r as toLoopSummary } from "./loopProjection-B8a829ij.mjs";
1
+ import { $t as validateLoopEdit, Et as pauseLoop$1, Ft as requestRunCancel, G as getMachine, J as getRun, Kt as tryDeleteLoop, P as forceDeleteLoop, Pt as requestDeleteLoop, Q as hasRunningRun, St as machinePresence, Ut as stopLoop$1, Vt as startLoop$1, W as getLoop, X as getTeamMember, Y as getTeam, _t as listTeamsForUser, dt as listMachines, ft as listMachinesForTeam, ht as listRunsBefore, j as ensureServer, qt as updateLoop, ut as listLoops$1 } from "./boot-sNlIkoLe.mjs";
2
+ import { a as toRunSummaries, i as toLoopSummaries, r as toLoopDetail, t as sortLoopSummariesByRecentRun } from "./loopProjection-eZvVobW7.mjs";
3
3
  import { canAccessLoop, requestScope } from "./auth-C0zoZCGe.mjs";
4
4
  import { n as createServerFn } from "./ssr.mjs";
5
5
  import { t as createServerRpc } from "./createServerRpc-BD8Xn_0_.mjs";
6
- //#region node_modules/.nitro/vite/services/ssr/assets/loopApi-BKyFB4KM.js
6
+ //#region node_modules/.nitro/vite/services/ssr/assets/loopApi-7YHXDl5g.js
7
7
  /**
8
8
  * Server functions backing the dashboard. They run server-side (createServerFn
9
9
  * → RPC) and call the IN-PROCESS scheduler + store directly — the scheduler
@@ -107,8 +107,8 @@ var listLoops = createServerFn({ method: "GET" }).validator((teamId) => teamId).
107
107
  await backend();
108
108
  const { enforce, userId, teamId: active } = await requestScope(teamId);
109
109
  if (enforce && !userId) return [];
110
- const loops = (await listLoops$1(enforce ? active : void 0)).sort((a, b) => a.createdAt < b.createdAt ? 1 : -1);
111
- return await Promise.all(loops.map(toLoopSummary));
110
+ const [loopRows, machines] = await Promise.all([listLoops$1(enforce ? active : void 0), enforce ? listMachinesForTeam(active) : listMachines()]);
111
+ return sortLoopSummariesByRecentRun(await toLoopSummaries(loopRows.sort((a, b) => a.createdAt < b.createdAt ? 1 : -1), machines));
112
112
  });
113
113
  var getLoopDetail_createServerFn_handler = createServerRpc({
114
114
  id: "b050455aacc84dd2a2c9a45517826ad10f91d8f1545e87cc7015784cc7116a97",
@@ -150,7 +150,7 @@ var getArtifacts_createServerFn_handler = createServerRpc({
150
150
  var getArtifacts = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifacts_createServerFn_handler, async ({ data }) => {
151
151
  await backend();
152
152
  if (!await ownedLoop(data.loopId)) return [];
153
- const { listLoopArtifacts } = await import("./artifactFiles-DtpRidFZ.mjs");
153
+ const { listLoopArtifacts } = await import("./artifactFiles-DHBXTtZn.mjs");
154
154
  return listLoopArtifacts(data.loopId);
155
155
  });
156
156
  var getArtifact_createServerFn_handler = createServerRpc({
@@ -161,7 +161,7 @@ var getArtifact_createServerFn_handler = createServerRpc({
161
161
  var getArtifact = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifact_createServerFn_handler, async ({ data }) => {
162
162
  await backend();
163
163
  if (!await ownedLoop(data.loopId)) return { error: "file not found" };
164
- const { readLoopArtifact } = await import("./artifactFiles-DtpRidFZ.mjs");
164
+ const { readLoopArtifact } = await import("./artifactFiles-DHBXTtZn.mjs");
165
165
  return readLoopArtifact(data.loopId, data.path);
166
166
  });
167
167
  var getRunDiff_createServerFn_handler = createServerRpc({
@@ -1,7 +1,18 @@
1
1
  import { G as getMachine, Ht as statusDefinitionsFromLoop, Q as hasRunningRun, Rt as scheduleFromLoop, St as machinePresence, T as daemonNeedsUpdate, Z as hasPendingRun, kt as reconciliationStatesForRuns, mt as listRuns, u as MIN_DAEMON_VERSION, y as countRuns } from "./boot-sNlIkoLe.mjs";
2
- //#region node_modules/.nitro/vite/services/ssr/assets/loopProjection-B8a829ij.js
2
+ //#region node_modules/.nitro/vite/services/ssr/assets/loopProjection-eZvVobW7.js
3
3
  /** Canonical client projections for persisted loops and runs. */
4
4
  var SUMMARY_RUNS = 18;
5
+ /** Dashboard order: loops with runs first, most recent run first. The incoming
6
+ * order remains the tie-breaker, so never-run loops keep listLoops' newest-created
7
+ * ordering and equal timestamps do not make cards jump between polls. */
8
+ function sortLoopSummariesByRecentRun(summaries) {
9
+ return summaries.toSorted((a, b) => {
10
+ if (a.lastRunTs && b.lastRunTs) return b.lastRunTs.localeCompare(a.lastRunTs);
11
+ if (a.lastRunTs) return -1;
12
+ if (b.lastRunTs) return 1;
13
+ return 0;
14
+ });
15
+ }
5
16
  function nextRun(loop) {
6
17
  return [loop.nextRunAt, loop.nextCadenceAt].filter((v) => v != null).sort()[0] ?? null;
7
18
  }
@@ -45,8 +56,9 @@ function toArtifactSummary(row) {
45
56
  oversize: row.oversize
46
57
  };
47
58
  }
48
- async function toLoopSummary(loop) {
59
+ async function toLoopSummaryWithMachine(loop, machine) {
49
60
  const runs = await toRunSummaries(loop.id, await listRuns(loop.id, SUMMARY_RUNS));
61
+ const presence = machinePresence(machine?.online, machine?.lastSeen);
50
62
  return {
51
63
  id: loop.id,
52
64
  name: loop.name,
@@ -55,6 +67,13 @@ async function toLoopSummary(loop) {
55
67
  agent: loop.agent,
56
68
  model: loop.model ?? null,
57
69
  reasoningEffort: loop.reasoningEffort ?? null,
70
+ machine: {
71
+ id: loop.machineId,
72
+ name: machine?.name || "",
73
+ online: presence === "online",
74
+ presence,
75
+ lastSeen: machine?.lastSeen ?? null
76
+ },
58
77
  enabled: loop.enabled,
59
78
  nextRun: nextRun(loop),
60
79
  running: await hasRunningRun(loop.id),
@@ -67,6 +86,12 @@ async function toLoopSummary(loop) {
67
86
  runCount: await countRuns(loop.id)
68
87
  };
69
88
  }
89
+ /** Batch dashboard projection: machine rows are preloaded once, avoiding a
90
+ * machine lookup per loop on every dashboard poll. */
91
+ async function toLoopSummaries(loops, machines) {
92
+ const byId = new Map(machines.map((machine) => [machine.id, machine]));
93
+ return Promise.all(loops.map((loop) => toLoopSummaryWithMachine(loop, byId.get(loop.machineId))));
94
+ }
70
95
  function toLoopFull(loop) {
71
96
  return {
72
97
  id: loop.id,
@@ -91,7 +116,7 @@ async function toLoopDetail(loop) {
91
116
  const presence = machinePresence(m?.online, m?.lastSeen);
92
117
  return {
93
118
  loop: toLoopFull(loop),
94
- summary: await toLoopSummary(loop),
119
+ summary: await toLoopSummaryWithMachine(loop, m),
95
120
  machine: {
96
121
  id: loop.machineId,
97
122
  name: m?.name || "",
@@ -107,4 +132,4 @@ async function toLoopDetail(loop) {
107
132
  };
108
133
  }
109
134
  //#endregion
110
- export { toRunSummaries as i, toLoopDetail as n, toLoopSummary as r, toArtifactSummary as t };
135
+ export { toRunSummaries as a, toLoopSummaries as i, toArtifactSummary as n, toLoopDetail as r, sortLoopSummariesByRecentRun as t };