@kky42/pievo-server 2.4.13 → 3.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 +1 -1
- package/.output/public/assets/{actionUi-D8m1FDHO.js → actionUi-BZrLpgHT.js} +1 -1
- package/.output/public/assets/app-DXLuQNb9.css +2 -0
- package/.output/public/assets/index-Di_wpAtL.js +10 -0
- package/.output/public/assets/loops._loopId-X3ClNPMY.js +67 -0
- package/.output/public/assets/loops._loopId_.runs._runId-ByU2BSyF.js +3 -0
- package/.output/public/assets/preload-helper-hRTYB_ju.js +3 -0
- package/.output/public/assets/{routes-79D939J4.js → routes-BIOJZsig.js} +1 -1
- package/.output/public/assets/routes-K8D5uBiV.js +1 -0
- package/.output/server/_chunks/ssr-renderer.mjs +1 -1
- package/.output/server/_libs/{drizzle-orm+postgres.mjs → drizzle-orm.mjs} +93 -2218
- package/.output/server/_ssr/{MachinesModal-DBIP648Z.mjs → MachinesModal-CmVMec6B.mjs} +52 -46
- package/.output/server/_ssr/{actionUi-C_WswNb1.mjs → actionUi-DE-Pb2tv.mjs} +4 -5
- package/.output/server/_ssr/{artifactFiles-BvVmixrs.mjs → artifactFiles-Di1xDKvX.mjs} +5 -7
- package/.output/server/_ssr/{artifactKind-DRCbYHZU.mjs → artifactKind-DqpmtxDU.mjs} +3 -9
- package/.output/server/_ssr/{boot-U-CFI65B.mjs → boot-CYRi-wez.mjs} +531 -1976
- package/.output/server/_ssr/lifecycleUi-BsbUsi5K.mjs +106 -0
- package/.output/server/_ssr/{loopApi-C4nN0msL.mjs → loopApi-Bez1rHV0.mjs} +50 -65
- package/.output/server/_ssr/{loopProjection-DMSNHux6.mjs → loopProjection-esCjyZJg.mjs} +4 -20
- package/.output/server/_ssr/{loops._loopId-Q4pRYPip.mjs → loops._loopId-KUezNY69.mjs} +133 -24
- package/.output/server/_ssr/{loops._loopId_.runs._runId-DNXVmCt5.mjs → loops._loopId_.runs._runId-BFP9oMrp.mjs} +2 -7
- package/.output/server/_ssr/{loops._loopId_.runs._runId-ty3AhkOi.mjs → loops._loopId_.runs._runId-DOkUEesG.mjs} +18 -33
- package/.output/server/_ssr/{machineFns-CkNms3zA.mjs → machineFns-CniGcY8s.mjs} +13 -49
- package/.output/server/_ssr/networkAccess-CIlK3ION.mjs +30 -0
- package/.output/server/_ssr/router-BFIH2UAE.mjs +362 -0
- package/.output/server/_ssr/routes-BSVBANI3.mjs +12 -0
- package/.output/server/_ssr/{routes-BaanDO41.mjs → routes-DnE7XDe_.mjs} +242 -77
- package/.output/server/_ssr/{routes-B3fulW5I.mjs → routes-ngpX7h8D.mjs} +2 -4
- package/.output/server/_ssr/ssr.mjs +25 -34
- package/.output/server/_ssr/start-B5_9Z5W-.mjs +35 -0
- package/.output/server/{_tanstack-start-manifest_v-DkmxsHDK.mjs → _tanstack-start-manifest_v-DnwAupbZ.mjs} +8 -13
- package/.output/server/drizzle/0000_baseline.sql +6 -97
- package/.output/server/drizzle/meta/_journal.json +2 -16
- package/.output/server/index.mjs +43 -50
- package/drizzle/0000_baseline.sql +6 -97
- package/drizzle/meta/_journal.json +2 -16
- package/package.json +4 -8
- package/scripts/pievo-server.mjs +49 -47
- package/scripts/server-cli-lib.mjs +21 -12
- package/scripts/server-network.mjs +139 -0
- package/.output/public/assets/SignIn-CDCdDD1a.js +0 -1
- package/.output/public/assets/app-PPhgN9iN.css +0 -2
- package/.output/public/assets/index-c0XPWXuz.js +0 -10
- package/.output/public/assets/loops._loopId-D7i_BGiE.js +0 -67
- package/.output/public/assets/loops._loopId_.runs._runId-CksSrEY7.js +0 -3
- package/.output/public/assets/preload-helper-Zcmr31XG.js +0 -5
- package/.output/public/assets/routes-BYgl3Tmv.js +0 -1
- package/.output/server/_libs/@aws-crypto/crc32+[...].mjs +0 -419
- package/.output/server/_libs/@aws-sdk/checksums+[...].mjs +0 -10732
- package/.output/server/_libs/@aws-sdk/client-s3+[...].mjs +0 -9475
- package/.output/server/_libs/@aws-sdk/credential-provider-http+[...].mjs +0 -137
- package/.output/server/_libs/@aws-sdk/credential-provider-ini+[...].mjs +0 -440
- package/.output/server/_libs/@aws-sdk/credential-provider-process+[...].mjs +0 -62
- package/.output/server/_libs/@aws-sdk/credential-provider-sso+[...].mjs +0 -818
- package/.output/server/_libs/@aws-sdk/credential-provider-web-identity+[...].mjs +0 -59
- package/.output/server/_libs/@smithy/credential-provider-imds+[...].mjs +0 -342
- package/.output/server/_libs/aws-crypto__crc32c.mjs +0 -314
- package/.output/server/_libs/aws-sdk__nested-clients.mjs +0 -2671
- package/.output/server/_ssr/SignIn-Bp3uWaCQ.mjs +0 -53
- package/.output/server/_ssr/artifacts-CzDJLaa6.mjs +0 -2
- package/.output/server/_ssr/auth-BV0MxVdo.mjs +0 -38355
- package/.output/server/_ssr/auth-client-RTpMpT4L.mjs +0 -1070
- package/.output/server/_ssr/boot-CsLXrLEa.mjs +0 -2
- package/.output/server/_ssr/bun-sqlite-dialect-BW9W1_Ps-D9KUBJ-L.mjs +0 -162
- package/.output/server/_ssr/core-RrmWoKne.mjs +0 -5
- package/.output/server/_ssr/d1-sqlite-dialect-BLC8LXE6-CVHRzH1n.mjs +0 -112
- package/.output/server/_ssr/db-BTX-xORB.mjs +0 -2
- package/.output/server/_ssr/dist-D7UDVZ5G.mjs +0 -342
- package/.output/server/_ssr/factory-DYFx1fg-.mjs +0 -6903
- package/.output/server/_ssr/kysely-adapter-CwdB7yBh.mjs +0 -2
- package/.output/server/_ssr/kysely-migration-tables-JkVUjPF_-bPAX9LR_.mjs +0 -19
- package/.output/server/_ssr/logger-CwiKSMp6.mjs +0 -2
- package/.output/server/_ssr/node-sqlite-dialect-B_g92oFK.mjs +0 -162
- package/.output/server/_ssr/router-DCNZ2xLm.mjs +0 -543
- package/.output/server/_ssr/routes-8JSF7bX_.mjs +0 -27
- package/.output/server/_ssr/runDiff-D7CxAgYL.mjs +0 -2
- package/.output/server/_ssr/start-4ifArtKx.mjs +0 -4
- package/.output/server/_ssr/store-DSNbXxqz.mjs +0 -2
- package/.output/server/_ssr/tokens-DzUv7CCp.mjs +0 -2
- package/.output/server/drizzle/0001_add_pi_agent.sql +0 -9
- package/.output/server/drizzle/0002_remove_teams.sql +0 -15
- package/.output/server/node_modules/tslib/modules/index.js +0 -70
- package/.output/server/node_modules/tslib/modules/package.json +0 -3
- package/.output/server/node_modules/tslib/package.json +0 -47
- package/.output/server/node_modules/tslib/tslib.js +0 -484
- package/.output/server/package.json +0 -9
- package/drizzle/0001_add_pi_agent.sql +0 -9
- package/drizzle/0002_remove_teams.sql +0 -15
- package/scripts/prestart.mjs +0 -66
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { i as getServerFnById, r as createServerFn, t as TSS_SERVER_FUNCTION } from "./ssr.mjs";
|
|
2
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/lifecycleUi-BsbUsi5K.js
|
|
3
|
+
var createSsrRpc = (functionId) => {
|
|
4
|
+
const url = "/_serverFn/" + functionId;
|
|
5
|
+
const serverFnMeta = { id: functionId };
|
|
6
|
+
const fn = async (...args) => {
|
|
7
|
+
return (await getServerFnById(functionId, { origin: "server" }))(...args);
|
|
8
|
+
};
|
|
9
|
+
return Object.assign(fn, {
|
|
10
|
+
url,
|
|
11
|
+
serverFnMeta,
|
|
12
|
+
[TSS_SERVER_FUNCTION]: true
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Server functions backing the dashboard. They run server-side (createServerFn
|
|
17
|
+
* → RPC) and call the IN-PROCESS scheduler + store directly — the scheduler
|
|
18
|
+
* lives in this same TanStack process (booted on first call via ensureServer).
|
|
19
|
+
* The machine-facing poll, CLI, report, and artifact-sync endpoints are sibling
|
|
20
|
+
* server routes in this same process, so one process owns the single scheduler.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Client config. `pievoCli` is the CLI invocation prefix the skill + connect
|
|
24
|
+
* dialog use for every verb (`daemon start`, `new`, …) — defaults to the globally
|
|
25
|
+
* installed `pievo`. Set PIEVO_CLI locally to a runnable command that points at the in-repo
|
|
26
|
+
* daemon, e.g. `tsx /abs/packages/daemon/src/cli.ts` or
|
|
27
|
+
* `node /abs/packages/daemon/dist/cli.js`, so loops created from THIS server tell
|
|
28
|
+
* Claude Code to run your local code instead of the registry build.
|
|
29
|
+
*/
|
|
30
|
+
var getConfig = createServerFn({ method: "GET" }).handler(createSsrRpc("cbb6a1b09b309459bbba3dc3851ae85fc468658b3cda77e22b6c6f3e28b65af4"));
|
|
31
|
+
/** GET — visible loops as compact summaries, most recently run first. */
|
|
32
|
+
var listLoops = createServerFn({ method: "GET" }).handler(createSsrRpc("23e290b2b7483ceea6fe669024c35b12c2c4ddd76649f6fab21c958ceda02940"));
|
|
33
|
+
var getLoopDetail = createServerFn({ method: "GET" }).validator((id) => id).handler(createSsrRpc("b050455aacc84dd2a2c9a45517826ad10f91d8f1545e87cc7015784cc7116a97"));
|
|
34
|
+
var loadOlderRuns = createServerFn({ method: "GET" }).validator((d) => d).handler(createSsrRpc("85fdf73d4fee43aed762f93c5d47d33200fbff39e2d082647dc921f610d32698"));
|
|
35
|
+
var getArtifacts = createServerFn({ method: "GET" }).validator((d) => d).handler(createSsrRpc("b18bbec3d06dfc77714e1e527dfb9172fd7575a64a6c0d6e73ba6dc658dccf0d"));
|
|
36
|
+
var getArtifact = createServerFn({ method: "GET" }).validator((d) => d).handler(createSsrRpc("ed10d5fe79208e5e0e4e18e4a17b18d7f7db4dd16204c00c3ac90c4644668841"));
|
|
37
|
+
/** GET — a run's per-file diff vs the previous run. Lazy by runId like
|
|
38
|
+
* computed on the server at read time (no stored diffs). Old runs
|
|
39
|
+
* with no snapshot return `hasSnapshot: false` for the degrade copy. */
|
|
40
|
+
var getRunDiff = createServerFn({ method: "GET" }).validator((d) => d).handler(createSsrRpc("08c28b892712a1b491b120b74c7dcb81761988d31ccea60216d1807b73c1182c"));
|
|
41
|
+
var patchLoop = createServerFn({ method: "POST" }).validator((d) => d).handler(createSsrRpc("9befe6b8d67ccbbd7aa9b538bde2a161a9894761c8936761a9503fda1a88c0fc"));
|
|
42
|
+
/** Dedicated lifecycle operations. Dashboard callers never synthesize these
|
|
43
|
+
* transitions with patchLoop: each delegates to the loop-locked store operation. */
|
|
44
|
+
var pauseLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("95b7483b333d7649e70c848319417e83c2af6a0327bbcda2d0e331f626dffe05"));
|
|
45
|
+
var startLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("5660ea82ea5ff2549e0ce2f8f070c54f3e9e24fee84d547601ef5d6ef49a4016"));
|
|
46
|
+
var stopLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("e233a461e4526dec3cc4cbaa891a7c3621d5967ce7f32b4fb17e9fb645857b9a"));
|
|
47
|
+
/** Delete is one confirmed operation. Reachable machines get the graceful
|
|
48
|
+
* Stop-and-wait path; a machine already offline at click time cannot acknowledge
|
|
49
|
+
* Stop, so retire its execution authority and remove server data immediately.
|
|
50
|
+
* Local files are never touched by either path. */
|
|
51
|
+
var deleteLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("5e0d6b55f5629faac2f55a68661eeb82668b2be752192b16264ffb5cd1e6fabe"));
|
|
52
|
+
var runLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("08565e35f6a3dd06ef25401de0343976c47f7ae319d3baed6320b56dd3718311"));
|
|
53
|
+
/** Dedicated Stop-run operation. Pending work cancels immediately; running work
|
|
54
|
+
* records intent and stays Running until the daemon reports its actual result. */
|
|
55
|
+
var stopRun = createServerFn({ method: "POST" }).validator((id) => id).handler(createSsrRpc("6850ba403da9dec5aff45794eb52636ca540ddec2d9e59f5c75ccbb852bfeacb"));
|
|
56
|
+
/** Mint the key shown in the New-loop daemon connection command. */
|
|
57
|
+
var mintConnectKey = createServerFn({ method: "POST" }).handler(createSsrRpc("ce43dcb9366e7c8f7338a6ad28e4290b75a5ee3b13d0d2c9cb585020008f12c6"));
|
|
58
|
+
var DAEMON_UPGRADE_REQUIRED = "Daemon upgrade required to stop a running process. Run `npm install -g @kky42/pievo@latest`, then `pievo daemon restart`.";
|
|
59
|
+
function deriveLoopLifecycle(loop) {
|
|
60
|
+
if (loop.deleteRequestedAt != null) return "deleting";
|
|
61
|
+
const running = loop.runs.find((run) => run.phase === "running");
|
|
62
|
+
if (!loop.enabled && running?.cancelRequested) return "stopping";
|
|
63
|
+
if (!loop.enabled && (loop.running || running)) return "paused-finishing";
|
|
64
|
+
if (!loop.enabled) return "paused";
|
|
65
|
+
return "active";
|
|
66
|
+
}
|
|
67
|
+
/** Stable lifecycle badge shared by dashboard cards and loop detail. It shows
|
|
68
|
+
* only scheduling state and its durable pause cause; execution transients
|
|
69
|
+
* (queued/running/stopping) stay in the runs timeline and never replace it. */
|
|
70
|
+
function lifecyclePresentation(loop) {
|
|
71
|
+
if (loop.deleteRequestedAt != null) return {
|
|
72
|
+
label: "Deleting",
|
|
73
|
+
tone: "accent"
|
|
74
|
+
};
|
|
75
|
+
if (loop.enabled) return {
|
|
76
|
+
label: "Active",
|
|
77
|
+
tone: "success"
|
|
78
|
+
};
|
|
79
|
+
if (loop.pauseCause?.kind === "blocked") return {
|
|
80
|
+
label: "Paused · blocked",
|
|
81
|
+
tone: "attention"
|
|
82
|
+
};
|
|
83
|
+
if (loop.pauseCause?.kind === "failure-streak") return {
|
|
84
|
+
label: "Paused · failure streak",
|
|
85
|
+
tone: "attention"
|
|
86
|
+
};
|
|
87
|
+
if (loop.pauseCause?.kind === "owner") return {
|
|
88
|
+
label: "Paused · owner",
|
|
89
|
+
tone: "neutral"
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
label: "Paused",
|
|
93
|
+
tone: "neutral"
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function daemonStopSupport(protocol) {
|
|
97
|
+
return protocol === 4 ? {
|
|
98
|
+
supported: true,
|
|
99
|
+
label: `Daemon protocol 4 · Stop supported`
|
|
100
|
+
} : {
|
|
101
|
+
supported: false,
|
|
102
|
+
label: `Daemon protocol ${protocol ?? "unknown"} · upgrade required`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { runLoop as _, deriveLoopLifecycle as a, stopRun as b, getConfig as c, lifecyclePresentation as d, listLoops as f, pauseLoop as g, patchLoop as h, deleteLoop as i, getLoopDetail as l, mintConnectKey as m, createSsrRpc as n, getArtifact as o, loadOlderRuns as p, daemonStopSupport as r, getArtifacts as s, DAEMON_UPGRADE_REQUIRED as t, getRunDiff as u, startLoop as v, stopLoop as y };
|
|
@@ -1,43 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as toRunSummaries, i as toLoopSummaries, r as toLoopDetail, t as sortLoopSummariesByRecentRun } from "./loopProjection-
|
|
3
|
-
import {
|
|
4
|
-
import { n as createServerFn } from "./ssr.mjs";
|
|
1
|
+
import { A as listMachines, C as getMachine, E as hasRunningRun, G as startLoop$1, H as requestRunCancel, I as machinePresence, J as updateLoop, K as stopLoop$1, M as listRunsBefore, R as pauseLoop$1, S as getLoop, V as requestDeleteLoop, c as ensureServer, h as validateLoopEdit, k as listLoops$1, q as tryDeleteLoop, w as getRun, y as forceDeleteLoop } from "./boot-CYRi-wez.mjs";
|
|
2
|
+
import { a as toRunSummaries, i as toLoopSummaries, r as toLoopDetail, t as sortLoopSummariesByRecentRun } from "./loopProjection-esCjyZJg.mjs";
|
|
3
|
+
import { r as createServerFn } from "./ssr.mjs";
|
|
5
4
|
import { t as createServerRpc } from "./createServerRpc-BD8Xn_0_.mjs";
|
|
6
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/loopApi-
|
|
5
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/loopApi-Bez1rHV0.js
|
|
7
6
|
/**
|
|
8
7
|
* Server functions backing the dashboard. They run server-side (createServerFn
|
|
9
8
|
* → RPC) and call the IN-PROCESS scheduler + store directly — the scheduler
|
|
10
9
|
* lives in this same TanStack process (booted on first call via ensureServer).
|
|
11
10
|
* The machine-facing poll, CLI, report, and artifact-sync endpoints are sibling
|
|
12
11
|
* server routes in this same process, so one process owns the single scheduler.
|
|
13
|
-
*
|
|
14
|
-
* Reads and writes are scoped through requestScope/ownedLoop so auth-mode users
|
|
15
|
-
* can access only their own loops. Open mode intentionally shares all loops.
|
|
16
12
|
*/
|
|
17
13
|
function backend() {
|
|
18
14
|
return ensureServer();
|
|
19
15
|
}
|
|
20
|
-
|
|
21
|
-
* Resolve a loop and authorize the request against its owner. Returns the loop,
|
|
22
|
-
* or undefined when it's missing OR (gate on) owned by a different user — callers
|
|
23
|
-
* treat both as "not found" so existence never leaks across users.
|
|
24
|
-
*/
|
|
25
|
-
async function ownedLoop(id) {
|
|
16
|
+
async function findLoop(id) {
|
|
26
17
|
const loop = await getLoop(id);
|
|
27
|
-
|
|
28
|
-
const scope = await requestScope();
|
|
29
|
-
if (!canAccessLoop(loop.userId, scope)) return void 0;
|
|
30
|
-
return { loop };
|
|
18
|
+
return loop ? { loop } : void 0;
|
|
31
19
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
20
|
+
/**
|
|
21
|
+
* Client config. `pievoCli` is the CLI invocation prefix the skill + connect
|
|
22
|
+
* dialog use for every verb (`daemon start`, `new`, …) — defaults to the globally
|
|
23
|
+
* installed `pievo`. Set PIEVO_CLI locally to a runnable command that points at the in-repo
|
|
24
|
+
* daemon, e.g. `tsx /abs/packages/daemon/src/cli.ts` or
|
|
25
|
+
* `node /abs/packages/daemon/dist/cli.js`, so loops created from THIS server tell
|
|
26
|
+
* Claude Code to run your local code instead of the registry build.
|
|
27
|
+
*/
|
|
41
28
|
var getConfig_createServerFn_handler = createServerRpc({
|
|
42
29
|
id: "cbb6a1b09b309459bbba3dc3851ae85fc468658b3cda77e22b6c6f3e28b65af4",
|
|
43
30
|
name: "getConfig",
|
|
@@ -49,7 +36,9 @@ var getConfig = createServerFn({ method: "GET" }).handler(getConfig_createServer
|
|
|
49
36
|
pievoCli: custom || "pievo",
|
|
50
37
|
/** True when a non-default (dev) CLI is configured — the New-loop paste then
|
|
51
38
|
* carries an explicit `pievo-cli:` line so Claude Code uses it verbatim. */
|
|
52
|
-
customCli: !!custom
|
|
39
|
+
customCli: !!custom,
|
|
40
|
+
/** Best URL for other devices, published by the launcher (HTTPS, Tailscale, then LAN). */
|
|
41
|
+
publicUrl: process.env.PIEVO_PUBLIC_URL?.trim() || null
|
|
53
42
|
};
|
|
54
43
|
});
|
|
55
44
|
var listLoops_createServerFn_handler = createServerRpc({
|
|
@@ -59,9 +48,7 @@ var listLoops_createServerFn_handler = createServerRpc({
|
|
|
59
48
|
}, (opts) => listLoops.__executeServer(opts));
|
|
60
49
|
var listLoops = createServerFn({ method: "GET" }).handler(listLoops_createServerFn_handler, async () => {
|
|
61
50
|
await backend();
|
|
62
|
-
const
|
|
63
|
-
if (scope.enforce && !scope.userId) return [];
|
|
64
|
-
const [loopRows, machines] = await Promise.all([scope.enforce ? listLoopsForUser(scope.userId) : listLoops$1(), scope.enforce ? listMachinesForUser(scope.userId) : listMachines()]);
|
|
51
|
+
const [loopRows, machines] = await Promise.all([listLoops$1(), listMachines()]);
|
|
65
52
|
return sortLoopSummariesByRecentRun(await toLoopSummaries(loopRows.sort((a, b) => a.createdAt < b.createdAt ? 1 : -1), machines));
|
|
66
53
|
});
|
|
67
54
|
var getLoopDetail_createServerFn_handler = createServerRpc({
|
|
@@ -71,9 +58,9 @@ var getLoopDetail_createServerFn_handler = createServerRpc({
|
|
|
71
58
|
}, (opts) => getLoopDetail.__executeServer(opts));
|
|
72
59
|
var getLoopDetail = createServerFn({ method: "GET" }).validator((id) => id).handler(getLoopDetail_createServerFn_handler, async ({ data: id }) => {
|
|
73
60
|
await backend();
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
76
|
-
return toLoopDetail(
|
|
61
|
+
const found = await findLoop(id);
|
|
62
|
+
if (!found) throw new Error("This loop does not exist.");
|
|
63
|
+
return toLoopDetail(found.loop);
|
|
77
64
|
});
|
|
78
65
|
var loadOlderRuns_createServerFn_handler = createServerRpc({
|
|
79
66
|
id: "85fdf73d4fee43aed762f93c5d47d33200fbff39e2d082647dc921f610d32698",
|
|
@@ -82,7 +69,7 @@ var loadOlderRuns_createServerFn_handler = createServerRpc({
|
|
|
82
69
|
}, (opts) => loadOlderRuns.__executeServer(opts));
|
|
83
70
|
var loadOlderRuns = createServerFn({ method: "GET" }).validator((d) => d).handler(loadOlderRuns_createServerFn_handler, async ({ data }) => {
|
|
84
71
|
await backend();
|
|
85
|
-
if (!await
|
|
72
|
+
if (!await findLoop(data.loopId)) return [];
|
|
86
73
|
const limit = Math.min(Math.max(data.limit ?? 16, 1), 100);
|
|
87
74
|
return toRunSummaries(data.loopId, await listRunsBefore(data.loopId, data.beforeTs, limit));
|
|
88
75
|
});
|
|
@@ -93,8 +80,8 @@ var getArtifacts_createServerFn_handler = createServerRpc({
|
|
|
93
80
|
}, (opts) => getArtifacts.__executeServer(opts));
|
|
94
81
|
var getArtifacts = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifacts_createServerFn_handler, async ({ data }) => {
|
|
95
82
|
await backend();
|
|
96
|
-
if (!await
|
|
97
|
-
const { listLoopArtifacts } = await import("./artifactFiles-
|
|
83
|
+
if (!await findLoop(data.loopId)) return [];
|
|
84
|
+
const { listLoopArtifacts } = await import("./artifactFiles-Di1xDKvX.mjs");
|
|
98
85
|
return listLoopArtifacts(data.loopId);
|
|
99
86
|
});
|
|
100
87
|
var getArtifact_createServerFn_handler = createServerRpc({
|
|
@@ -104,8 +91,8 @@ var getArtifact_createServerFn_handler = createServerRpc({
|
|
|
104
91
|
}, (opts) => getArtifact.__executeServer(opts));
|
|
105
92
|
var getArtifact = createServerFn({ method: "GET" }).validator((d) => d).handler(getArtifact_createServerFn_handler, async ({ data }) => {
|
|
106
93
|
await backend();
|
|
107
|
-
if (!await
|
|
108
|
-
const { readLoopArtifact } = await import("./artifactFiles-
|
|
94
|
+
if (!await findLoop(data.loopId)) return { error: "file not found" };
|
|
95
|
+
const { readLoopArtifact } = await import("./artifactFiles-Di1xDKvX.mjs");
|
|
109
96
|
return readLoopArtifact(data.loopId, data.path);
|
|
110
97
|
});
|
|
111
98
|
var getRunDiff_createServerFn_handler = createServerRpc({
|
|
@@ -120,11 +107,11 @@ var getRunDiff = createServerFn({ method: "GET" }).validator((d) => d).handler(g
|
|
|
120
107
|
hasSnapshot: false,
|
|
121
108
|
files: []
|
|
122
109
|
};
|
|
123
|
-
if (!await
|
|
110
|
+
if (!await findLoop(run.loopId)) return {
|
|
124
111
|
hasSnapshot: false,
|
|
125
112
|
files: []
|
|
126
113
|
};
|
|
127
|
-
const { computeRunDiff } = await import("./
|
|
114
|
+
const { computeRunDiff } = await import("./boot-CYRi-wez.mjs").then((n) => n.i).then((n) => n.i);
|
|
128
115
|
return computeRunDiff(data.runId);
|
|
129
116
|
});
|
|
130
117
|
var patchLoop_createServerFn_handler = createServerRpc({
|
|
@@ -134,11 +121,11 @@ var patchLoop_createServerFn_handler = createServerRpc({
|
|
|
134
121
|
}, (opts) => patchLoop.__executeServer(opts));
|
|
135
122
|
var patchLoop = createServerFn({ method: "POST" }).validator((d) => d).handler(patchLoop_createServerFn_handler, async ({ data }) => {
|
|
136
123
|
const { scheduler } = await backend();
|
|
137
|
-
const
|
|
138
|
-
if (!
|
|
124
|
+
const found = await findLoop(data.id);
|
|
125
|
+
if (!found) return { error: "not found" };
|
|
139
126
|
const p = data.patch;
|
|
140
127
|
{
|
|
141
|
-
const validated = validateLoopEdit(
|
|
128
|
+
const validated = validateLoopEdit(found.loop, p);
|
|
142
129
|
if (!validated.ok) return { error: validated.detail };
|
|
143
130
|
const loop = await updateLoop(data.id, validated.value);
|
|
144
131
|
if (!loop) return { error: "not found" };
|
|
@@ -154,7 +141,7 @@ var pauseLoop_createServerFn_handler = createServerRpc({
|
|
|
154
141
|
}, (opts) => pauseLoop.__executeServer(opts));
|
|
155
142
|
var pauseLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(pauseLoop_createServerFn_handler, async ({ data: id }) => {
|
|
156
143
|
const { scheduler } = await backend();
|
|
157
|
-
if (!await
|
|
144
|
+
if (!await findLoop(id)) return { error: "not found" };
|
|
158
145
|
if (!await pauseLoop$1(id)) return { error: "not found" };
|
|
159
146
|
scheduler.removeLoop(id);
|
|
160
147
|
return { ok: true };
|
|
@@ -166,9 +153,9 @@ var startLoop_createServerFn_handler = createServerRpc({
|
|
|
166
153
|
}, (opts) => startLoop.__executeServer(opts));
|
|
167
154
|
var startLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(startLoop_createServerFn_handler, async ({ data: id }) => {
|
|
168
155
|
const { scheduler } = await backend();
|
|
169
|
-
const
|
|
170
|
-
if (!
|
|
171
|
-
if (
|
|
156
|
+
const found = await findLoop(id);
|
|
157
|
+
if (!found) return { error: "not found" };
|
|
158
|
+
if (found.loop.deleteRequestedAt) return { error: "loop is being deleted" };
|
|
172
159
|
const loop = await startLoop$1(id);
|
|
173
160
|
if (!loop) return { error: "not found" };
|
|
174
161
|
scheduler.addLoop(loop);
|
|
@@ -181,10 +168,10 @@ var stopLoop_createServerFn_handler = createServerRpc({
|
|
|
181
168
|
}, (opts) => stopLoop.__executeServer(opts));
|
|
182
169
|
var stopLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(stopLoop_createServerFn_handler, async ({ data: id }) => {
|
|
183
170
|
const { scheduler } = await backend();
|
|
184
|
-
const
|
|
185
|
-
if (!
|
|
171
|
+
const found = await findLoop(id);
|
|
172
|
+
if (!found) return { error: "not found" };
|
|
186
173
|
if (await hasRunningRun(id)) {
|
|
187
|
-
if ((await getMachine(
|
|
174
|
+
if ((await getMachine(found.loop.machineId))?.daemonProtocol !== 4) return { error: "Daemon upgrade required to stop a running process" };
|
|
188
175
|
}
|
|
189
176
|
const stopped = await stopLoop$1(id);
|
|
190
177
|
if (!stopped) return { error: "not found" };
|
|
@@ -201,20 +188,20 @@ var deleteLoop_createServerFn_handler = createServerRpc({
|
|
|
201
188
|
}, (opts) => deleteLoop.__executeServer(opts));
|
|
202
189
|
var deleteLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(deleteLoop_createServerFn_handler, async ({ data: id }) => {
|
|
203
190
|
const { scheduler } = await backend();
|
|
204
|
-
const
|
|
205
|
-
if (!
|
|
206
|
-
const machine = await getMachine(
|
|
191
|
+
const found = await findLoop(id);
|
|
192
|
+
if (!found) return { error: "not found" };
|
|
193
|
+
const machine = await getMachine(found.loop.machineId);
|
|
207
194
|
const unreachable = machinePresence(machine?.online, machine?.lastSeen) !== "online";
|
|
208
195
|
if (!unreachable && await hasRunningRun(id) && machine?.daemonProtocol !== 4) return { error: "Daemon upgrade required to stop a running process" };
|
|
209
196
|
scheduler.removeLoop(id);
|
|
210
197
|
if (!await requestDeleteLoop(id)) return { error: "not found" };
|
|
211
198
|
if (unreachable) {
|
|
212
199
|
if (!await forceDeleteLoop(id)) return { error: "delete failed; server data was not deleted" };
|
|
213
|
-
const { logger } = await import("./
|
|
200
|
+
const { logger } = await import("./boot-CYRi-wez.mjs").then((n) => n.N).then((n) => n.Jt);
|
|
214
201
|
logger.child({ mod: "loop-lifecycle" }).warn({
|
|
215
202
|
action: "unreachable-delete",
|
|
216
203
|
loopId: id,
|
|
217
|
-
machineId:
|
|
204
|
+
machineId: found.loop.machineId
|
|
218
205
|
}, "unreachable-machine delete: retired execution authority and removed server data");
|
|
219
206
|
return {
|
|
220
207
|
ok: true,
|
|
@@ -235,7 +222,7 @@ var runLoop_createServerFn_handler = createServerRpc({
|
|
|
235
222
|
}, (opts) => runLoop.__executeServer(opts));
|
|
236
223
|
var runLoop = createServerFn({ method: "POST" }).validator((id) => id).handler(runLoop_createServerFn_handler, async ({ data: id }) => {
|
|
237
224
|
const { scheduler } = await backend();
|
|
238
|
-
if (!await
|
|
225
|
+
if (!await findLoop(id)) return { error: "not found" };
|
|
239
226
|
const queued = await scheduler.runNow(id);
|
|
240
227
|
if (!("run" in queued)) return { error: queued.reason };
|
|
241
228
|
return {
|
|
@@ -253,9 +240,9 @@ var stopRun_createServerFn_handler = createServerRpc({
|
|
|
253
240
|
var stopRun = createServerFn({ method: "POST" }).validator((id) => id).handler(stopRun_createServerFn_handler, async ({ data: id }) => {
|
|
254
241
|
await backend();
|
|
255
242
|
const run = await getRun(id);
|
|
256
|
-
const
|
|
257
|
-
if (!run || !
|
|
258
|
-
if (run.phase === "running" && (await getMachine(
|
|
243
|
+
const found = run ? await findLoop(run.loopId) : void 0;
|
|
244
|
+
if (!run || !found) return { error: "run not found" };
|
|
245
|
+
if (run.phase === "running" && (await getMachine(found.loop.machineId))?.daemonProtocol !== 4) return { error: "Daemon upgrade required to stop a running process" };
|
|
259
246
|
const result = await requestRunCancel(run.loopId, id);
|
|
260
247
|
return result ? {
|
|
261
248
|
ok: true,
|
|
@@ -269,12 +256,10 @@ var mintConnectKey_createServerFn_handler = createServerRpc({
|
|
|
269
256
|
}, (opts) => mintConnectKey.__executeServer(opts));
|
|
270
257
|
var mintConnectKey = createServerFn({ method: "POST" }).handler(mintConnectKey_createServerFn_handler, async () => {
|
|
271
258
|
await backend();
|
|
272
|
-
const
|
|
273
|
-
if (scope.enforce && !scope.userId) return { error: "not signed in" };
|
|
274
|
-
const { mintDeviceToken, rememberConnectKey } = await import("./tokens-DzUv7CCp.mjs");
|
|
259
|
+
const { mintDeviceToken, rememberConnectKey } = await import("./boot-CYRi-wez.mjs").then((n) => n.N).then((n) => n.g);
|
|
275
260
|
const token = mintDeviceToken();
|
|
276
|
-
await rememberConnectKey(token
|
|
261
|
+
await rememberConnectKey(token);
|
|
277
262
|
return { token };
|
|
278
263
|
});
|
|
279
264
|
//#endregion
|
|
280
|
-
export { deleteLoop_createServerFn_handler, getArtifact_createServerFn_handler, getArtifacts_createServerFn_handler,
|
|
265
|
+
export { deleteLoop_createServerFn_handler, getArtifact_createServerFn_handler, getArtifacts_createServerFn_handler, getConfig_createServerFn_handler, getLoopDetail_createServerFn_handler, getRunDiff_createServerFn_handler, listLoops_createServerFn_handler, loadOlderRuns_createServerFn_handler, mintConnectKey_createServerFn_handler, patchLoop_createServerFn_handler, pauseLoop_createServerFn_handler, runLoop_createServerFn_handler, startLoop_createServerFn_handler, stopLoop_createServerFn_handler, stopRun_createServerFn_handler };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/loopProjection-
|
|
1
|
+
import { B as reconciliationStatesForRuns, C as getMachine, E as hasRunningRun, I as machinePresence, T as hasPendingRun, _ as countRuns, a as canonicalLoopEnvelope, j as listRuns, n as MIN_DAEMON_VERSION, o as canonicalLoopSummary, s as daemonNeedsUpdate, z as recentLoopUsage } from "./boot-CYRi-wez.mjs";
|
|
2
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/loopProjection-esCjyZJg.js
|
|
3
3
|
var SUMMARY_RUNS = 18;
|
|
4
4
|
var RECENT_USAGE_WINDOW_MS = 10080 * 60 * 1e3;
|
|
5
5
|
/** Dashboard order: loops with runs first, most recent run first. The incoming
|
|
@@ -60,13 +60,7 @@ async function toLoopSummaryWithMachine(loop, machine) {
|
|
|
60
60
|
const recentUsage = await recentLoopUsage(loop.id, (/* @__PURE__ */ new Date(Date.now() - RECENT_USAGE_WINDOW_MS)).toISOString());
|
|
61
61
|
const presence = machinePresence(machine?.online, machine?.lastSeen);
|
|
62
62
|
return {
|
|
63
|
-
|
|
64
|
-
name: loop.name,
|
|
65
|
-
schedule: scheduleFromLoop(loop),
|
|
66
|
-
workdir: loop.workdir,
|
|
67
|
-
agent: loop.agent,
|
|
68
|
-
model: loop.model ?? null,
|
|
69
|
-
reasoningEffort: loop.reasoningEffort ?? null,
|
|
63
|
+
...canonicalLoopSummary(loop),
|
|
70
64
|
machine: {
|
|
71
65
|
id: loop.machineId,
|
|
72
66
|
name: machine?.name || "",
|
|
@@ -95,17 +89,7 @@ async function toLoopSummaries(loops, machines) {
|
|
|
95
89
|
}
|
|
96
90
|
function toLoopFull(loop) {
|
|
97
91
|
return {
|
|
98
|
-
|
|
99
|
-
name: loop.name,
|
|
100
|
-
schedule: scheduleFromLoop(loop),
|
|
101
|
-
workdir: loop.workdir,
|
|
102
|
-
agent: loop.agent,
|
|
103
|
-
model: loop.model ?? null,
|
|
104
|
-
reasoningEffort: loop.reasoningEffort ?? null,
|
|
105
|
-
prompt: loop.prompt,
|
|
106
|
-
statusDefinitions: statusDefinitionsFromLoop(loop),
|
|
107
|
-
artifacts: loop.artifacts,
|
|
108
|
-
enabled: loop.enabled,
|
|
92
|
+
...canonicalLoopEnvelope(loop),
|
|
109
93
|
pauseCause: loop.pauseCause ?? null,
|
|
110
94
|
createdAt: loop.createdAt,
|
|
111
95
|
updatedAt: loop.updatedAt
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { o as __toESM } from "../_runtime.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { X as validateLoopTags, g as CODING_AGENTS } from "./boot-CYRi-wez.mjs";
|
|
3
3
|
import { g as require_react, h as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
|
|
4
4
|
import { d as useNavigate, u as Link } from "../_libs/@tanstack/react-router+[...].mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { a as Timeline,
|
|
8
|
-
import { n as artifactKind, t as Route } from "./artifactKind-
|
|
9
|
-
import { t as SignIn } from "./SignIn-Bp3uWaCQ.mjs";
|
|
5
|
+
import { _ as runLoop, a as deriveLoopLifecycle, g as pauseLoop, h as patchLoop, i as deleteLoop, l as getLoopDetail, o as getArtifact, p as loadOlderRuns, r as daemonStopSupport, s as getArtifacts, t as DAEMON_UPGRADE_REQUIRED, v as startLoop, y as stopLoop } from "./lifecycleUi-BsbUsi5K.mjs";
|
|
6
|
+
import { A as tsShort, E as runPulseStyle, M as useFlash, O as sectionHeadCls, S as labelCls, _ as fmt, a as Loading, b as humanBytes, c as btn, d as btnQuiet, g as dur, i as LoadErrorCard, k as selectCls, l as btnDanger, m as dotLabel, n as ErrorBanner, p as dotColor, r as FlashLine, t as ConfirmBar, u as btnPrimary, w as rel, x as inputCls, y as focusRing } from "./actionUi-DE-Pb2tv.mjs";
|
|
7
|
+
import { a as Timeline, l as mergeRuns, n as MachinesModal, t as LoopOverview } from "./MachinesModal-CmVMec6B.mjs";
|
|
8
|
+
import { n as artifactKind, t as Route } from "./artifactKind-DqpmtxDU.mjs";
|
|
10
9
|
import { t as purify } from "../_libs/dompurify.mjs";
|
|
11
10
|
import { t as g } from "../_libs/marked.mjs";
|
|
12
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-
|
|
11
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/loops._loopId-KUezNY69.js
|
|
13
12
|
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
14
13
|
var import_jsx_runtime = require_jsx_runtime();
|
|
15
14
|
/** Download URL for one artifact. Each path segment is encoded independently so
|
|
@@ -368,6 +367,8 @@ function initState(initial) {
|
|
|
368
367
|
const schedule = initial?.schedule;
|
|
369
368
|
return {
|
|
370
369
|
name: initial?.name ?? "",
|
|
370
|
+
tags: initial?.tags ?? [],
|
|
371
|
+
tagDraft: "",
|
|
371
372
|
mode: schedule?.mode ?? "cron",
|
|
372
373
|
cron: schedule?.mode === "cron" ? schedule.cron : "0 */3 * * *",
|
|
373
374
|
timezone: schedule?.mode === "cron" ? schedule.timezone : Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
|
|
@@ -447,10 +448,37 @@ function TextArea({ label, value, onChange, rows = 4, mono, hint }) {
|
|
|
447
448
|
var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial }, ref) {
|
|
448
449
|
const [form, setForm] = (0, import_react.useState)(() => initState(initial));
|
|
449
450
|
const [error, setError] = (0, import_react.useState)(null);
|
|
451
|
+
const [tagError, setTagError] = (0, import_react.useState)(null);
|
|
452
|
+
const tagsLabelId = (0, import_react.useId)();
|
|
453
|
+
const tagsHintId = (0, import_react.useId)();
|
|
454
|
+
const tagsErrorId = (0, import_react.useId)();
|
|
455
|
+
const tagGroupRef = (0, import_react.useRef)(null);
|
|
456
|
+
const tagInputRef = (0, import_react.useRef)(null);
|
|
450
457
|
const set = (key, value) => setForm((current) => ({
|
|
451
458
|
...current,
|
|
452
459
|
[key]: value
|
|
453
460
|
}));
|
|
461
|
+
const commitTagDraft = () => {
|
|
462
|
+
const additions = form.tagDraft.trim() ? [form.tagDraft] : [];
|
|
463
|
+
if (!additions.length) {
|
|
464
|
+
set("tagDraft", "");
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const result = validateLoopTags([...form.tags, ...additions]);
|
|
468
|
+
if (!result.ok) {
|
|
469
|
+
setTagError(result.detail);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
setForm((current) => ({
|
|
473
|
+
...current,
|
|
474
|
+
tags: result.value,
|
|
475
|
+
tagDraft: ""
|
|
476
|
+
}));
|
|
477
|
+
setTagError(null);
|
|
478
|
+
if (result.value.length === 4) requestAnimationFrame(() => {
|
|
479
|
+
if (document.activeElement === document.body) tagGroupRef.current?.focus();
|
|
480
|
+
});
|
|
481
|
+
};
|
|
454
482
|
(0, import_react.useImperativeHandle)(ref, () => ({ read() {
|
|
455
483
|
const missing = [
|
|
456
484
|
["Name", form.name],
|
|
@@ -464,6 +492,12 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial }, ref)
|
|
|
464
492
|
setError(`${missing[0]} is required.`);
|
|
465
493
|
return null;
|
|
466
494
|
}
|
|
495
|
+
const tagResult = validateLoopTags([...form.tags, ...form.tagDraft.trim() ? [form.tagDraft] : []]);
|
|
496
|
+
if (!tagResult.ok) {
|
|
497
|
+
setTagError(tagResult.detail);
|
|
498
|
+
setError(null);
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
467
501
|
const delayMinutes = Number(form.delayMinutes);
|
|
468
502
|
if (form.mode === "continuous" && (!Number.isInteger(delayMinutes) || delayMinutes < 1)) {
|
|
469
503
|
setError("Continuous delay must be an integer of at least 1 minute.");
|
|
@@ -479,8 +513,10 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial }, ref)
|
|
|
479
513
|
delayMinutes
|
|
480
514
|
};
|
|
481
515
|
setError(null);
|
|
516
|
+
setTagError(null);
|
|
482
517
|
return {
|
|
483
518
|
name: form.name.trim(),
|
|
519
|
+
tags: tagResult.value,
|
|
484
520
|
schedule,
|
|
485
521
|
workdir: form.workdir.trim(),
|
|
486
522
|
agent: form.agent,
|
|
@@ -506,6 +542,79 @@ var LoopForm = (0, import_react.forwardRef)(function LoopForm({ initial }, ref)
|
|
|
506
542
|
value: form.name,
|
|
507
543
|
onChange: (value) => set("name", value)
|
|
508
544
|
}),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
546
|
+
className: "min-w-0",
|
|
547
|
+
children: [
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
549
|
+
id: tagsLabelId,
|
|
550
|
+
className: labelCls,
|
|
551
|
+
children: "Tags"
|
|
552
|
+
}),
|
|
553
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
554
|
+
ref: tagGroupRef,
|
|
555
|
+
role: "group",
|
|
556
|
+
tabIndex: -1,
|
|
557
|
+
"aria-labelledby": tagsLabelId,
|
|
558
|
+
"aria-describedby": `${tagsHintId}${tagError ? ` ${tagsErrorId}` : ""}`,
|
|
559
|
+
"aria-invalid": tagError ? "true" : void 0,
|
|
560
|
+
className: "flex min-h-10 flex-wrap items-center gap-1.5 rounded-control border border-wire bg-surface px-2.5 py-1.5 outline-none transition-shadow focus-within:border-transparent focus-within:shadow-focus",
|
|
561
|
+
children: [form.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
562
|
+
className: "inline-flex h-6 max-w-full items-center gap-1 rounded-full bg-raised px-2.5 text-caption font-medium text-secondary",
|
|
563
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
564
|
+
className: "max-w-52 truncate",
|
|
565
|
+
title: tag,
|
|
566
|
+
children: tag
|
|
567
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
568
|
+
type: "button",
|
|
569
|
+
"aria-label": `Remove tag ${tag}`,
|
|
570
|
+
onClick: () => {
|
|
571
|
+
set("tags", form.tags.filter((value) => value !== tag));
|
|
572
|
+
setTagError(null);
|
|
573
|
+
requestAnimationFrame(() => (tagInputRef.current ?? tagGroupRef.current)?.focus());
|
|
574
|
+
},
|
|
575
|
+
className: `-mr-1 inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full text-disabled transition-colors hover:bg-surface hover:text-primary ${focusRing}`,
|
|
576
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
577
|
+
"aria-hidden": true,
|
|
578
|
+
children: "×"
|
|
579
|
+
})
|
|
580
|
+
})]
|
|
581
|
+
}, tag)), form.tags.length < 4 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
582
|
+
ref: tagInputRef,
|
|
583
|
+
"aria-label": "Add tag",
|
|
584
|
+
value: form.tagDraft,
|
|
585
|
+
placeholder: form.tags.length ? "Add another…" : "Add a tag…",
|
|
586
|
+
onChange: (event) => {
|
|
587
|
+
set("tagDraft", event.target.value);
|
|
588
|
+
setTagError(null);
|
|
589
|
+
},
|
|
590
|
+
onKeyDown: (event) => {
|
|
591
|
+
if (event.nativeEvent.isComposing) return;
|
|
592
|
+
if (event.key === "Enter") {
|
|
593
|
+
event.preventDefault();
|
|
594
|
+
commitTagDraft();
|
|
595
|
+
} else if (event.key === "Backspace" && !form.tagDraft && form.tags.length) set("tags", form.tags.slice(0, -1));
|
|
596
|
+
},
|
|
597
|
+
onBlur: commitTagDraft,
|
|
598
|
+
className: "h-6 min-w-28 flex-1 bg-transparent px-1 text-sm text-primary outline-none placeholder:text-disabled"
|
|
599
|
+
})]
|
|
600
|
+
}),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
602
|
+
id: tagsHintId,
|
|
603
|
+
className: hintCls,
|
|
604
|
+
children: [
|
|
605
|
+
"Up to ",
|
|
606
|
+
4,
|
|
607
|
+
". Press Enter to add."
|
|
608
|
+
]
|
|
609
|
+
}),
|
|
610
|
+
tagError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
611
|
+
id: tagsErrorId,
|
|
612
|
+
role: "alert",
|
|
613
|
+
className: "mt-1 text-caption text-accent",
|
|
614
|
+
children: tagError
|
|
615
|
+
})
|
|
616
|
+
]
|
|
617
|
+
}),
|
|
509
618
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
510
619
|
className: "min-w-0",
|
|
511
620
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
|
|
@@ -971,6 +1080,20 @@ function LoopDetailView({ id }) {
|
|
|
971
1080
|
children: configurationScheduleText
|
|
972
1081
|
})
|
|
973
1082
|
}),
|
|
1083
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Config, {
|
|
1084
|
+
label: "Tags",
|
|
1085
|
+
children: loop.tags.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1086
|
+
className: "flex flex-wrap gap-1.5",
|
|
1087
|
+
children: loop.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1088
|
+
className: "inline-flex h-[22px] max-w-52 items-center truncate rounded-full bg-raised px-2.5 text-caption font-medium text-secondary",
|
|
1089
|
+
title: tag,
|
|
1090
|
+
children: tag
|
|
1091
|
+
}, tag))
|
|
1092
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1093
|
+
className: "text-disabled",
|
|
1094
|
+
children: "None"
|
|
1095
|
+
})
|
|
1096
|
+
}),
|
|
974
1097
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Config, {
|
|
975
1098
|
label: "Working directory",
|
|
976
1099
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
|
|
@@ -1082,7 +1205,7 @@ function EditHead({ name, onBack }) {
|
|
|
1082
1205
|
}),
|
|
1083
1206
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
1084
1207
|
className: "mt-1.5 text-meta text-secondary",
|
|
1085
|
-
children: "Edit
|
|
1208
|
+
children: "Edit tags, schedule, execution settings, prompt, status definitions, and exact artifact paths."
|
|
1086
1209
|
})
|
|
1087
1210
|
] });
|
|
1088
1211
|
}
|
|
@@ -1163,25 +1286,11 @@ function RunsSection({ loopId, summary, runs, older, onMore, onPickRun }) {
|
|
|
1163
1286
|
/**
|
|
1164
1287
|
* Loop detail page — `/loops/$loopId`: a loop header and action toolbar, the
|
|
1165
1288
|
* exact artifact Files panel, and the runs timeline. The view owns its own
|
|
1166
|
-
* data + self-poll
|
|
1167
|
-
* like the dashboard loader). Run rows link on to `/loops/$loopId/runs/$runId`.
|
|
1168
|
-
*
|
|
1169
|
-
* Auth-gated exactly like the dashboard (`/`): Better Auth's session hook keeps a
|
|
1170
|
-
* logged-out or expired deep link from mounting the ownership-scoped data view.
|
|
1289
|
+
* data + self-poll. Run rows link on to `/loops/$loopId/runs/$runId`.
|
|
1171
1290
|
*/
|
|
1172
1291
|
function LoopDetailPage() {
|
|
1173
1292
|
const { loopId } = Route.useParams();
|
|
1174
|
-
|
|
1175
|
-
const { data: session, isPending } = useSession();
|
|
1176
|
-
if (auth.enabled && isPending) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", {
|
|
1177
|
-
className: "mx-auto max-w-[1360px] px-8 pt-10",
|
|
1178
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Loading, {})
|
|
1179
|
-
});
|
|
1180
|
-
if (auth.enabled && !session) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SignIn, { callbackURL: `/loops/${loopId}` });
|
|
1181
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [!auth.enabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1182
|
-
className: "mx-auto max-w-[1360px] px-8 pt-6",
|
|
1183
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OpenModeWarning, {})
|
|
1184
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopDetailView, { id: loopId })] });
|
|
1293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoopDetailView, { id: loopId });
|
|
1185
1294
|
}
|
|
1186
1295
|
//#endregion
|
|
1187
1296
|
export { LoopDetailPage as component };
|