@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.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/SignIn-CIFwnZtF.js +1 -0
- package/.output/public/assets/{ui-s5IMg6RF.js → actionUi-5PtES4q0.js} +1 -1
- package/.output/public/assets/app-DvHMhs7S.css +2 -0
- package/.output/public/assets/index-CRX2pu0W.js +10 -0
- package/.output/public/assets/loops._loopId-BsuV-Rmf.js +67 -0
- package/.output/public/assets/loops._loopId_.runs._runId-DpK_fzmZ.js +3 -0
- package/.output/public/assets/{preload-helper-Bs7oCAsw.js → preload-helper-sAZOZb3G.js} +3 -3
- package/.output/public/assets/routes-Dm_3J2aV.js +1 -0
- package/.output/public/assets/routes-DxF_s3cD.js +1 -0
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
- package/.output/server/_ssr/{MachinesModal-BhRw7oOx.mjs → MachinesModal-BaEtzycr.mjs} +24 -57
- package/.output/server/_ssr/{SignIn-BhoZIOUp.mjs → SignIn-sHQaBQJC.mjs} +3 -3
- package/.output/server/_ssr/{ui-DGz-q9MT.mjs → actionUi-5HOCZnom.mjs} +115 -4
- package/.output/server/_ssr/{artifactFiles-ChuJ4PzC.mjs → artifactFiles-DO43wwXA.mjs} +4 -3
- package/.output/server/_ssr/{artifactKind-DXumOv7c.mjs → artifactKind-DwDr8IYc.mjs} +6 -14
- package/.output/server/_ssr/artifacts-Cd7Qx3Qp.mjs +2 -0
- package/.output/server/_ssr/{auth-LwPp_iim.mjs → auth-0AamrwHo.mjs} +44 -124
- package/.output/server/_ssr/{SocialLinks-DVCLmql0.mjs → auth-client-lSMb_Idt.mjs} +143 -109
- package/.output/server/_ssr/boot-C472kLwY.mjs +3947 -0
- package/.output/server/_ssr/{bun-sqlite-dialect-BW9W1_Ps-CHMDkKqA.mjs → bun-sqlite-dialect-BW9W1_Ps-DLIXocA0.mjs} +2 -2
- package/.output/server/_ssr/{d1-sqlite-dialect-BLC8LXE6-DYum6qky.mjs → d1-sqlite-dialect-BLC8LXE6-BoFMIPr_.mjs} +2 -2
- package/.output/server/_ssr/db-BzvMQ2kx.mjs +2 -0
- package/.output/server/_ssr/{dist-bWqs5sTy.mjs → dist-ClzqkwxD.mjs} +2 -2
- package/.output/server/_ssr/{factory-pBwrjVTI.mjs → factory-ixUjZqJn.mjs} +2 -2
- package/.output/server/_ssr/{kysely-adapter-DMf5pFTf.mjs → kysely-adapter-DkZbmKgV.mjs} +1 -1
- package/.output/server/_ssr/logger-DDjsYB2X.mjs +2 -0
- package/.output/server/_ssr/{loopApi-Im6JSK0p.mjs → loopApi-DT751TJA.mjs} +30 -90
- package/.output/server/_ssr/{loopProjection-DIpGR6rp.mjs → loopProjection-qaD2I48a.mjs} +5 -2
- package/.output/server/_ssr/loopTags-CXx5UdGf.mjs +3356 -0
- package/.output/server/_ssr/{loops._loopId-B5iPseDG.mjs → loops._loopId-CXgw2Rz1.mjs} +144 -46
- package/.output/server/_ssr/{loops._loopId_.runs._runId-DVtG0xYb.mjs → loops._loopId_.runs._runId-Dk94Z0Jq.mjs} +6 -13
- package/.output/server/_ssr/{loops._loopId_.runs._runId-BA-P6sGA.mjs → loops._loopId_.runs._runId-SASSqOfy.mjs} +31 -23
- package/.output/server/_ssr/{machineFns-Bb9KNXun.mjs → machineFns-BSrIgn3f.mjs} +42 -108
- package/.output/server/_ssr/{node-sqlite-dialect-Dho9YjXb.mjs → node-sqlite-dialect-BbUqnnYv.mjs} +2 -2
- package/.output/server/_ssr/{router-C8iotXtk.mjs → router-BlLlhfJe.mjs} +26 -40
- package/.output/server/_ssr/routes-Cr-9yDEH.mjs +491 -0
- package/.output/server/_ssr/{routes-FO0MFfYK.mjs → routes-DRBS4Zi4.mjs} +4 -9
- package/.output/server/_ssr/routes-DTBltabU.mjs +27 -0
- package/.output/server/_ssr/ssr.mjs +28 -88
- package/.output/server/_ssr/store-vDZ9INSa.mjs +2 -0
- package/.output/server/_ssr/tokens-BHiCElYD.mjs +2 -0
- package/.output/server/_tanstack-start-manifest_v-DxLIQ0cc.mjs +52 -0
- package/.output/server/drizzle/0002_remove_teams.sql +15 -0
- package/.output/server/drizzle/0003_add_loop_tags.sql +5 -0
- package/.output/server/drizzle/meta/_journal.json +14 -0
- package/.output/server/index.mjs +47 -96
- package/drizzle/0002_remove_teams.sql +15 -0
- package/drizzle/0003_add_loop_tags.sql +5 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +2 -2
- package/.output/public/assets/MachinesModal-ByHejech.js +0 -1
- package/.output/public/assets/SignIn-Cf4HOpdF.js +0 -1
- package/.output/public/assets/actionUi-yYVvoOTn.js +0 -1
- package/.output/public/assets/app-D5Hy4BcS.css +0 -2
- package/.output/public/assets/index-D504r3X9.js +0 -10
- package/.output/public/assets/invite._token-B0EKVyrU.js +0 -1
- package/.output/public/assets/invite._token-BSnGRyUw.js +0 -1
- package/.output/public/assets/lifecycleUi-C0DaC6NM.js +0 -1
- package/.output/public/assets/loops._loopId-j5EB2PLW.js +0 -67
- package/.output/public/assets/loops._loopId_.runs._runId-BICo_pRz.js +0 -3
- package/.output/public/assets/routes-4N6mrQK_.js +0 -1
- package/.output/public/assets/routes-DZU0Tqka.js +0 -1
- package/.output/public/assets/t._teamId-CAUjvMZ6.js +0 -1
- package/.output/public/assets/t._teamId-Cqzd69sO.js +0 -1
- package/.output/server/_ssr/DashboardView-DrKNkmcX.mjs +0 -867
- package/.output/server/_ssr/actionUi-Cf6DuEC2.mjs +0 -119
- package/.output/server/_ssr/artifacts-DOLHJHcd.mjs +0 -2
- package/.output/server/_ssr/boot-BIxtZHU-.mjs +0 -7466
- package/.output/server/_ssr/boot-D8cj4uZj.mjs +0 -2
- package/.output/server/_ssr/db-BphSJs66.mjs +0 -2
- package/.output/server/_ssr/invite._token-CPSvdDox.mjs +0 -27
- package/.output/server/_ssr/invite._token-CRBsTSTZ.mjs +0 -84
- package/.output/server/_ssr/invite._token-CaTLt92a.mjs +0 -20
- package/.output/server/_ssr/lifecycleUi-DauKavgx.mjs +0 -50
- package/.output/server/_ssr/logger-EinA2J6y.mjs +0 -2
- package/.output/server/_ssr/routes-CsV1weub.mjs +0 -26
- package/.output/server/_ssr/routes-fiMzFtcP.mjs +0 -39
- package/.output/server/_ssr/runDiff-BLdot9mi.mjs +0 -2
- package/.output/server/_ssr/store-CFCp_ggC.mjs +0 -2
- package/.output/server/_ssr/t._teamId-BYA4Dnjp.mjs +0 -43
- package/.output/server/_ssr/t._teamId-CKsrgN86.mjs +0 -32
- package/.output/server/_ssr/t._teamId-D1BTwhWf.mjs +0 -31
- package/.output/server/_ssr/teamCookie-B7hLOIie.mjs +0 -10
- package/.output/server/_ssr/teamFns-DfqtuBW2.mjs +0 -451
- package/.output/server/_ssr/teamFns-cI_tsiCv.mjs +0 -32
- package/.output/server/_ssr/tokens-CUz4LDLm.mjs +0 -2
- 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 {
|
|
4
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/routes-
|
|
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
|
-
*
|
|
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 };
|