@kky42/pievo-server 2.4.12 → 2.4.14

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 (88) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/SignIn-CIFwnZtF.js +1 -0
  3. package/.output/public/assets/{ui-s5IMg6RF.js → actionUi-5PtES4q0.js} +1 -1
  4. package/.output/public/assets/app-DvHMhs7S.css +2 -0
  5. package/.output/public/assets/index-CRX2pu0W.js +10 -0
  6. package/.output/public/assets/loops._loopId-BsuV-Rmf.js +67 -0
  7. package/.output/public/assets/loops._loopId_.runs._runId-DpK_fzmZ.js +3 -0
  8. package/.output/public/assets/{preload-helper-Bs7oCAsw.js → preload-helper-sAZOZb3G.js} +3 -3
  9. package/.output/public/assets/routes-Dm_3J2aV.js +1 -0
  10. package/.output/public/assets/routes-DxF_s3cD.js +1 -0
  11. package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
  12. package/.output/server/_ssr/{MachinesModal-BhRw7oOx.mjs → MachinesModal-BaEtzycr.mjs} +24 -57
  13. package/.output/server/_ssr/{SignIn-BhoZIOUp.mjs → SignIn-sHQaBQJC.mjs} +3 -3
  14. package/.output/server/_ssr/{ui-DGz-q9MT.mjs → actionUi-5HOCZnom.mjs} +115 -4
  15. package/.output/server/_ssr/{artifactFiles-ChuJ4PzC.mjs → artifactFiles-DO43wwXA.mjs} +4 -3
  16. package/.output/server/_ssr/{artifactKind-DXumOv7c.mjs → artifactKind-DwDr8IYc.mjs} +6 -14
  17. package/.output/server/_ssr/artifacts-Cd7Qx3Qp.mjs +2 -0
  18. package/.output/server/_ssr/{auth-LwPp_iim.mjs → auth-0AamrwHo.mjs} +44 -124
  19. package/.output/server/_ssr/{SocialLinks-DVCLmql0.mjs → auth-client-lSMb_Idt.mjs} +143 -109
  20. package/.output/server/_ssr/boot-C472kLwY.mjs +3947 -0
  21. package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CHMDkKqA.mjs → bun-sqlite-dialect-BW9W1_Ps-DLIXocA0.mjs} +2 -2
  22. package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-DYum6qky.mjs → d1-sqlite-dialect-BLC8LXE6-BoFMIPr_.mjs} +2 -2
  23. package/.output/server/_ssr/db-BzvMQ2kx.mjs +2 -0
  24. package/.output/server/_ssr/{dist-bWqs5sTy.mjs → dist-ClzqkwxD.mjs} +2 -2
  25. package/.output/server/_ssr/{factory-pBwrjVTI.mjs → factory-ixUjZqJn.mjs} +2 -2
  26. package/.output/server/_ssr/{kysely-adapter-DMf5pFTf.mjs → kysely-adapter-DkZbmKgV.mjs} +1 -1
  27. package/.output/server/_ssr/logger-DDjsYB2X.mjs +2 -0
  28. package/.output/server/_ssr/{loopApi-Im6JSK0p.mjs → loopApi-DT751TJA.mjs} +30 -90
  29. package/.output/server/_ssr/{loopProjection-DIpGR6rp.mjs → loopProjection-qaD2I48a.mjs} +5 -2
  30. package/.output/server/_ssr/loopTags-CXx5UdGf.mjs +3356 -0
  31. package/.output/server/_ssr/{loops._loopId-B5iPseDG.mjs → loops._loopId-CXgw2Rz1.mjs} +144 -46
  32. package/.output/server/_ssr/{loops._loopId_.runs._runId-DVtG0xYb.mjs → loops._loopId_.runs._runId-Dk94Z0Jq.mjs} +6 -13
  33. package/.output/server/_ssr/{loops._loopId_.runs._runId-BA-P6sGA.mjs → loops._loopId_.runs._runId-SASSqOfy.mjs} +31 -23
  34. package/.output/server/_ssr/{machineFns-Bb9KNXun.mjs → machineFns-BSrIgn3f.mjs} +42 -108
  35. package/.output/server/_ssr/{node-sqlite-dialect-Dho9YjXb.mjs → node-sqlite-dialect-BbUqnnYv.mjs} +2 -2
  36. package/.output/server/_ssr/{router-C8iotXtk.mjs → router-BlLlhfJe.mjs} +26 -40
  37. package/.output/server/_ssr/routes-Cr-9yDEH.mjs +491 -0
  38. package/.output/server/_ssr/{routes-FO0MFfYK.mjs → routes-DRBS4Zi4.mjs} +4 -9
  39. package/.output/server/_ssr/routes-DTBltabU.mjs +27 -0
  40. package/.output/server/_ssr/ssr.mjs +28 -88
  41. package/.output/server/_ssr/store-vDZ9INSa.mjs +2 -0
  42. package/.output/server/_ssr/tokens-BHiCElYD.mjs +2 -0
  43. package/.output/server/_tanstack-start-manifest_v-DxLIQ0cc.mjs +52 -0
  44. package/.output/server/drizzle/0002_remove_teams.sql +15 -0
  45. package/.output/server/drizzle/0003_add_loop_tags.sql +5 -0
  46. package/.output/server/drizzle/meta/_journal.json +14 -0
  47. package/.output/server/index.mjs +47 -96
  48. package/drizzle/0002_remove_teams.sql +15 -0
  49. package/drizzle/0003_add_loop_tags.sql +5 -0
  50. package/drizzle/meta/_journal.json +14 -0
  51. package/package.json +2 -2
  52. package/.output/public/assets/MachinesModal-ByHejech.js +0 -1
  53. package/.output/public/assets/SignIn-Cf4HOpdF.js +0 -1
  54. package/.output/public/assets/actionUi-yYVvoOTn.js +0 -1
  55. package/.output/public/assets/app-D5Hy4BcS.css +0 -2
  56. package/.output/public/assets/index-D504r3X9.js +0 -10
  57. package/.output/public/assets/invite._token-B0EKVyrU.js +0 -1
  58. package/.output/public/assets/invite._token-BSnGRyUw.js +0 -1
  59. package/.output/public/assets/lifecycleUi-C0DaC6NM.js +0 -1
  60. package/.output/public/assets/loops._loopId-j5EB2PLW.js +0 -67
  61. package/.output/public/assets/loops._loopId_.runs._runId-BICo_pRz.js +0 -3
  62. package/.output/public/assets/routes-4N6mrQK_.js +0 -1
  63. package/.output/public/assets/routes-DZU0Tqka.js +0 -1
  64. package/.output/public/assets/t._teamId-CAUjvMZ6.js +0 -1
  65. package/.output/public/assets/t._teamId-Cqzd69sO.js +0 -1
  66. package/.output/server/_ssr/DashboardView-DrKNkmcX.mjs +0 -867
  67. package/.output/server/_ssr/actionUi-Cf6DuEC2.mjs +0 -119
  68. package/.output/server/_ssr/artifacts-DOLHJHcd.mjs +0 -2
  69. package/.output/server/_ssr/boot-BIxtZHU-.mjs +0 -7466
  70. package/.output/server/_ssr/boot-D8cj4uZj.mjs +0 -2
  71. package/.output/server/_ssr/db-BphSJs66.mjs +0 -2
  72. package/.output/server/_ssr/invite._token-CPSvdDox.mjs +0 -27
  73. package/.output/server/_ssr/invite._token-CRBsTSTZ.mjs +0 -84
  74. package/.output/server/_ssr/invite._token-CaTLt92a.mjs +0 -20
  75. package/.output/server/_ssr/lifecycleUi-DauKavgx.mjs +0 -50
  76. package/.output/server/_ssr/logger-EinA2J6y.mjs +0 -2
  77. package/.output/server/_ssr/routes-CsV1weub.mjs +0 -26
  78. package/.output/server/_ssr/routes-fiMzFtcP.mjs +0 -39
  79. package/.output/server/_ssr/runDiff-BLdot9mi.mjs +0 -2
  80. package/.output/server/_ssr/store-CFCp_ggC.mjs +0 -2
  81. package/.output/server/_ssr/t._teamId-BYA4Dnjp.mjs +0 -43
  82. package/.output/server/_ssr/t._teamId-CKsrgN86.mjs +0 -32
  83. package/.output/server/_ssr/t._teamId-D1BTwhWf.mjs +0 -31
  84. package/.output/server/_ssr/teamCookie-B7hLOIie.mjs +0 -10
  85. package/.output/server/_ssr/teamFns-DfqtuBW2.mjs +0 -451
  86. package/.output/server/_ssr/teamFns-cI_tsiCv.mjs +0 -32
  87. package/.output/server/_ssr/tokens-CUz4LDLm.mjs +0 -2
  88. package/.output/server/_tanstack-start-manifest_v-xSxVtI1J.mjs +0 -86
