@kky42/pievo-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +17 -0
- package/.output/public/assets/CodeField-dOzyFQNH.js +34 -0
- package/.output/public/assets/LoopView-B4H9QibC.js +55 -0
- package/.output/public/assets/Modal-D33gNSgx.js +1 -0
- package/.output/public/assets/SignIn-SHuRRyOv.js +1 -0
- package/.output/public/assets/actionUi-ChGGALzg.js +1 -0
- package/.output/public/assets/app-DElSo_jy.css +2 -0
- package/.output/public/assets/artifactView-DFuubXLJ.js +66 -0
- package/.output/public/assets/index-DfpTWRSz.js +12 -0
- package/.output/public/assets/invite._token-DJtd-XE2.js +1 -0
- package/.output/public/assets/invite._token-T8oo4Qtw.js +1 -0
- package/.output/public/assets/jsx-runtime-BseJUIpC.js +1 -0
- package/.output/public/assets/lifecycleUi-DKkChdnU.js +1 -0
- package/.output/public/assets/loopApi-BM2nj71x.js +3 -0
- package/.output/public/assets/loops._loopId-B19Jw7jC.js +5 -0
- package/.output/public/assets/loops._loopId_.runs._runId-_CflHV38.js +3 -0
- package/.output/public/assets/notifyFns-DCubjpRy.js +1 -0
- package/.output/public/assets/preload-helper-CKUiEq3b.js +3 -0
- package/.output/public/assets/routes-B9tgli5f.js +1 -0
- package/.output/public/assets/routes-CTtlM_qt.js +1 -0
- package/.output/public/assets/t._teamId-Bm21mngW.js +1 -0
- package/.output/public/assets/t._teamId-gR7BVKkR.js +1 -0
- package/.output/public/assets/ui-Dp88qUWh.js +1 -0
- package/.output/public/assets/useRouter-DsjH8G0p.js +1 -0
- package/.output/public/favicon.svg +12 -0
- package/.output/public/fonts/GeistPixel-Square.woff2 +0 -0
- package/.output/server/_chunks/ssr-renderer.mjs +26 -0
- package/.output/server/_libs/@aws-crypto/crc32+[...].mjs +419 -0
- package/.output/server/_libs/@aws-sdk/checksums+[...].mjs +10732 -0
- package/.output/server/_libs/@aws-sdk/client-s3+[...].mjs +9475 -0
- package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +137 -0
- package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +440 -0
- package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +62 -0
- package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +818 -0
- package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +59 -0
- package/.output/server/_libs/@base-ui/react+[...].mjs +11125 -0
- package/.output/server/_libs/@codemirror/autocomplete+[...].mjs +19713 -0
- package/.output/server/_libs/@codemirror/lang-css+[...].mjs +2636 -0
- package/.output/server/_libs/@codemirror/lang-html+[...].mjs +2247 -0
- package/.output/server/_libs/@codemirror/lang-json+[...].mjs +79 -0
- package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1736 -0
- package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +342 -0
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +14300 -0
- package/.output/server/_libs/@uiw/codemirror-extensions-basic-setup+[...].mjs +76 -0
- package/.output/server/_libs/atomic-sleep.mjs +27 -0
- package/.output/server/_libs/aws-crypto__crc32c.mjs +314 -0
- package/.output/server/_libs/aws-sdk__nested-clients.mjs +2671 -0
- package/.output/server/_libs/babel__runtime.mjs +30 -0
- package/.output/server/_libs/clsx.mjs +16 -0
- package/.output/server/_libs/codemirror__commands.mjs +1725 -0
- package/.output/server/_libs/codemirror__lint.mjs +565 -0
- package/.output/server/_libs/codemirror__search.mjs +1138 -0
- package/.output/server/_libs/codemirror__theme-one-dark.mjs +161 -0
- package/.output/server/_libs/colorette.mjs +129 -0
- package/.output/server/_libs/croner.mjs +735 -0
- package/.output/server/_libs/d3-array.mjs +231 -0
- package/.output/server/_libs/d3-color.mjs +330 -0
- package/.output/server/_libs/d3-format.mjs +252 -0
- package/.output/server/_libs/d3-interpolate.mjs +163 -0
- package/.output/server/_libs/d3-path.mjs +77 -0
- package/.output/server/_libs/d3-scale+[...].mjs +1907 -0
- package/.output/server/_libs/d3-shape.mjs +689 -0
- package/.output/server/_libs/dateformat.mjs +341 -0
- package/.output/server/_libs/decimal.js-light.mjs +884 -0
- package/.output/server/_libs/diff.mjs +732 -0
- package/.output/server/_libs/dom-serializer+[...].mjs +708 -0
- package/.output/server/_libs/domhandler.mjs +461 -0
- package/.output/server/_libs/dompurify.mjs +2111 -0
- package/.output/server/_libs/domutils.mjs +868 -0
- package/.output/server/_libs/drizzle-orm+postgres.mjs +7689 -0
- package/.output/server/_libs/electric-sql__pglite.mjs +14674 -0
- package/.output/server/_libs/end-of-stream+once+wrappy.mjs +145 -0
- package/.output/server/_libs/es-toolkit.mjs +1737 -0
- package/.output/server/_libs/eventemitter3.mjs +236 -0
- package/.output/server/_libs/fast-copy.mjs +285 -0
- package/.output/server/_libs/fast-safe-stringify.mjs +172 -0
- package/.output/server/_libs/h3+rou3+srvx.mjs +1201 -0
- package/.output/server/_libs/html-dom-parser+htmlparser2.mjs +1560 -0
- package/.output/server/_libs/html-react-parser+[...].mjs +1360 -0
- package/.output/server/_libs/initdb.wasm +0 -0
- package/.output/server/_libs/marked.mjs +1548 -0
- package/.output/server/_libs/on-exit-leak-free.mjs +80 -0
- package/.output/server/_libs/pglite.data +37667 -8
- package/.output/server/_libs/pglite.wasm +0 -0
- package/.output/server/_libs/pino+[...].mjs +3196 -0
- package/.output/server/_libs/pino-abstract-transport+split2.mjs +194 -0
- package/.output/server/_libs/pino-pretty+[...].mjs +1623 -0
- package/.output/server/_libs/pinojs__redact.mjs +280 -0
- package/.output/server/_libs/react-redux+[...].mjs +205 -0
- package/.output/server/_libs/recharts+victory-vendor.mjs +15875 -0
- package/.output/server/_libs/tanstack__history.mjs +342 -0
- package/.output/server/_libs/ufo.mjs +64 -0
- package/.output/server/_libs/uiw__codemirror-themes.mjs +32 -0
- package/.output/server/_libs/uiw__react-codemirror.mjs +354 -0
- package/.output/server/_runtime.mjs +37 -0
- package/.output/server/_ssr/CodeField-tm4rr6G3.mjs +143 -0
- package/.output/server/_ssr/DashboardView-CC7htv28.mjs +2795 -0
- package/.output/server/_ssr/LoopPlaybook-BXH8mhiX.mjs +2105 -0
- package/.output/server/_ssr/LoopView-DCugEbHx.mjs +1106 -0
- package/.output/server/_ssr/Modal-DpKZHLZK.mjs +49 -0
- package/.output/server/_ssr/SignIn-dTndU6Hw.mjs +67 -0
- package/.output/server/_ssr/actionUi-CZbEixbf.mjs +119 -0
- package/.output/server/_ssr/adapters-BS8XosjF.mjs +130 -0
- package/.output/server/_ssr/artifactFiles-Cagtj7J0.mjs +61 -0
- package/.output/server/_ssr/artifactKind-BW0isV8L.mjs +37 -0
- package/.output/server/_ssr/artifactView-DS4O22wl.mjs +304 -0
- package/.output/server/_ssr/artifacts-DngKyW2u.mjs +2 -0
- package/.output/server/_ssr/auth-DY1DuYZd.mjs +38429 -0
- package/.output/server/_ssr/boot-BbtG0ImW.mjs +9010 -0
- package/.output/server/_ssr/boot-CMHTxQpJ.mjs +2 -0
- package/.output/server/_ssr/bun-sqlite-dialect-BW9W1_Ps-CU1Spd6z.mjs +162 -0
- package/.output/server/_ssr/core-RrmWoKne.mjs +5 -0
- package/.output/server/_ssr/createServerRpc-BD8Xn_0_.mjs +12 -0
- package/.output/server/_ssr/d1-sqlite-dialect-BLC8LXE6-DfG7tB8s.mjs +112 -0
- package/.output/server/_ssr/db-DWAuZq1o.mjs +2 -0
- package/.output/server/_ssr/dist-BIxFFVZg.mjs +342 -0
- package/.output/server/_ssr/empty-plugin-adapters-DKUlnwwl.mjs +5 -0
- package/.output/server/_ssr/factory-Blq0DYfT.mjs +6903 -0
- package/.output/server/_ssr/invite._token-BRCo9LGB.mjs +36 -0
- package/.output/server/_ssr/invite._token-DJxGLILJ.mjs +28 -0
- package/.output/server/_ssr/invite._token-NewFt27g.mjs +92 -0
- package/.output/server/_ssr/kysely-adapter-D3XTe64J.mjs +2 -0
- package/.output/server/_ssr/kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs +19 -0
- package/.output/server/_ssr/lifecycleUi-C9lg1r3r.mjs +38 -0
- package/.output/server/_ssr/logger-Dw82jNjH.mjs +2 -0
- package/.output/server/_ssr/loopApi-BtfkZQYK.mjs +532 -0
- package/.output/server/_ssr/loopApi-Cxe8WyOB.mjs +105 -0
- package/.output/server/_ssr/loops._loopId-7NQJPB9W.mjs +30 -0
- package/.output/server/_ssr/loops._loopId-DhnArGdL.mjs +1635 -0
- package/.output/server/_ssr/loops._loopId_.runs._runId-Bvuo2nki.mjs +29 -0
- package/.output/server/_ssr/loops._loopId_.runs._runId-Dip5Xk-q.mjs +674 -0
- package/.output/server/_ssr/machineFns-Dvr5ICUy.mjs +266 -0
- package/.output/server/_ssr/node-sqlite-dialect-DhyOpJTX.mjs +162 -0
- package/.output/server/_ssr/notifyFns-BcMRY5kP.mjs +118 -0
- package/.output/server/_ssr/notifyFns-Q458pZmE.mjs +580 -0
- package/.output/server/_ssr/router-J8KZ30xw.mjs +678 -0
- package/.output/server/_ssr/routes-Bcs4T1ox.mjs +28 -0
- package/.output/server/_ssr/routes-BoGrcf-b.mjs +43 -0
- package/.output/server/_ssr/routes-D4am3Zff.mjs +28 -0
- package/.output/server/_ssr/runDiff-CpEFqo7G.mjs +113 -0
- package/.output/server/_ssr/ssr.mjs +5837 -0
- package/.output/server/_ssr/start-4ifArtKx.mjs +4 -0
- package/.output/server/_ssr/store-b3JcQ08F.mjs +2 -0
- package/.output/server/_ssr/t._teamId-CeUhzgzT.mjs +32 -0
- package/.output/server/_ssr/t._teamId-DR-hQK7o.mjs +47 -0
- package/.output/server/_ssr/t._teamId-Dy_McbRt.mjs +31 -0
- package/.output/server/_ssr/teamCookie-B7hLOIie.mjs +10 -0
- package/.output/server/_ssr/teamFns-BIDnsg2A.mjs +473 -0
- package/.output/server/_ssr/teamFns-DA4ovI5g.mjs +33 -0
- package/.output/server/_ssr/tokens-ytd60FUt.mjs +2 -0
- package/.output/server/_ssr/ui-Dej2qjuS.mjs +267 -0
- package/.output/server/_tanstack-start-manifest_v-CVS6c7re.mjs +95 -0
- package/.output/server/drizzle/0000_round_marauders.sql +193 -0
- package/.output/server/drizzle/0001_naive_silver_fox.sql +25 -0
- package/.output/server/drizzle/0002_funny_sage.sql +12 -0
- package/.output/server/drizzle/0003_optimal_slapstick.sql +102 -0
- package/.output/server/drizzle/0004_remove_grok_agent.sql +5 -0
- package/.output/server/drizzle/0005_heavy_gauntlet.sql +8 -0
- package/.output/server/drizzle/0006_tranquil_sharon_carter.sql +1 -0
- package/.output/server/drizzle/0007_faulty_starbolt.sql +30 -0
- package/.output/server/drizzle/0008_durable_lifecycle_evidence.sql +15 -0
- package/.output/server/drizzle/meta/0000_snapshot.json +1333 -0
- package/.output/server/drizzle/meta/0001_snapshot.json +1498 -0
- package/.output/server/drizzle/meta/0002_snapshot.json +1576 -0
- package/.output/server/drizzle/meta/0003_snapshot.json +1666 -0
- package/.output/server/drizzle/meta/0005_snapshot.json +1666 -0
- package/.output/server/drizzle/meta/0006_snapshot.json +1672 -0
- package/.output/server/drizzle/meta/0007_snapshot.json +1787 -0
- package/.output/server/drizzle/meta/_journal.json +69 -0
- package/.output/server/index.mjs +464 -0
- package/.output/server/node_modules/tslib/modules/index.js +70 -0
- package/.output/server/node_modules/tslib/modules/package.json +3 -0
- package/.output/server/node_modules/tslib/package.json +47 -0
- package/.output/server/node_modules/tslib/tslib.js +484 -0
- package/.output/server/package.json +9 -0
- package/LICENSE +21 -0
- package/drizzle/0000_round_marauders.sql +193 -0
- package/drizzle/0001_naive_silver_fox.sql +25 -0
- package/drizzle/0002_funny_sage.sql +12 -0
- package/drizzle/0003_optimal_slapstick.sql +102 -0
- package/drizzle/0004_remove_grok_agent.sql +5 -0
- package/drizzle/0005_heavy_gauntlet.sql +8 -0
- package/drizzle/0006_tranquil_sharon_carter.sql +1 -0
- package/drizzle/0007_faulty_starbolt.sql +30 -0
- package/drizzle/0008_durable_lifecycle_evidence.sql +15 -0
- package/drizzle/meta/0000_snapshot.json +1333 -0
- package/drizzle/meta/0001_snapshot.json +1498 -0
- package/drizzle/meta/0002_snapshot.json +1576 -0
- package/drizzle/meta/0003_snapshot.json +1666 -0
- package/drizzle/meta/0005_snapshot.json +1666 -0
- package/drizzle/meta/0006_snapshot.json +1672 -0
- package/drizzle/meta/0007_snapshot.json +1787 -0
- package/drizzle/meta/_journal.json +69 -0
- package/package.json +84 -0
- package/scripts/pievo-server.mjs +390 -0
- package/scripts/prestart.mjs +66 -0
- package/scripts/server-cli-lib.mjs +451 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { o as __toESM } from "../_runtime.mjs";
|
|
2
|
+
import { C as require_jsx_runtime, S as require_react, d as TooltipPortal, f as TooltipTrigger, l as TooltipPopup, p as TooltipRoot, u as TooltipPositioner } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
|
+
import { jt as machinePresence } from "./boot-BbtG0ImW.mjs";
|
|
4
|
+
import { C as labelCls, D as runPulseAnim, E as rel, M as until, N as useHydrated, S as isCompleted, _ as fmt, b as inputCls, c as btnDanger, g as dur, h as dotLabel, l as btnPrimary, m as dotColor, o as btn, t as ErrorBanner } from "./ui-Dej2qjuS.mjs";
|
|
5
|
+
import { n as createServerFn } from "./ssr.mjs";
|
|
6
|
+
import { r as createSsrRpc, u as getConfig } from "./loopApi-Cxe8WyOB.mjs";
|
|
7
|
+
import { n as ModalHead, r as ModalSection, t as Modal } from "./Modal-DpKZHLZK.mjs";
|
|
8
|
+
import { n as daemonStopSupport } from "./lifecycleUi-C9lg1r3r.mjs";
|
|
9
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/notifyFns-Q458pZmE.js
|
|
10
|
+
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
11
|
+
var import_jsx_runtime = require_jsx_runtime();
|
|
12
|
+
/**
|
|
13
|
+
* Machine management server functions. Connect flow (two acts):
|
|
14
|
+
* 1. createMachine() → mint a token, create a PENDING (unnamed) row, return
|
|
15
|
+
* {id, token}. The UI shows the connect command + "waiting…".
|
|
16
|
+
* 2. the daemon connects → poll records online + hostname/platform/arch. The
|
|
17
|
+
* UI polls machineStatus(id); once connected it shows the name field
|
|
18
|
+
* (prefilled with the hostname). finalizeMachine({id,name}) names it →
|
|
19
|
+
* it appears in the list. cancelMachine(id) drops a pending row.
|
|
20
|
+
*
|
|
21
|
+
* Scoping: when the auth gate is on, every fn requires a signed-in user, and a
|
|
22
|
+
* machine is visible/actionable only when the requester owns it, its owner is a
|
|
23
|
+
* member of the active team, or the scope is the admin "All teams" view (the
|
|
24
|
+
* same rule listMachines filters by). The PLAINTEXT device token is serialized
|
|
25
|
+
* ONLY to the machine's owner — it fully impersonates the machine (poll /
|
|
26
|
+
* create-loop / log), so a teammate who can see the row must never exfiltrate
|
|
27
|
+
* it. Open mode (gate off) keeps the shared workspace: everyone sees/manages
|
|
28
|
+
* all machines, tokens included. No workdir jail (fully open) for now.
|
|
29
|
+
*/
|
|
30
|
+
/** Ids of the machines membership-visible in the scope's active team (the same
|
|
31
|
+
* set listMachines serves). Empty when the scope needs no team check (open
|
|
32
|
+
* mode or signed-out — machineInScope settles those before ever invoking its
|
|
33
|
+
* team-set thunk). */
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a machine and authorize it against the request scope (the machine-fn
|
|
36
|
+
* twin of loopApi's `ownedLoop`). `machine` is undefined when it's missing OR
|
|
37
|
+
* out of scope — callers treat both as "not found" so existence never leaks.
|
|
38
|
+
* The scope rides along so callers don't re-run requestScope (a second session
|
|
39
|
+
* decrypt); the team-set thunk keeps the owner fast path query-free.
|
|
40
|
+
*/
|
|
41
|
+
/** Named machines only (pending/unnamed rows are mid-connect). Scoped to the
|
|
42
|
+
* given/active team when the gate is on; the full shared list in open mode. An
|
|
43
|
+
* explicit `teamId` (the `/t/<id>` route) scopes this request independent of the
|
|
44
|
+
* cookie, so a tab on /t/A and one on /t/B list different machines at once. */
|
|
45
|
+
var listMachines = createServerFn({ method: "GET" }).validator((teamId) => teamId).handler(createSsrRpc("aa46310016bb8a58b273a648ffd498c87f1f450d12827e30110a3b83ba6a27d9"));
|
|
46
|
+
/** Act 1 — create a pending machine + token, owned by the signed-in user's team.
|
|
47
|
+
* An explicit `teamId` (the `/t/<id>` route) binds the machine to that tab's team
|
|
48
|
+
* independent of the last-used cookie, mirroring `mintClaim`/`listMachines`. */
|
|
49
|
+
var createMachine = createServerFn({ method: "POST" }).validator((teamId) => teamId).handler(createSsrRpc("ed679b4e1e05e903a5d4ba4a70d9b9d883991ab22ed59b4d2d69078941818415"));
|
|
50
|
+
/** Poll while the connect dialog is open. Scoped like listMachines; the token
|
|
51
|
+
* rides along only for the machine's owner (the connect dialog's minter). */
|
|
52
|
+
var machineStatus = createServerFn({ method: "GET" }).validator((id) => id).handler(createSsrRpc("169566e7637a22599b4eb32ee3775574e99677406922bbef7482a102036c33dd"));
|
|
53
|
+
/** Act 2 — name the connected machine (it then appears in the list). */
|
|
54
|
+
var finalizeMachine = createServerFn({ method: "POST" }).validator((d) => d).handler(createSsrRpc("27d7eba0b6a2257949392fdd56057275a5c5366484ae01faf3b5897a225ecd83"));
|
|
55
|
+
/**
|
|
56
|
+
* Cancel a pending connect (or delete an existing machine). A machine that still
|
|
57
|
+
* owns loops can't be deleted — the loops execute on it, so they must be removed
|
|
58
|
+
* first (we block rather than cascade, to never silently nuke a loop's history).
|
|
59
|
+
* Pending/unnamed machines have no loops, so the connect-cancel path passes through.
|
|
60
|
+
*/
|
|
61
|
+
var deleteMachine = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("a6384dc7154d9930422d29396f5de64b3ac69c62ad3824bc4a22d745fc07b293"));
|
|
62
|
+
/** Merge two chronological (oldest-first) run lists, dedup by id (the first
|
|
63
|
+
* occurrence wins, so pass the fresher list first), re-sorted by ts ascending.
|
|
64
|
+
* Shared by the dashboard cards and the loop detail page, which both seed the
|
|
65
|
+
* timeline with the newest page and grow it leftward with lazily-paged older runs. */
|
|
66
|
+
function mergeRuns(primary, secondary) {
|
|
67
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68
|
+
const out = [];
|
|
69
|
+
for (const r of [...primary, ...secondary]) {
|
|
70
|
+
if (seen.has(r.id)) continue;
|
|
71
|
+
seen.add(r.id);
|
|
72
|
+
out.push(r);
|
|
73
|
+
}
|
|
74
|
+
out.sort((a, b) => a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0);
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
var PAGE = 16;
|
|
78
|
+
var RAD = "rounded-[4px]";
|
|
79
|
+
var SEG = `h-5 w-[18px] shrink-0 ${RAD}`;
|
|
80
|
+
function RunSeg({ run, onClick }) {
|
|
81
|
+
const body = run.error || run.message || "";
|
|
82
|
+
const meta = run.durationMs ? ` · ${dur(run.durationMs)}` : "";
|
|
83
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TooltipRoot, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipTrigger, { render: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
84
|
+
type: "button",
|
|
85
|
+
onClick: (e) => {
|
|
86
|
+
e.stopPropagation();
|
|
87
|
+
onClick();
|
|
88
|
+
},
|
|
89
|
+
"aria-label": dotLabel(run),
|
|
90
|
+
className: `${SEG} cursor-pointer transition-opacity hover:opacity-70`,
|
|
91
|
+
style: {
|
|
92
|
+
background: dotColor(run),
|
|
93
|
+
...run.running ? runPulseAnim : {}
|
|
94
|
+
}
|
|
95
|
+
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipPositioner, {
|
|
96
|
+
sideOffset: 8,
|
|
97
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TooltipPopup, {
|
|
98
|
+
className: "glass-strong pointer-events-none max-w-[340px] rounded-control px-3.5 py-2.5 text-meta leading-snug text-primary",
|
|
99
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
100
|
+
className: "flex items-center gap-1.5 font-medium",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
103
|
+
className: "size-2 shrink-0 rounded-[2px]",
|
|
104
|
+
style: { background: dotColor(run) }
|
|
105
|
+
}),
|
|
106
|
+
dotLabel(run),
|
|
107
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
108
|
+
className: "ml-auto whitespace-nowrap pl-3 font-mono text-caption font-normal text-secondary",
|
|
109
|
+
children: [fmt(run.ts), meta]
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
}), body && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
113
|
+
className: `mt-1.5 max-h-[150px] overflow-hidden whitespace-pre-wrap ${run.error ? "text-accent" : "text-secondary"}`,
|
|
114
|
+
children: body
|
|
115
|
+
})]
|
|
116
|
+
})
|
|
117
|
+
}) })] });
|
|
118
|
+
}
|
|
119
|
+
/** An "N more" pager rendered as the SAME cube block as a run — identical 18px
|
|
120
|
+
* width (bordered, not filled, so it reads as an affordance; the "+" is dropped
|
|
121
|
+
* to keep the count inside the run-block width). Renders nothing when there's no
|
|
122
|
+
* overflow — no left-edge whitespace reserved. */
|
|
123
|
+
function Pager({ count, onClick, loading }) {
|
|
124
|
+
if (!count) return null;
|
|
125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
126
|
+
type: "button",
|
|
127
|
+
onClick: (e) => {
|
|
128
|
+
e.stopPropagation();
|
|
129
|
+
onClick();
|
|
130
|
+
},
|
|
131
|
+
className: `flex h-5 w-[18px] shrink-0 items-center justify-center overflow-hidden border border-wire px-0 font-mono text-[9px] leading-none text-disabled transition-colors hover:border-display hover:text-primary ${RAD} ${loading ? "animate-pulse" : "cursor-pointer"}`,
|
|
132
|
+
title: `${count} more - click to reveal`,
|
|
133
|
+
children: loading ? "…" : count
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function Timeline({ job, runs, total, onLoadMore, onPickRun }) {
|
|
137
|
+
const all = runs;
|
|
138
|
+
const en = job.enabled;
|
|
139
|
+
const done = isCompleted(job);
|
|
140
|
+
const L = all.length;
|
|
141
|
+
const unloaded = Math.max(0, total - L);
|
|
142
|
+
const hydrated = useHydrated();
|
|
143
|
+
const [winStart, setWinStart] = (0, import_react.useState)(-1);
|
|
144
|
+
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
145
|
+
const maxStart = Math.max(0, L - 16);
|
|
146
|
+
const start = winStart < 0 ? maxStart : Math.min(winStart, maxStart);
|
|
147
|
+
const end = Math.min(start + 16, L);
|
|
148
|
+
const visible = all.slice(start, end);
|
|
149
|
+
const olderHidden = unloaded + start;
|
|
150
|
+
const newerHidden = L - end;
|
|
151
|
+
const atLatest = newerHidden === 0;
|
|
152
|
+
const pageBack = async () => {
|
|
153
|
+
const target = start - PAGE;
|
|
154
|
+
if (target < 0 && unloaded > 0 && !loading) {
|
|
155
|
+
setLoading(true);
|
|
156
|
+
const added = await onLoadMore().catch(() => 0);
|
|
157
|
+
setLoading(false);
|
|
158
|
+
setWinStart(Math.max(0, start + added - PAGE));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
setWinStart(Math.max(0, target));
|
|
162
|
+
};
|
|
163
|
+
const pageFwd = () => {
|
|
164
|
+
const next = start + PAGE;
|
|
165
|
+
setWinStart(next >= maxStart ? -1 : next);
|
|
166
|
+
};
|
|
167
|
+
const running = !!(job.running || job.queued) && atLatest;
|
|
168
|
+
const showNext = atLatest && en && !done && !!job.nextRun && !running;
|
|
169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
170
|
+
className: "flex min-w-0 items-center gap-[3px] overflow-x-auto",
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pager, {
|
|
173
|
+
count: olderHidden,
|
|
174
|
+
onClick: pageBack,
|
|
175
|
+
loading
|
|
176
|
+
}),
|
|
177
|
+
visible.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunSeg, {
|
|
178
|
+
run: r,
|
|
179
|
+
onClick: () => onPickRun(r)
|
|
180
|
+
}, r.id)),
|
|
181
|
+
showNext ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
182
|
+
className: "ml-1 flex items-center gap-2",
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w-12 border-t border-dashed border-wire" }),
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
186
|
+
className: "size-[11px] shrink-0 rounded-full border border-wire",
|
|
187
|
+
title: hydrated ? `Next scheduled run · ${fmt(job.nextRun)}` : void 0
|
|
188
|
+
}),
|
|
189
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
190
|
+
className: "text-caption text-disabled",
|
|
191
|
+
children: hydrated ? until(job.nextRun) : ""
|
|
192
|
+
})
|
|
193
|
+
]
|
|
194
|
+
}) : !atLatest && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pager, {
|
|
195
|
+
count: newerHidden,
|
|
196
|
+
onClick: pageFwd
|
|
197
|
+
})
|
|
198
|
+
]
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Tiny semver comparison — just enough to decide "is the daemon older than the
|
|
203
|
+
* latest published version?" for the web's update hint. No dependency; we only
|
|
204
|
+
* need numeric-core ordering (major.minor.patch), and a pre-release is treated
|
|
205
|
+
* as older than its release (a "0.9.0-rc.1" daemon is still behind "0.9.0").
|
|
206
|
+
*/
|
|
207
|
+
/** Parse the leading numeric core `x.y.z` of a version, ignoring any pre-release
|
|
208
|
+
* / build suffix. Returns null when it isn't a recognizable version. */
|
|
209
|
+
function core(v) {
|
|
210
|
+
const m = /^\s*v?(\d+)\.(\d+)\.(\d+)/.exec(v);
|
|
211
|
+
if (!m) return null;
|
|
212
|
+
return [
|
|
213
|
+
Number(m[1]),
|
|
214
|
+
Number(m[2]),
|
|
215
|
+
Number(m[3])
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
/** Does `v` carry a pre-release suffix (e.g. "1.2.3-rc.1")? */
|
|
219
|
+
function isPre(v) {
|
|
220
|
+
return /^\s*v?\d+\.\d+\.\d+-/.test(v);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* `true` when `current` is strictly older than `latest`. Returns `false` on any
|
|
224
|
+
* unparseable/equal/newer input — the hint is opt-in, so we only ever show it
|
|
225
|
+
* when we can be confident the daemon is genuinely behind.
|
|
226
|
+
*/
|
|
227
|
+
function isOutdated(current, latest) {
|
|
228
|
+
if (!current || !latest) return false;
|
|
229
|
+
const a = core(current);
|
|
230
|
+
const b = core(latest);
|
|
231
|
+
if (!a || !b) return false;
|
|
232
|
+
for (let i = 0; i < 3; i++) {
|
|
233
|
+
const ai = a[i];
|
|
234
|
+
const bi = b[i];
|
|
235
|
+
if (ai < bi) return true;
|
|
236
|
+
if (ai > bi) return false;
|
|
237
|
+
}
|
|
238
|
+
return isPre(current) && !isPre(latest);
|
|
239
|
+
}
|
|
240
|
+
/** User-facing daemon commands. Public UX installs globally; PIEVO_CLI dev
|
|
241
|
+
* overrides are invoked verbatim and never trigger a global npm install. */
|
|
242
|
+
function daemonConnectCommand(origin, token, cli, customCli) {
|
|
243
|
+
const start = `${cli} daemon start --server-url ${origin} --connect-key ${token}`;
|
|
244
|
+
return customCli ? start : `npm install -g @kky42/pievo@latest && ${start}`;
|
|
245
|
+
}
|
|
246
|
+
function daemonUpgradeCommand(cli, customCli) {
|
|
247
|
+
const restart = `${cli} daemon restart`;
|
|
248
|
+
return customCli ? restart : `npm install -g @kky42/pievo@latest && ${restart}`;
|
|
249
|
+
}
|
|
250
|
+
function connectCmd(token, cli, customCli) {
|
|
251
|
+
return daemonConnectCommand(typeof window !== "undefined" ? window.location.origin : "http://127.0.0.1:3000", token, cli, customCli);
|
|
252
|
+
}
|
|
253
|
+
function CopyButton({ text }) {
|
|
254
|
+
const [done, setDone] = (0, import_react.useState)(false);
|
|
255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
256
|
+
className: btn,
|
|
257
|
+
onClick: () => {
|
|
258
|
+
navigator.clipboard?.writeText(text);
|
|
259
|
+
setDone(true);
|
|
260
|
+
setTimeout(() => setDone(false), 1400);
|
|
261
|
+
},
|
|
262
|
+
children: done ? "Copied ✓" : "Copy"
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function MachinesModal({ open, onClose, teamId }) {
|
|
266
|
+
const [machines, setMachines] = (0, import_react.useState)([]);
|
|
267
|
+
const [pending, setPending] = (0, import_react.useState)(null);
|
|
268
|
+
const [status, setStatus] = (0, import_react.useState)(null);
|
|
269
|
+
const [name, setName] = (0, import_react.useState)("");
|
|
270
|
+
const [busy, setBusy] = (0, import_react.useState)(false);
|
|
271
|
+
const [delErr, setDelErr] = (0, import_react.useState)(null);
|
|
272
|
+
const [cliConfig, setCliConfig] = (0, import_react.useState)(null);
|
|
273
|
+
const [configErr, setConfigErr] = (0, import_react.useState)(false);
|
|
274
|
+
(0, import_react.useEffect)(() => {
|
|
275
|
+
if (!open) {
|
|
276
|
+
setDelErr(null);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
let active = true;
|
|
280
|
+
setCliConfig(null);
|
|
281
|
+
setConfigErr(false);
|
|
282
|
+
getConfig().then((config) => {
|
|
283
|
+
if (active) setCliConfig(config);
|
|
284
|
+
}).catch(() => {
|
|
285
|
+
if (active) setConfigErr(true);
|
|
286
|
+
});
|
|
287
|
+
return () => {
|
|
288
|
+
active = false;
|
|
289
|
+
};
|
|
290
|
+
}, [open]);
|
|
291
|
+
const load = (0, import_react.useCallback)(async () => {
|
|
292
|
+
try {
|
|
293
|
+
setMachines(await listMachines({ data: teamId }));
|
|
294
|
+
} catch {}
|
|
295
|
+
}, [teamId]);
|
|
296
|
+
const openRef = (0, import_react.useRef)(open);
|
|
297
|
+
openRef.current = open;
|
|
298
|
+
(0, import_react.useEffect)(() => {
|
|
299
|
+
if (!open || pending) return;
|
|
300
|
+
load();
|
|
301
|
+
const t = setInterval(() => openRef.current && void load(), 3e3);
|
|
302
|
+
return () => clearInterval(t);
|
|
303
|
+
}, [
|
|
304
|
+
open,
|
|
305
|
+
pending,
|
|
306
|
+
load
|
|
307
|
+
]);
|
|
308
|
+
(0, import_react.useEffect)(() => {
|
|
309
|
+
if (!pending) return;
|
|
310
|
+
let active = true;
|
|
311
|
+
const tick = async () => {
|
|
312
|
+
const s = await machineStatus({ data: pending.id }).catch(() => void 0);
|
|
313
|
+
if (!active || s === void 0) return;
|
|
314
|
+
setStatus(s);
|
|
315
|
+
if (s?.online && s.hostname) setName((n) => n || s.hostname || "");
|
|
316
|
+
};
|
|
317
|
+
tick();
|
|
318
|
+
const t = setInterval(tick, 2e3);
|
|
319
|
+
return () => {
|
|
320
|
+
active = false;
|
|
321
|
+
clearInterval(t);
|
|
322
|
+
};
|
|
323
|
+
}, [pending]);
|
|
324
|
+
async function startConnect() {
|
|
325
|
+
setBusy(true);
|
|
326
|
+
setDelErr(null);
|
|
327
|
+
try {
|
|
328
|
+
const r = await createMachine({ data: teamId });
|
|
329
|
+
if ("error" in r) {
|
|
330
|
+
setDelErr(r.error);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
setStatus(null);
|
|
334
|
+
setName("");
|
|
335
|
+
setPending(r);
|
|
336
|
+
} finally {
|
|
337
|
+
setBusy(false);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function cancel() {
|
|
341
|
+
if (pending) await deleteMachine({ data: pending.id });
|
|
342
|
+
setPending(null);
|
|
343
|
+
setStatus(null);
|
|
344
|
+
await load();
|
|
345
|
+
}
|
|
346
|
+
async function done() {
|
|
347
|
+
if (pending && name.trim()) await finalizeMachine({ data: {
|
|
348
|
+
id: pending.id,
|
|
349
|
+
name: name.trim()
|
|
350
|
+
} });
|
|
351
|
+
setPending(null);
|
|
352
|
+
setStatus(null);
|
|
353
|
+
await load();
|
|
354
|
+
}
|
|
355
|
+
async function remove(id) {
|
|
356
|
+
setDelErr(null);
|
|
357
|
+
const r = await deleteMachine({ data: id });
|
|
358
|
+
if (!r.ok) {
|
|
359
|
+
setDelErr(r.error ?? "Could not delete this machine.");
|
|
360
|
+
await load();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
await load();
|
|
364
|
+
}
|
|
365
|
+
const connected = !!status?.online;
|
|
366
|
+
if (pending) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Modal, {
|
|
367
|
+
open,
|
|
368
|
+
onClose: cancel,
|
|
369
|
+
children: [
|
|
370
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHead, { title: connected ? "Computer connected" : "Connect computer" }),
|
|
371
|
+
!connected ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
373
|
+
className: "mt-5 text-body font-medium text-display",
|
|
374
|
+
children: "Run this command on your computer to connect:"
|
|
375
|
+
}),
|
|
376
|
+
cliConfig ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
377
|
+
className: "mt-2 flex items-start gap-2",
|
|
378
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
379
|
+
className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-4 font-mono text-label leading-relaxed text-paper",
|
|
380
|
+
children: connectCmd(pending.token, cliConfig.pievoCli, cliConfig.customCli)
|
|
381
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(pending.token, cliConfig.pievoCli, cliConfig.customCli) })]
|
|
382
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
383
|
+
className: "mt-2 text-body text-secondary",
|
|
384
|
+
children: configErr ? "Could not load the connection command. Close and try again." : "Loading connection command…"
|
|
385
|
+
}),
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
387
|
+
className: "mt-4 flex items-center gap-2.5 rounded-control border border-hairline bg-warn-soft px-4 py-3",
|
|
388
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "inline-block h-2.5 w-2.5 animate-pulse rounded-full bg-rubik-orange" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
389
|
+
className: "text-[14px] font-medium text-warn",
|
|
390
|
+
children: "Waiting for computer to connect…"
|
|
391
|
+
})]
|
|
392
|
+
})
|
|
393
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
394
|
+
className: "mt-5 flex items-center gap-3 rounded-control border border-hairline bg-success-soft px-4 py-3",
|
|
395
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
396
|
+
className: "text-xl text-success",
|
|
397
|
+
children: "✓"
|
|
398
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
399
|
+
className: "text-[15px] font-medium text-display",
|
|
400
|
+
children: "Computer connected successfully!"
|
|
401
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
402
|
+
className: "text-label text-secondary",
|
|
403
|
+
children: [status?.hostname ?? "unknown", status?.platform ? ` - ${status.platform} ${status.arch ?? ""}` : ""]
|
|
404
|
+
})] })]
|
|
405
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
406
|
+
className: "mt-5",
|
|
407
|
+
children: [
|
|
408
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
|
|
409
|
+
className: labelCls,
|
|
410
|
+
children: "Computer name"
|
|
411
|
+
}),
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
413
|
+
className: inputCls,
|
|
414
|
+
value: name,
|
|
415
|
+
onChange: (e) => setName(e.target.value),
|
|
416
|
+
placeholder: status?.hostname ?? "My computer"
|
|
417
|
+
}),
|
|
418
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
419
|
+
className: "mt-1 text-label text-secondary",
|
|
420
|
+
children: "A friendly name for this computer."
|
|
421
|
+
})
|
|
422
|
+
]
|
|
423
|
+
})] }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
425
|
+
className: "mt-6 flex justify-end gap-2",
|
|
426
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
427
|
+
className: btn,
|
|
428
|
+
onClick: () => void cancel(),
|
|
429
|
+
children: "Cancel"
|
|
430
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
431
|
+
className: btnPrimary,
|
|
432
|
+
disabled: !connected || !name.trim(),
|
|
433
|
+
onClick: () => void done(),
|
|
434
|
+
children: "Done"
|
|
435
|
+
})]
|
|
436
|
+
})
|
|
437
|
+
]
|
|
438
|
+
});
|
|
439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Modal, {
|
|
440
|
+
open,
|
|
441
|
+
onClose,
|
|
442
|
+
children: [
|
|
443
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHead, {
|
|
444
|
+
title: "Machines",
|
|
445
|
+
sub: "Each machine runs a pievo daemon that executes your loops via your local coding agent."
|
|
446
|
+
}),
|
|
447
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalSection, { children: "Connected machines" }),
|
|
448
|
+
delErr && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, {
|
|
449
|
+
message: delErr,
|
|
450
|
+
onDismiss: () => setDelErr(null)
|
|
451
|
+
}),
|
|
452
|
+
machines.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
453
|
+
className: "py-3 text-body text-secondary",
|
|
454
|
+
children: "No machines yet."
|
|
455
|
+
}),
|
|
456
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
|
|
457
|
+
className: "flex flex-col gap-2",
|
|
458
|
+
children: machines.map((m) => {
|
|
459
|
+
const presence = machinePresence(m.online, m.lastSeen);
|
|
460
|
+
const dotCls = presence === "online" ? "bg-rubik-green" : presence === "asleep" ? "bg-rubik-yellow" : "bg-disabled";
|
|
461
|
+
const stateText = presence === "online" ? "online" : presence === "asleep" ? `asleep${m.lastSeen ? ` · seen ${rel(m.lastSeen)}` : ""}` : m.lastSeen ? `offline · seen ${rel(m.lastSeen)}` : "offline";
|
|
462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", {
|
|
463
|
+
className: "flex flex-col gap-2 rounded-control border border-hairline bg-surface px-4 py-3",
|
|
464
|
+
children: [
|
|
465
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
466
|
+
className: "flex items-center justify-between gap-3",
|
|
467
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
468
|
+
className: "flex items-center gap-2.5",
|
|
469
|
+
children: [
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
471
|
+
className: `inline-block h-2 w-2 rounded-full ${dotCls}`,
|
|
472
|
+
title: presence
|
|
473
|
+
}),
|
|
474
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
475
|
+
className: "text-[15px] font-medium text-display",
|
|
476
|
+
children: m.name
|
|
477
|
+
}),
|
|
478
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
479
|
+
className: "text-label text-secondary",
|
|
480
|
+
children: [
|
|
481
|
+
stateText,
|
|
482
|
+
m.platform ? ` · ${m.platform} ${m.arch ?? ""}` : "",
|
|
483
|
+
m.loopCount > 0 ? ` · ${m.loopCount} loop${m.loopCount === 1 ? "" : "s"}` : ""
|
|
484
|
+
]
|
|
485
|
+
})
|
|
486
|
+
]
|
|
487
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
488
|
+
className: btnDanger,
|
|
489
|
+
disabled: m.loopCount > 0,
|
|
490
|
+
title: m.loopCount > 0 ? "Delete its loops first" : void 0,
|
|
491
|
+
onClick: () => void remove(m.id),
|
|
492
|
+
children: "Delete"
|
|
493
|
+
})]
|
|
494
|
+
}),
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
496
|
+
className: "text-label text-secondary",
|
|
497
|
+
children: daemonStopSupport(m.daemonProtocol).label
|
|
498
|
+
}),
|
|
499
|
+
m.daemonProtocol !== 2 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
500
|
+
className: "text-label text-accent",
|
|
501
|
+
children: "Daemon upgrade required to stop a running process"
|
|
502
|
+
}),
|
|
503
|
+
!m.online && !m.token && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
504
|
+
className: "text-label text-secondary",
|
|
505
|
+
children: "Reconnect command available from the machine owner's account."
|
|
506
|
+
}),
|
|
507
|
+
!m.online && m.token && !cliConfig && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
508
|
+
className: "text-label text-secondary",
|
|
509
|
+
children: configErr ? "Could not load the reconnect command. Close and try again." : "Loading reconnect command…"
|
|
510
|
+
}),
|
|
511
|
+
!m.online && m.token && cliConfig && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", {
|
|
512
|
+
className: "cursor-pointer select-none text-label font-medium text-secondary marker:content-[''] hover:text-display",
|
|
513
|
+
children: "Reconnect command"
|
|
514
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
515
|
+
className: "mt-2 flex items-start gap-2",
|
|
516
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
517
|
+
className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
|
|
518
|
+
children: connectCmd(m.token, cliConfig.pievoCli, cliConfig.customCli)
|
|
519
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: connectCmd(m.token, cliConfig.pievoCli, cliConfig.customCli) })]
|
|
520
|
+
})] }),
|
|
521
|
+
isOutdated(m.daemonVersion, m.latestDaemonVersion) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
522
|
+
className: "flex flex-col gap-1.5",
|
|
523
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
524
|
+
className: "text-label text-secondary",
|
|
525
|
+
children: [
|
|
526
|
+
"daemon v",
|
|
527
|
+
m.daemonVersion,
|
|
528
|
+
" · upgrade available (v",
|
|
529
|
+
m.latestDaemonVersion,
|
|
530
|
+
")"
|
|
531
|
+
]
|
|
532
|
+
}), cliConfig ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
533
|
+
className: "flex items-start gap-2",
|
|
534
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
535
|
+
className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-control bg-display p-3 font-mono text-caption leading-relaxed text-paper",
|
|
536
|
+
children: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli)
|
|
537
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: daemonUpgradeCommand(cliConfig.pievoCli, cliConfig.customCli) })]
|
|
538
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
539
|
+
className: "text-label text-secondary",
|
|
540
|
+
children: configErr ? "Could not load the upgrade command. Close and try again." : "Loading upgrade command…"
|
|
541
|
+
})]
|
|
542
|
+
})
|
|
543
|
+
]
|
|
544
|
+
}, m.id);
|
|
545
|
+
})
|
|
546
|
+
}),
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
548
|
+
className: "mt-6",
|
|
549
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
550
|
+
className: btnPrimary,
|
|
551
|
+
disabled: busy,
|
|
552
|
+
onClick: () => void startConnect(),
|
|
553
|
+
children: busy ? "Preparing…" : "+ Connect computer"
|
|
554
|
+
})
|
|
555
|
+
})
|
|
556
|
+
]
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Notification-channel server functions. Channels are per-team push targets a
|
|
561
|
+
* loop can route its run messages to. Secrets (bot token / chat id) live in the
|
|
562
|
+
* channel's `config` and are NEVER returned to the client — list/test surface
|
|
563
|
+
* only a redacted summary. Scoped to the request's team (see requestScope).
|
|
564
|
+
*
|
|
565
|
+
* Per-type behavior (validate / hint / send) lives in `CHANNELS` (gateway/notify);
|
|
566
|
+
* this module just wires it to auth + storage.
|
|
567
|
+
*/
|
|
568
|
+
/** Resolve a channel and authorize it against the request's team — undefined when
|
|
569
|
+
* missing OR (gate on) owned by another team, so existence never leaks. Mirrors
|
|
570
|
+
* loopApi's ownedLoop for the channel routes. */
|
|
571
|
+
/** GET — the team's channels (redacted summaries, newest first). */
|
|
572
|
+
var listChannels = createServerFn({ method: "GET" }).handler(createSsrRpc("ced5641f28e3e64d3b8773ea4c875b78ee305bd08caba90a2207e86ef1ab3327"));
|
|
573
|
+
/** POST — create a channel in the team. Validates per-type required fields. */
|
|
574
|
+
var createChannel = createServerFn({ method: "POST" }).validator((d) => d).handler(createSsrRpc("d6cb1ea6f7fdaf940fbbe91d6b0898a0d5ac2308f8bc572dc3b856824a1f4581"));
|
|
575
|
+
/** POST — delete a channel (loops pointing at it fall back to dashboard-only). */
|
|
576
|
+
var deleteChannel = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("9defc1b5d0f4316d61621e2c4614a70dc052ad6b7a3aa2ead00836f7d5cb5b4c"));
|
|
577
|
+
/** POST — send a test message through a saved channel (verifies the secrets). */
|
|
578
|
+
var testChannel = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("a4e3ae06af7087a3dc291236cf6d5ad272e2f754884c1f948e75a18a4ebada93"));
|
|
579
|
+
//#endregion
|
|
580
|
+
export { listChannels as a, testChannel as c, deleteChannel as i, Timeline as n, listMachines as o, createChannel as r, mergeRuns as s, MachinesModal as t };
|