@@ -0,0 +1,491 @@
1
+ import { o as __toESM } from "../_runtime.mjs";
2
+ import { g as require_react, h as require_jsx_runtime, s as TooltipProvider } from "../_libs/@base-ui/react+[...].mjs";
3
+ import { c as createFileRoute, d as useNavigate, f as useRouter, s as lazyRouteComponent } from "../_libs/@tanstack/react-router+[...].mjs";
4
+ import { O as useSession, _ as listLoops, a as PievoLogo, f as getAuthState, i as OpenModeWarning, n as GITHUB_URL, p as getConfig, r as GitHubIcon, v as loadOlderRuns, w as signOut, y as mintConnectKey } from "./auth-client-lSMb_Idt.mjs";
5
+ import { f as btnSm, y as focusRing } from "./actionUi-5HOCZnom.mjs";
6
+ import { c as mergeRuns, i as ModalHead, n as MachinesModal, o as daemonConnectCommand, r as Modal, s as listMachines, t as LoopOverview } from "./MachinesModal-BaEtzycr.mjs";
7
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-Cr-9yDEH.js
8
+ var import_react = /* @__PURE__ */ __toESM(require_react());
9
+ var import_jsx_runtime = require_jsx_runtime();
10
+ function LoopCard({ loop, onOpen, onPickRun }) {
11
+ const en = loop.enabled;
12
+ const [older, setOlder] = (0, import_react.useState)([]);
13
+ const runs = (0, import_react.useMemo)(() => older.length ? mergeRuns(loop.runs ?? [], older) : loop.runs ?? [], [loop.runs, older]);
14
+ const newestRun = runs.at(-1);
15
+ const latestIncidentRun = newestRun?.reportIncident ? newestRun : void 0;
16
+ const loadMore = async () => {
17
+ const oldest = runs[0];
18
+ if (!oldest) return 0;
19
+ const more = await loadOlderRuns({ data: {
20
+ loopId: loop.id,
21
+ beforeTs: oldest.ts,
22
+ limit: 16
23
+ } });
24
+ if (more.length) setOlder((prev) => mergeRuns(prev, more));
25
+ return more.length;
26
+ };
27
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
28
+ onClick: () => onOpen(loop.id),
29
+ className: `mb-[18px] cursor-pointer rounded-card border border-hairline bg-surface px-[26px] pb-5 pt-[22px] shadow-card transition-colors hover:border-wire ${en || latestIncidentRun?.reportIncident || loop.pauseCause?.kind === "failure-streak" || loop.pauseCause?.kind === "blocked" ? "" : "opacity-60"}`,
30
+ style: { animation: "fadeIn .25s cubic-bezier(0.25,0.1,0.25,1) both" },
31
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopOverview, {
32
+ loop,
33
+ runs,
34
+ onLoadMore: loadMore,
35
+ onPickRun: (run) => onPickRun(loop.id, run),
36
+ onOpen: () => onOpen(loop.id)
37
+ })
38
+ });
39
+ }
40
+ function LoopFilterBar({ options, selectedKey, onSelect }) {
41
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
42
+ className: "scrollbar-none -mx-1 overflow-x-auto px-1 pb-1",
43
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
44
+ role: "group",
45
+ "aria-label": "Loop filters",
46
+ className: "flex min-w-max items-center gap-1.5",
47
+ children: options.map((option) => {
48
+ const selected = option.key === selectedKey;
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
50
+ type: "button",
51
+ "aria-pressed": selected,
52
+ title: option.filter.kind === "tag" ? option.label : void 0,
53
+ onClick: (event) => {
54
+ event.currentTarget.scrollIntoView?.({
55
+ block: "nearest",
56
+ inline: "nearest"
57
+ });
58
+ onSelect(option.filter);
59
+ },
60
+ className: `inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-full border px-3 text-body font-medium transition-colors ${focusRing} ${selected ? "border-display bg-display text-paper" : "border-hairline bg-surface text-secondary hover:border-wire hover:bg-raised hover:text-primary"}`,
61
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
62
+ className: option.filter.kind === "tag" ? "max-w-44 truncate" : "",
63
+ children: option.label
64
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
65
+ className: selected ? "text-paper/70" : "text-disabled",
66
+ children: [
67
+ "(",
68
+ option.count,
69
+ ")"
70
+ ]
71
+ })]
72
+ }, option.key);
73
+ })
74
+ })
75
+ });
76
+ }
77
+ function ComposeModal({ open, onClose }) {
78
+ const [token, setToken] = (0, import_react.useState)(null);
79
+ const [config, setConfig] = (0, import_react.useState)(null);
80
+ const [copied, setCopied] = (0, import_react.useState)(false);
81
+ const [error, setError] = (0, import_react.useState)(null);
82
+ const [configError, setConfigError] = (0, import_react.useState)(false);
83
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
84
+ const command = token && config ? daemonConnectCommand(origin, token, config.pievoCli, config.customCli) : "";
85
+ (0, import_react.useEffect)(() => {
86
+ if (!open) return;
87
+ setToken(null);
88
+ setConfig(null);
89
+ setCopied(false);
90
+ setError(null);
91
+ setConfigError(false);
92
+ }, [open]);
93
+ (0, import_react.useEffect)(() => {
94
+ if (!open) return;
95
+ let active = true;
96
+ getConfig().then((value) => {
97
+ if (active) setConfig(value);
98
+ }).catch(() => {
99
+ if (active) setConfigError(true);
100
+ });
101
+ mintConnectKey().then((result) => {
102
+ if (!active) return;
103
+ if ("token" in result) setToken(result.token);
104
+ else setError(result.error);
105
+ }).catch(() => {
106
+ if (active) setError("could not mint a connect key");
107
+ });
108
+ return () => {
109
+ active = false;
110
+ };
111
+ }, [open]);
112
+ async function copyCommand() {
113
+ try {
114
+ await navigator.clipboard.writeText(command);
115
+ setCopied(true);
116
+ setTimeout(() => setCopied(false), 1500);
117
+ } catch {
118
+ setError("could not copy - select the command and copy manually");
119
+ }
120
+ }
121
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Modal, {
122
+ open,
123
+ onClose,
124
+ children: [
125
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHead, { title: "New loop" }),
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
127
+ className: "mt-6",
128
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Step, {
129
+ number: "1",
130
+ continued: true,
131
+ title: "Install and connect the daemon",
132
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
133
+ className: "mt-1.5 text-body leading-snug text-secondary",
134
+ children: "Run this command in your terminal. It connects the daemon and installs the Pievo skill."
135
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
136
+ className: "mt-3 flex min-w-0 items-start gap-2",
137
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
138
+ className: "min-w-0 flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-4 font-mono text-label leading-relaxed text-paper",
139
+ children: command || (configError ? "Could not load the connection command. Close and try again." : token ? "Loading CLI configuration…" : "Minting a connect key…")
140
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
141
+ className: btnSm,
142
+ onClick: () => void copyCommand(),
143
+ disabled: !command,
144
+ children: copied ? "Copied ✓" : "Copy"
145
+ })]
146
+ })]
147
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Step, {
148
+ number: "2",
149
+ title: "Start a new session",
150
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
151
+ className: "mt-1.5 text-body leading-snug text-secondary",
152
+ children: "After the command finishes, start a new session in the project where the loop should run, then manually invoke the Pievo skill:"
153
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
154
+ className: "mt-3 space-y-2 rounded-control border border-hairline bg-raised p-4 text-body text-display",
155
+ children: [
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkillCommand, {
157
+ agent: "Claude Code",
158
+ command: "/pievo Create a Pievo loop."
159
+ }),
160
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkillCommand, {
161
+ agent: "Codex",
162
+ command: "$pievo Create a Pievo loop."
163
+ }),
164
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SkillCommand, {
165
+ agent: "Pi",
166
+ command: "/skill:pievo Create a Pievo loop."
167
+ })
168
+ ]
169
+ })]
170
+ })]
171
+ }),
172
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
173
+ className: "mt-4 text-body text-accent",
174
+ children: ["Error: ", error]
175
+ })
176
+ ]
177
+ });
178
+ }
179
+ function SkillCommand({ agent, command }) {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
181
+ className: "flex flex-wrap items-baseline gap-x-3 gap-y-1",
182
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
183
+ className: "w-24 shrink-0 text-label font-medium text-secondary",
184
+ children: agent
185
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
186
+ className: "font-mono text-label font-medium text-display",
187
+ children: command
188
+ })]
189
+ });
190
+ }
191
+ function Step({ number, title, continued = false, children }) {
192
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
193
+ className: "flex gap-3.5",
194
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
195
+ className: "flex flex-col items-center",
196
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
197
+ className: "flex size-5 shrink-0 items-center justify-center rounded-full border border-display text-micro font-medium leading-none text-display",
198
+ children: number
199
+ }), continued && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-px flex-1 bg-hairline" })]
200
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
201
+ className: continued ? "min-w-0 flex-1 pb-7" : "min-w-0 flex-1",
202
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", {
203
+ className: "text-label font-semibold text-display",
204
+ children: title
205
+ }), children]
206
+ })]
207
+ });
208
+ }
209
+ function loopFilterKey(filter) {
210
+ return filter.kind === "tag" ? `tag:${filter.tag}` : filter.kind;
211
+ }
212
+ function loopFilterOptions(loops) {
213
+ const active = loops.filter((loop) => loop.enabled && !loop.deleteRequestedAt).length;
214
+ const paused = loops.filter((loop) => !loop.enabled && !loop.deleteRequestedAt).length;
215
+ const blocked = loops.filter((loop) => !loop.enabled && !loop.deleteRequestedAt && loop.pauseCause?.kind === "blocked").length;
216
+ const tagCounts = /* @__PURE__ */ new Map();
217
+ for (const loop of loops) for (const tag of new Set(loop.tags)) tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
218
+ return [
219
+ {
220
+ key: "all",
221
+ label: "All Loops",
222
+ count: loops.length,
223
+ filter: { kind: "all" }
224
+ },
225
+ {
226
+ key: "active",
227
+ label: "Active",
228
+ count: active,
229
+ filter: { kind: "active" }
230
+ },
231
+ {
232
+ key: "paused",
233
+ label: "Paused",
234
+ count: paused,
235
+ filter: { kind: "paused" }
236
+ },
237
+ {
238
+ key: "blocked",
239
+ label: "Blocked",
240
+ count: blocked,
241
+ filter: { kind: "blocked" }
242
+ },
243
+ ...[...tagCounts].sort(([a], [b]) => a.localeCompare(b, "en-US")).map(([tag, count]) => ({
244
+ key: `tag:${tag}`,
245
+ label: tag,
246
+ count,
247
+ filter: {
248
+ kind: "tag",
249
+ tag
250
+ }
251
+ }))
252
+ ];
253
+ }
254
+ function filterLoops(loops, filter) {
255
+ switch (filter.kind) {
256
+ case "all": return loops;
257
+ case "active": return loops.filter((loop) => loop.enabled && !loop.deleteRequestedAt);
258
+ case "paused": return loops.filter((loop) => !loop.enabled && !loop.deleteRequestedAt);
259
+ case "blocked": return loops.filter((loop) => !loop.enabled && !loop.deleteRequestedAt && loop.pauseCause?.kind === "blocked");
260
+ case "tag": return loops.filter((loop) => loop.tags.includes(filter.tag));
261
+ }
262
+ }
263
+ /** Loops and machines change between polls. Authorization is derived server-side
264
+ * from the current session; clients do not send tenant identifiers. */
265
+ async function fetchLiveData() {
266
+ const [loops, machines] = await Promise.all([listLoops(), listMachines()]);
267
+ return {
268
+ loops,
269
+ machines
270
+ };
271
+ }
272
+ function DashboardView({ initial, mode }) {
273
+ const [live, setLive] = (0, import_react.useState)(null);
274
+ const { loops, machines } = live ?? initial;
275
+ const online = machines.filter((m) => m.online).length;
276
+ const navigate = useNavigate();
277
+ const router = useRouter();
278
+ const { data: session } = useSession();
279
+ const [signingOut, setSigningOut] = (0, import_react.useState)(false);
280
+ const [composeOpen, setComposeOpen] = (0, import_react.useState)(false);
281
+ const [machinesOpen, setMachinesOpen] = (0, import_react.useState)(false);
282
+ const [filter, setFilter] = (0, import_react.useState)({ kind: "all" });
283
+ async function logout() {
284
+ setSigningOut(true);
285
+ try {
286
+ await signOut();
287
+ await navigate({ to: "/" });
288
+ await router.invalidate();
289
+ } finally {
290
+ setSigningOut(false);
291
+ }
292
+ }
293
+ const refetch = (0, import_react.useCallback)(async () => {
294
+ try {
295
+ setLive(await fetchLiveData());
296
+ } catch {}
297
+ }, []);
298
+ const openRef = (0, import_react.useRef)(false);
299
+ openRef.current = composeOpen || machinesOpen;
300
+ const anyRunning = loops.some((j) => j.running);
301
+ (0, import_react.useEffect)(() => {
302
+ const t = setInterval(() => {
303
+ if (!openRef.current) refetch();
304
+ }, anyRunning ? 3e3 : 1e4);
305
+ return () => clearInterval(t);
306
+ }, [refetch, anyRunning]);
307
+ const filterOptions = (0, import_react.useMemo)(() => loopFilterOptions(loops), [loops]);
308
+ const selectedFilterKey = loopFilterKey(filter);
309
+ const filteredLoops = (0, import_react.useMemo)(() => filterLoops(loops, filter), [loops, filter]);
310
+ (0, import_react.useEffect)(() => {
311
+ if (filter.kind === "tag" && !filterOptions.some((option) => option.key === selectedFilterKey)) setFilter({ kind: "all" });
312
+ }, [
313
+ filter,
314
+ filterOptions,
315
+ selectedFilterKey
316
+ ]);
317
+ const cardProps = () => ({
318
+ onOpen: (id) => void navigate({
319
+ to: "/loops/$loopId",
320
+ params: { loopId: id }
321
+ }),
322
+ onPickRun: (loopId, run) => void navigate({
323
+ to: "/loops/$loopId/runs/$runId",
324
+ params: {
325
+ loopId,
326
+ runId: run.id
327
+ }
328
+ })
329
+ });
330
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TooltipProvider, {
331
+ delay: 120,
332
+ children: [
333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", {
334
+ className: "glass glass-bar sticky top-0 z-50",
335
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
336
+ className: "mx-auto flex max-w-[1180px] items-center gap-2 px-4 py-2.5 sm:gap-3 sm:px-8",
337
+ children: [
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
339
+ className: "shrink-0",
340
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PievoLogo, { size: 30 })
341
+ }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
343
+ className: `shrink-0 text-[18px] font-semibold tracking-[-0.015em] text-display ${mode === "auth" ? "hidden sm:inline" : ""}`,
344
+ children: "Pievo"
345
+ }),
346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex-1" }),
347
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
348
+ href: GITHUB_URL,
349
+ target: "_blank",
350
+ rel: "noreferrer",
351
+ "aria-label": "GitHub repository",
352
+ title: "GitHub",
353
+ className: `${headerIconBtn} hidden sm:inline-flex`,
354
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitHubIcon, { className: "size-[17px]" })
355
+ }),
356
+ mode === "auth" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
357
+ className: "flex shrink-0 items-center gap-2",
358
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
359
+ className: "hidden max-w-48 truncate text-label text-secondary md:inline",
360
+ title: session?.user.email ?? session?.user.name ?? "Account",
361
+ children: session?.user.email ?? session?.user.name ?? "Account"
362
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
363
+ onClick: () => void logout(),
364
+ disabled: signingOut,
365
+ className: headerBtn,
366
+ children: signingOut ? "Signing out…" : "Sign out"
367
+ })]
368
+ }),
369
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
370
+ onClick: () => setMachinesOpen(true),
371
+ "aria-label": `${online} ${online === 1 ? "machine" : "machines"} online`,
372
+ className: `${headerBtn} gap-1.5 px-2 sm:px-3`,
373
+ children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `inline-block size-1.5 rounded-full ${online ? "bg-rubik-green" : "bg-disabled"}` }),
375
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
376
+ className: "sm:hidden",
377
+ children: online
378
+ }),
379
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
380
+ className: "hidden sm:inline",
381
+ children: [
382
+ online,
383
+ " ",
384
+ online === 1 ? "machine" : "machines",
385
+ " online"
386
+ ]
387
+ })
388
+ ]
389
+ }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
391
+ onClick: () => setComposeOpen(true),
392
+ className: "inline-flex shrink-0 cursor-pointer items-center rounded-full bg-display px-3.5 py-1.5 text-meta font-medium text-paper transition-opacity hover:opacity-85",
393
+ children: "New Loop"
394
+ })
395
+ ]
396
+ })
397
+ }),
398
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", {
399
+ className: "mx-auto max-w-[1180px] px-8 pb-24",
400
+ children: [
401
+ mode === "open" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpenModeWarning, { className: "mt-6" }),
402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
403
+ className: "pb-2 pt-14 text-center",
404
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
405
+ className: "font-pixel text-[clamp(28px,4.5vw,38px)] leading-[1.15] text-display",
406
+ children: "What should happen while you sleep?"
407
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
408
+ className: "mt-7",
409
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
410
+ onClick: () => setComposeOpen(true),
411
+ className: "inline-flex cursor-pointer items-center gap-1.5 rounded-full bg-display px-6 py-2.5 text-body font-medium text-paper transition-opacity hover:opacity-85",
412
+ children: ["Start a new loop ", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
413
+ "aria-hidden": true,
414
+ children: "→"
415
+ })]
416
+ })
417
+ })]
418
+ }),
419
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
420
+ className: "mb-5 mt-12",
421
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopFilterBar, {
422
+ options: filterOptions,
423
+ selectedKey: selectedFilterKey,
424
+ onSelect: setFilter
425
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
426
+ className: "sr-only",
427
+ "aria-live": "polite",
428
+ children: [
429
+ "Showing ",
430
+ filteredLoops.length,
431
+ " loops"
432
+ ]
433
+ })]
434
+ }),
435
+ filteredLoops.length ? filteredLoops.map((j) => /* @__PURE__ */ (0, import_react.createElement)(LoopCard, {
436
+ loop: j,
437
+ ...cardProps(),
438
+ key: j.id
439
+ })) : loops.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
440
+ className: "py-16 text-center",
441
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
442
+ className: "text-[15px] text-secondary",
443
+ children: "No loops match this filter"
444
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
445
+ type: "button",
446
+ onClick: () => setFilter({ kind: "all" }),
447
+ className: "mt-2 text-body font-medium text-interactive hover:underline",
448
+ children: "Show all loops"
449
+ })]
450
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
451
+ className: "py-16 text-center",
452
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
453
+ className: "text-[15px] text-secondary",
454
+ children: "No loops yet"
455
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
456
+ className: "mt-1.5 text-body text-disabled",
457
+ children: "Create a scheduled prompt for a connected machine."
458
+ })]
459
+ })
460
+ ]
461
+ }),
462
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposeModal, {
463
+ open: composeOpen,
464
+ onClose: () => setComposeOpen(false)
465
+ }),
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MachinesModal, {
467
+ open: machinesOpen,
468
+ onClose: () => setMachinesOpen(false)
469
+ })
470
+ ]
471
+ });
472
+ }
473
+ 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";
474
+ var headerIconBtn = "shrink-0 cursor-pointer items-center rounded-full p-1.5 text-secondary transition-colors hover:bg-raised hover:text-display";
475
+ var $$splitErrorComponentImporter = () => import("./routes-DRBS4Zi4.mjs");
476
+ var $$splitComponentImporter = () => import("./routes-DTBltabU.mjs");
477
+ /** The dashboard route. Auth mode shows sign-in before loading owner-scoped data;
478
+ * open mode renders the server's shared administrative workspace. */
479
+ var Route = createFileRoute("/")({
480
+ ssr: false,
481
+ loader: async () => {
482
+ return {
483
+ auth: await getAuthState(),
484
+ initial: await fetchLiveData()
485
+ };
486
+ },
487
+ component: lazyRouteComponent($$splitComponentImporter, "component"),
488
+ errorComponent: lazyRouteComponent($$splitErrorComponentImporter, "errorComponent")
489
+ });
490
+ //#endregion
491
+ export { Route as n, DashboardView as t };
@@ -1,15 +1,10 @@
1
1
  import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
2
  import { f as useRouter } from "../_libs/@tanstack/react-router+[...].mjs";
3
- import { r as LoadErrorCard } from "./actionUi-Cf6DuEC2.mjs";
4
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-FO0MFfYK.js
3
+ import { i as LoadErrorCard } from "./actionUi-5HOCZnom.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-DRBS4Zi4.js
5
5
  var import_jsx_runtime = require_jsx_runtime();
6
- /**
7
- * The home route. Under the auth gate it is now a THIN redirect to the explicit
8
- * team URL (`/t/<lastUsed|personal>`) so the dashboard's team lives in the path
9
- * (bookmarkable, multi-tab). `/` keeps working forever: a signed-out visitor gets
10
- * the sign-in CTA; open mode (no gate ⇒ a single shared workspace with no team to
11
- * expose in the URL) renders the dashboard right here, unchanged.
12
- */
6
+ /** The dashboard route. Auth mode shows sign-in before loading owner-scoped data;
7
+ * open mode renders the server's shared administrative workspace. */
13
8
  /** First-load failure screen — a calm retry instead of the router's default
14
9
  * error dump. Only the initial loader can land here; the in-page poll is
15
10
  * fetch-then-set and keeps stale data on a transient blip. */
@@ -0,0 +1,27 @@
1
+ import { h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
+ import { O as useSession } from "./auth-client-lSMb_Idt.mjs";
3
+ import { a as Loading } from "./actionUi-5HOCZnom.mjs";
4
+ import { t as SignIn } from "./SignIn-sHQaBQJC.mjs";
5
+ import { n as Route, t as DashboardView } from "./routes-Cr-9yDEH.mjs";
6
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-DTBltabU.js
7
+ var import_jsx_runtime = require_jsx_runtime();
8
+ /** The dashboard route. Auth mode shows sign-in before loading owner-scoped data;
9
+ * open mode renders the server's shared administrative workspace. */
10
+ /** First-load failure screen — a calm retry instead of the router's default
11
+ * error dump. Only the initial loader can land here; the in-page poll is
12
+ * fetch-then-set and keeps stale data on a transient blip. */
13
+ function Home() {
14
+ const loaded = Route.useLoaderData();
15
+ const { data: session, isPending } = useSession();
16
+ if (loaded.auth.enabled && isPending) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", {
17
+ className: "mx-auto max-w-[1180px] px-8 pt-12",
18
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Loading, {})
19
+ });
20
+ if (loaded.auth.enabled && !session) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SignIn, {});
21
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DashboardView, {
22
+ initial: loaded.initial,
23
+ mode: loaded.auth.enabled ? "auth" : "open"
24
+ });
25
+ }
26
+ //#endregion
27
+ export { Home as component };