loopable-cli 0.2.0 → 0.3.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/_connectorId-CDCuSgpN.js +1 -0
- package/.output/public/assets/_loopId-DOnIsVTW.js +1 -0
- package/.output/public/assets/_taskId-BO5MZnlZ.js +1 -0
- package/.output/public/assets/agents-CBozi7oi.js +1 -0
- package/.output/public/assets/alert-Bn_wjgTX.js +1 -0
- package/.output/public/assets/button-K3ypIhAZ.js +1 -0
- package/.output/public/assets/card-DiVnaTIE.js +1 -0
- package/.output/public/assets/chevron-right-BrctLtFK.js +1 -0
- package/.output/public/assets/connection-status-DKWelvLO.js +1 -0
- package/.output/public/assets/connector-icon-CEbdE71G.js +1 -0
- package/.output/public/assets/connectors-JyX3IzJj.js +1 -0
- package/.output/public/assets/gaps-PjmcbaWo.js +1 -0
- package/.output/public/assets/inbox-CujRR0Cz.js +1 -0
- package/.output/public/assets/index-C9SQ_Baq.js +16 -0
- package/.output/public/assets/loop-form-Dw3cuTzw.js +1 -0
- package/.output/public/assets/loops-DcEfZa2_.js +1 -0
- package/.output/public/assets/manifests-yJpevyye.js +1 -0
- package/.output/public/assets/new-CwsnNuRW.js +1 -0
- package/.output/public/assets/page-bvnfRMum.js +1 -0
- package/.output/public/assets/play-yHLs4DjK.js +1 -0
- package/.output/public/assets/plus-Ber25lrU.js +1 -0
- package/.output/public/assets/preload-helper-BoU_7EQC.js +3 -0
- package/.output/public/assets/refresh-cw-BzSY7M8I.js +1 -0
- package/.output/public/assets/rotate-ccw-DLv9EfCX.js +1 -0
- package/.output/public/assets/runners-DzX-RU3i.js +2 -0
- package/.output/public/assets/select-C9grIFwG.js +1 -0
- package/.output/public/assets/setting-fields-DUc3npgh.js +3 -0
- package/.output/public/assets/styles-B9B98zLk.css +2 -0
- package/.output/public/assets/switch-DwABVI6d.js +1 -0
- package/.output/public/assets/task-list-Ddk8-qt7.js +1 -0
- package/.output/public/assets/textarea-Ds-gIYUQ.js +1 -0
- package/.output/public/assets/time-goBWd-5J.js +1 -0
- package/.output/public/assets/use-live-tasks-DZNNuECy.js +1 -0
- package/.output/public/assets/useCompositeListItem-P4Nmmn7j.js +1 -0
- package/.output/public/assets/usePositioner-B7i9Ejzh.js +1 -0
- package/.output/server/_chunks/ssr-renderer.mjs +1 -1
- package/.output/server/_connectorId-COuQN02a.mjs +512 -0
- package/.output/server/_libs/@base-ui/react+[...].mjs +1410 -804
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
- package/.output/server/_libs/lucide-react.mjs +93 -84
- package/.output/server/_libs/next-themes.mjs +1 -1
- package/.output/server/_libs/sonner.mjs +1 -1
- package/.output/server/_loopId-CZh6_Yhr.mjs +310 -0
- package/.output/server/_ssr/{callback-D20cVD2w.mjs → access-DTttr563.mjs} +37 -20
- package/.output/server/_ssr/{agents-CrUmIQpi.mjs → agents-B_qo1gpL.mjs} +196 -7
- package/.output/server/_ssr/{agents-Dms_6TBF.mjs → agents-Bz10gz_m.mjs} +8 -8
- package/.output/server/_ssr/agents-CjbOUp3Z.mjs +206 -0
- package/.output/server/_ssr/{alert-DQvzE7bu.mjs → alert-C2WBWfzo.mjs} +2 -2
- package/.output/server/_ssr/card-r1cV-PCN.mjs +36 -0
- package/.output/server/_ssr/{client-BtVRVhQ2.mjs → client-Dk3SD8Il.mjs} +5 -1
- package/.output/server/_ssr/connection-status-BogAL-Fj.mjs +32 -0
- package/.output/server/_ssr/{connections-ypex3qUd.mjs → connections-Cqvb6Gw2.mjs} +1109 -263
- package/.output/server/_ssr/connector-icon-DrhVbhs6.mjs +190 -0
- package/.output/server/_ssr/connectors-BfS5tQKr.mjs +81 -0
- package/.output/server/_ssr/{connectors-BZly0yGF.mjs → connectors-DJI-rzPU.mjs} +21 -10
- package/.output/server/_ssr/{createServerRpc-DPDrnFdH.mjs → createServerRpc-DDrp2nLT.mjs} +2 -2
- package/.output/server/_ssr/{gaps-D2Zh8sEo.mjs → gaps-CcvHiLcj.mjs} +18 -10
- package/.output/server/_ssr/inbox-D1ef761v.mjs +178 -0
- package/.output/server/_ssr/loop-form-DWwOR05R.mjs +346 -0
- package/.output/server/_ssr/{loops-Og_G3KyZ.mjs → loops-6WhUe_lc.mjs} +228 -25
- package/.output/server/_ssr/loops-DHPjzG-t.mjs +217 -0
- package/.output/server/_ssr/new-ChKBdcXJ.mjs +245 -0
- package/.output/server/_ssr/page-DZVxKvdn.mjs +120 -0
- package/.output/server/_ssr/{router-BbrBz36P.mjs → router-DdwREiOf.mjs} +167 -489
- package/.output/server/_ssr/runners-CK9Cx9fS.mjs +217 -0
- package/.output/server/_ssr/runners-CrznFPHt.mjs +140 -0
- package/.output/server/_ssr/runners-W-pgo5yo.mjs +55 -0
- package/.output/server/_ssr/{secrets-CRnpwGBh.mjs → secrets-CV5scFlt.mjs} +2 -2
- package/.output/server/_ssr/select-BtndHhHb.mjs +76 -0
- package/.output/server/_ssr/{setting-fields-mpXfGftI.mjs → setting-fields-LNgywAW7.mjs} +25 -20
- package/.output/server/_ssr/ssr.mjs +49 -40
- package/.output/server/_ssr/{start-BgTj-h_C.mjs → start-C_j-e4vF.mjs} +10 -6
- package/.output/server/_ssr/{switch-1pnd_bPJ.mjs → switch-odxNO_S4.mjs} +3 -3
- package/.output/server/_ssr/task-list-Dnmq_WeE.mjs +150 -0
- package/.output/server/_ssr/{tasks-LIi-W4cy.mjs → tasks-D-kXLgVP.mjs} +13 -13
- package/.output/server/_ssr/{tasks-B_QmDFVs.mjs → tasks-D7aUvA33.mjs} +55 -17
- package/.output/server/_ssr/{textarea-CHJTKtsJ.mjs → textarea-D2c_vTIC.mjs} +2 -2
- package/.output/server/_ssr/time-Cy8TZP0Z.mjs +13 -0
- package/.output/server/_ssr/use-live-tasks-BzhTkEOL.mjs +40 -0
- package/.output/server/_tanstack-start-manifest_v-2HUdn-2E.mjs +166 -0
- package/.output/server/_taskId-D3KkNJW1.mjs +263 -0
- package/.output/server/index.mjs +204 -162
- package/README.md +54 -19
- package/dist/cli.mjs +185 -67
- package/dist/dispatcher.mjs +1443 -277
- package/dist/runner.mjs +333 -46
- package/drizzle/0025_prompt_tasks_done.sql +2 -0
- package/drizzle/0026_guidance_into_prompt.sql +3 -0
- package/drizzle/0027_relative_folders.sql +5 -0
- package/drizzle/0028_runner_version.sql +5 -0
- package/drizzle/meta/_journal.json +29 -1
- package/package.json +23 -17
- package/.output/public/assets/_connectorId-m67WbiJ8.js +0 -1
- package/.output/public/assets/_loopId-Bf4K5sdd.js +0 -1
- package/.output/public/assets/_taskId-eCKkcVOx.js +0 -1
- package/.output/public/assets/alert-BT2EVMJP.js +0 -1
- package/.output/public/assets/arrow-left-CWUZt6k2.js +0 -1
- package/.output/public/assets/arrow-right-dy_oOg_c.js +0 -1
- package/.output/public/assets/connection-status-DCqqmY_6.js +0 -1
- package/.output/public/assets/connector-icon-qGpNsPgH.js +0 -1
- package/.output/public/assets/connectors-DxXlc9zF.js +0 -1
- package/.output/public/assets/external-link-DC11orFA.js +0 -1
- package/.output/public/assets/gaps-CoTA-PzA.js +0 -1
- package/.output/public/assets/inbox-CLEXUXCI.js +0 -1
- package/.output/public/assets/index-Cndsw84p.js +0 -16
- package/.output/public/assets/loader-B4Epchm_.js +0 -1
- package/.output/public/assets/loop-form-BvizlZdR.js +0 -1
- package/.output/public/assets/loops-Dbe_mf5T.js +0 -1
- package/.output/public/assets/new-DPEaXKAY.js +0 -1
- package/.output/public/assets/play-DD4xQgvi.js +0 -1
- package/.output/public/assets/preload-helper-CfdAYKD7.js +0 -3
- package/.output/public/assets/rolldown-runtime-CbXtAM7H.js +0 -1
- package/.output/public/assets/runners-BVBggS5B.js +0 -1
- package/.output/public/assets/select-Cppu-hti.js +0 -1
- package/.output/public/assets/setting-fields-BT1naVJX.js +0 -3
- package/.output/public/assets/styles-D3sonCfX.css +0 -2
- package/.output/public/assets/switch-hRIbNGOj.js +0 -1
- package/.output/public/assets/task-list-CrptnI1N.js +0 -1
- package/.output/public/assets/textarea-Fyuzi6Vp.js +0 -1
- package/.output/public/assets/trash-2-BXZzBsoV.js +0 -1
- package/.output/public/assets/useValueChanged-VVyq4hb9.js +0 -1
- package/.output/server/_connectorId-DcSnoRjk.mjs +0 -421
- package/.output/server/_loopId-G_TAkYtS.mjs +0 -272
- package/.output/server/_ssr/access-B7TcOZ7F.mjs +0 -42
- package/.output/server/_ssr/connection-status-BZr3Y-IC.mjs +0 -31
- package/.output/server/_ssr/connector-icon-CFrrHjzR.mjs +0 -37
- package/.output/server/_ssr/connectors-4yzKb0KG.mjs +0 -106
- package/.output/server/_ssr/inbox-C2VBGLa5.mjs +0 -114
- package/.output/server/_ssr/loop-form-D-U-kU4k.mjs +0 -413
- package/.output/server/_ssr/loops-D0XJ8eBb.mjs +0 -222
- package/.output/server/_ssr/new-CajvgIog.mjs +0 -169
- package/.output/server/_ssr/runners-B_WuF8UJ.mjs +0 -32
- package/.output/server/_ssr/runners-D-0_lfiq.mjs +0 -106
- package/.output/server/_ssr/runners-zqF_zbEc.mjs +0 -116
- package/.output/server/_ssr/task-list-BnQJ94Dk.mjs +0 -187
- package/.output/server/_tanstack-start-manifest_v-BCHAazE8.mjs +0 -129
- package/.output/server/_taskId-CIv0ajIx.mjs +0 -256
|
@@ -1,24 +1,42 @@
|
|
|
1
1
|
import { f as eq } from "../_libs/drizzle-orm.mjs";
|
|
2
|
-
import { n as agentSettings, r as appSettings, s as db } from "./client-
|
|
3
|
-
import { n as isHosted } from "./secrets-
|
|
2
|
+
import { n as agentSettings, r as appSettings, s as db } from "./client-Dk3SD8Il.mjs";
|
|
3
|
+
import { n as isHosted } from "./secrets-CV5scFlt.mjs";
|
|
4
4
|
import { accessSync, constants, createWriteStream, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { homedir, tmpdir } from "node:os";
|
|
7
7
|
import { execFile, spawn } from "node:child_process";
|
|
8
8
|
import { promisify } from "node:util";
|
|
9
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/agents-
|
|
9
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/agents-B_qo1gpL.js
|
|
10
10
|
function defineAgentManifest(manifest) {
|
|
11
11
|
return manifest;
|
|
12
12
|
}
|
|
13
13
|
function defineAgentRuntime(runtime) {
|
|
14
14
|
return runtime;
|
|
15
15
|
}
|
|
16
|
+
var claudeManifest = defineAgentManifest({
|
|
17
|
+
id: "claude",
|
|
18
|
+
name: "Claude Code",
|
|
19
|
+
tagline: "Anthropic's coding agent, driven through its print mode.",
|
|
20
|
+
docsUrl: "https://docs.claude.com/en/docs/claude-code/cli-reference",
|
|
21
|
+
icon: "ClaudeCode",
|
|
22
|
+
accent: "bg-[#d97757] text-white",
|
|
23
|
+
binaries: ["claude"],
|
|
24
|
+
installHint: "Install with curl -fsSL https://claude.ai/install.sh | bash, then run claude auth login.",
|
|
25
|
+
permissionModes: ["read_only", "workspace_write"],
|
|
26
|
+
supportsModel: true,
|
|
27
|
+
modelPlaceholder: "e.g. sonnet or opus; leave empty for the default",
|
|
28
|
+
defaults: {
|
|
29
|
+
permissionMode: "read_only",
|
|
30
|
+
model: null,
|
|
31
|
+
timeoutMs: 3e5
|
|
32
|
+
}
|
|
33
|
+
});
|
|
16
34
|
var codexManifest = defineAgentManifest({
|
|
17
35
|
id: "codex",
|
|
18
36
|
name: "Codex",
|
|
19
37
|
tagline: "OpenAI's coding agent, driven non-interactively through codex exec.",
|
|
20
38
|
docsUrl: "https://developers.openai.com/codex/cli",
|
|
21
|
-
icon: "
|
|
39
|
+
icon: "Codex",
|
|
22
40
|
accent: "bg-neutral-900 text-white",
|
|
23
41
|
binaries: ["codex"],
|
|
24
42
|
installHint: "Install with npm i -g @openai/codex, then run codex login.",
|
|
@@ -36,7 +54,7 @@ var cursorAgentManifest = defineAgentManifest({
|
|
|
36
54
|
name: "Cursor Agent",
|
|
37
55
|
tagline: "Cursor's CLI agent, driven through its print mode.",
|
|
38
56
|
docsUrl: "https://cursor.com/docs/cli",
|
|
39
|
-
icon: "
|
|
57
|
+
icon: "Cursor",
|
|
40
58
|
accent: "bg-blue-600 text-white",
|
|
41
59
|
binaries: ["cursor-agent"],
|
|
42
60
|
installHint: "Install with curl https://cursor.com/install -fsS | bash, then run cursor-agent login.",
|
|
@@ -50,7 +68,11 @@ var cursorAgentManifest = defineAgentManifest({
|
|
|
50
68
|
}
|
|
51
69
|
});
|
|
52
70
|
/** Client-safe registry, listing only agents whose invocation we have verified. */
|
|
53
|
-
var AGENT_MANIFESTS = [
|
|
71
|
+
var AGENT_MANIFESTS = [
|
|
72
|
+
codexManifest,
|
|
73
|
+
claudeManifest,
|
|
74
|
+
cursorAgentManifest
|
|
75
|
+
];
|
|
54
76
|
function agentManifest(id) {
|
|
55
77
|
return AGENT_MANIFESTS.find((manifest) => manifest.id === id);
|
|
56
78
|
}
|
|
@@ -268,6 +290,172 @@ function runProcess(input) {
|
|
|
268
290
|
child.on("close", (code) => finish(code));
|
|
269
291
|
});
|
|
270
292
|
}
|
|
293
|
+
function parse$1(line) {
|
|
294
|
+
const trimmed = line.trim();
|
|
295
|
+
if (!trimmed.startsWith("{")) return null;
|
|
296
|
+
try {
|
|
297
|
+
return JSON.parse(trimmed);
|
|
298
|
+
} catch {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function blocks(event) {
|
|
303
|
+
return event?.type === "assistant" ? event.message?.content ?? [] : [];
|
|
304
|
+
}
|
|
305
|
+
/** `Read` with a file_path becomes `read <path>`. */
|
|
306
|
+
function describeTool$1(block, cwd) {
|
|
307
|
+
const verb = (block.name ?? "a tool").toLowerCase();
|
|
308
|
+
const input = block.input ?? {};
|
|
309
|
+
const subject = input.file_path ?? input.path ?? input.command ?? input.pattern ?? input.url ?? input.query;
|
|
310
|
+
if (typeof subject !== "string") return verb;
|
|
311
|
+
return `${verb} ${cwd && subject.startsWith(`${cwd}/`) ? subject.slice(cwd.length + 1) : subject}`;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* One readable line for the log, or nothing when the event says nothing a
|
|
315
|
+
* person would want to read. Speech is left out: the answer is shown in full
|
|
316
|
+
* elsewhere, and the narration in between is what the tool lines already say.
|
|
317
|
+
*/
|
|
318
|
+
function describeEvent$1(line, cwd) {
|
|
319
|
+
const event = parse$1(line);
|
|
320
|
+
if (!event) return line.trim() === "" ? null : line;
|
|
321
|
+
switch (event.type) {
|
|
322
|
+
case "system":
|
|
323
|
+
if (event.subtype !== "init") return null;
|
|
324
|
+
return event.model ? `Started with ${event.model}.` : "Started.";
|
|
325
|
+
case "assistant": {
|
|
326
|
+
const tools = blocks(event).filter((block) => block.type === "tool_use").map((block) => `Running ${describeTool$1(block, cwd)}`);
|
|
327
|
+
return tools.length > 0 ? tools.join("\n") : null;
|
|
328
|
+
}
|
|
329
|
+
case "result": {
|
|
330
|
+
const seconds = event.duration_ms !== void 0 ? (event.duration_ms / 1e3).toFixed(0) : "?";
|
|
331
|
+
const tokens = event.usage?.output_tokens;
|
|
332
|
+
const spent = tokens === void 0 ? "" : `, ${tokens} tokens out`;
|
|
333
|
+
return event.is_error ? `Failed after ${seconds}s${spent}: ${event.result ?? event.subtype ?? "unknown error"}` : `Answered after ${seconds}s${spent}.`;
|
|
334
|
+
}
|
|
335
|
+
default: return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* The answer, which is the agent's last message and not everything it said.
|
|
340
|
+
*
|
|
341
|
+
* The result event carries exactly that, so it wins when present. A stopped
|
|
342
|
+
* run never gets one; then the text after the last tool use is the block it
|
|
343
|
+
* was in the middle of, and earlier text is it thinking out loud.
|
|
344
|
+
*/
|
|
345
|
+
function answerFrom$1(stdout) {
|
|
346
|
+
const events = stdout.split("\n").map(parse$1);
|
|
347
|
+
const result = events.filter((event) => event?.type === "result").at(-1);
|
|
348
|
+
const failed = result?.is_error === true;
|
|
349
|
+
if (typeof result?.result === "string" && result.result.trim() !== "") return {
|
|
350
|
+
text: result.result.trim(),
|
|
351
|
+
failed
|
|
352
|
+
};
|
|
353
|
+
const said = events.flatMap(blocks);
|
|
354
|
+
const lastTool = said.findLastIndex((block) => block.type === "tool_use");
|
|
355
|
+
return {
|
|
356
|
+
text: said.slice(lastTool + 1).filter((block) => block.type === "text").map((block) => block.text ?? "").join("\n").trim(),
|
|
357
|
+
failed
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
async function binary$2() {
|
|
361
|
+
const found = await resolveBinary(claudeManifest.binaries);
|
|
362
|
+
if (!found) throw new Error("The claude binary was not found on this host.");
|
|
363
|
+
return found;
|
|
364
|
+
}
|
|
365
|
+
function args$2(input) {
|
|
366
|
+
const list = [
|
|
367
|
+
"-p",
|
|
368
|
+
"--output-format",
|
|
369
|
+
"stream-json",
|
|
370
|
+
"--verbose",
|
|
371
|
+
"--no-session-persistence"
|
|
372
|
+
];
|
|
373
|
+
if (input.settings.permissionMode === "read_only") list.push("--permission-mode", "dontAsk", "--tools", "Read,Grep,Glob");
|
|
374
|
+
else list.push("--permission-mode", "acceptEdits", "--allowedTools", "Bash");
|
|
375
|
+
if (input.settings.model) list.push("--model", input.settings.model);
|
|
376
|
+
list.push("--", input.prompt);
|
|
377
|
+
return list;
|
|
378
|
+
}
|
|
379
|
+
var claudeRuntime = defineAgentRuntime({
|
|
380
|
+
async detect() {
|
|
381
|
+
const found = await resolveBinary(claudeManifest.binaries);
|
|
382
|
+
if (!found) return { installed: false };
|
|
383
|
+
return {
|
|
384
|
+
installed: true,
|
|
385
|
+
binaryPath: found,
|
|
386
|
+
version: firstLine((await probe(found, ["--version"])).text)
|
|
387
|
+
};
|
|
388
|
+
},
|
|
389
|
+
async authStatus() {
|
|
390
|
+
const found = await resolveBinary(claudeManifest.binaries);
|
|
391
|
+
if (!found) return {
|
|
392
|
+
signedIn: false,
|
|
393
|
+
detail: "Not installed."
|
|
394
|
+
};
|
|
395
|
+
const result = await probe(found, [
|
|
396
|
+
"auth",
|
|
397
|
+
"status",
|
|
398
|
+
"--json"
|
|
399
|
+
]);
|
|
400
|
+
try {
|
|
401
|
+
const status = JSON.parse(result.text);
|
|
402
|
+
return status.loggedIn ? {
|
|
403
|
+
signedIn: true,
|
|
404
|
+
detail: `Signed in (${status.authMethod ?? "unknown method"}).`
|
|
405
|
+
} : {
|
|
406
|
+
signedIn: false,
|
|
407
|
+
detail: "Run claude auth login."
|
|
408
|
+
};
|
|
409
|
+
} catch {
|
|
410
|
+
return {
|
|
411
|
+
signedIn: result.ok,
|
|
412
|
+
detail: firstLine(result.text) || (result.ok ? "Signed in." : "Run claude auth login.")
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
invocation(input) {
|
|
417
|
+
return {
|
|
418
|
+
bin: claudeManifest.binaries[0],
|
|
419
|
+
args: args$2(input)
|
|
420
|
+
};
|
|
421
|
+
},
|
|
422
|
+
async run(input) {
|
|
423
|
+
const bin = await binary$2();
|
|
424
|
+
const argv = args$2(input);
|
|
425
|
+
const outcome = await runProcess({
|
|
426
|
+
bin,
|
|
427
|
+
args: argv,
|
|
428
|
+
cwd: input.cwd,
|
|
429
|
+
timeoutMs: input.settings.timeoutMs,
|
|
430
|
+
signal: input.signal,
|
|
431
|
+
logPath: input.logFile,
|
|
432
|
+
logLine: (line) => describeEvent$1(line, input.cwd)
|
|
433
|
+
});
|
|
434
|
+
const command = `${bin} ${argv.join(" ")}`;
|
|
435
|
+
const answer = answerFrom$1(outcome.stdout);
|
|
436
|
+
if (outcome.aborted) return {
|
|
437
|
+
ok: false,
|
|
438
|
+
aborted: true,
|
|
439
|
+
output: answer.text,
|
|
440
|
+
durationMs: outcome.durationMs,
|
|
441
|
+
command
|
|
442
|
+
};
|
|
443
|
+
if (outcome.timedOut) return {
|
|
444
|
+
ok: false,
|
|
445
|
+
output: answer.text,
|
|
446
|
+
detail: `Claude Code did not finish within ${Math.round(input.settings.timeoutMs / 1e3)}s.`,
|
|
447
|
+
durationMs: outcome.durationMs,
|
|
448
|
+
command
|
|
449
|
+
};
|
|
450
|
+
return {
|
|
451
|
+
ok: outcome.code === 0 && !answer.failed,
|
|
452
|
+
output: answer.text,
|
|
453
|
+
detail: outcome.code === 0 && !answer.failed ? void 0 : answer.failed ? answer.text || "The agent reported an error." : outcome.stderr || `Exited with code ${outcome.code}.`,
|
|
454
|
+
durationMs: outcome.durationMs,
|
|
455
|
+
command
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
});
|
|
271
459
|
async function binary$1() {
|
|
272
460
|
const found = await resolveBinary(codexManifest.binaries);
|
|
273
461
|
if (!found) throw new Error("The codex binary was not found on this host.");
|
|
@@ -458,6 +646,7 @@ function args(input) {
|
|
|
458
646
|
/** Server-only registry. Never import this from a component. */
|
|
459
647
|
var RUNTIMES = {
|
|
460
648
|
codex: codexRuntime,
|
|
649
|
+
claude: claudeRuntime,
|
|
461
650
|
"cursor-agent": defineAgentRuntime({
|
|
462
651
|
async detect() {
|
|
463
652
|
const found = await resolveBinary(cursorAgentManifest.binaries);
|
|
@@ -654,4 +843,4 @@ async function testAgent(agentId) {
|
|
|
654
843
|
};
|
|
655
844
|
}
|
|
656
845
|
//#endregion
|
|
657
|
-
export {
|
|
846
|
+
export { saveAgentSettings as a, testAgent as c, listAgents as i, agentManifest as n, setDefaultAgent as o, agentRuntime as r, settingsFor as s, AGENT_MANIFESTS as t };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { c as
|
|
4
|
-
import { t as createServerRpc } from "./createServerRpc-
|
|
5
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/agents-
|
|
1
|
+
import { r as createServerFn } from "./ssr.mjs";
|
|
2
|
+
import { l as listRunners, n as availableAgentIds } from "./runners-CK9Cx9fS.mjs";
|
|
3
|
+
import { a as saveAgentSettings, c as testAgent, i as listAgents, o as setDefaultAgent } from "./agents-B_qo1gpL.mjs";
|
|
4
|
+
import { t as createServerRpc } from "./createServerRpc-DDrp2nLT.mjs";
|
|
5
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/agents-Bz10gz_m.js
|
|
6
6
|
async function withRunners(agents) {
|
|
7
7
|
const runners = await listRunners();
|
|
8
8
|
const available = await availableAgentIds();
|
|
@@ -40,7 +40,7 @@ var saveAgent_createServerFn_handler = createServerRpc({
|
|
|
40
40
|
name: "saveAgent",
|
|
41
41
|
filename: "src/server/functions/agents.ts"
|
|
42
42
|
}, (opts) => saveAgent.__executeServer(opts));
|
|
43
|
-
var saveAgent = createServerFn({ method: "POST" }).
|
|
43
|
+
var saveAgent = createServerFn({ method: "POST" }).validator((data) => data).handler(saveAgent_createServerFn_handler, async ({ data }) => {
|
|
44
44
|
await saveAgentSettings(data.agentId, {
|
|
45
45
|
permissionMode: data.permissionMode,
|
|
46
46
|
model: data.model,
|
|
@@ -53,7 +53,7 @@ var chooseDefaultAgent_createServerFn_handler = createServerRpc({
|
|
|
53
53
|
name: "chooseDefaultAgent",
|
|
54
54
|
filename: "src/server/functions/agents.ts"
|
|
55
55
|
}, (opts) => chooseDefaultAgent.__executeServer(opts));
|
|
56
|
-
var chooseDefaultAgent = createServerFn({ method: "POST" }).
|
|
56
|
+
var chooseDefaultAgent = createServerFn({ method: "POST" }).validator((data) => data).handler(chooseDefaultAgent_createServerFn_handler, async ({ data }) => {
|
|
57
57
|
await setDefaultAgent(data.agentId);
|
|
58
58
|
return await withRunners(await listAgents());
|
|
59
59
|
});
|
|
@@ -62,7 +62,7 @@ var runAgentTest_createServerFn_handler = createServerRpc({
|
|
|
62
62
|
name: "runAgentTest",
|
|
63
63
|
filename: "src/server/functions/agents.ts"
|
|
64
64
|
}, (opts) => runAgentTest.__executeServer(opts));
|
|
65
|
-
var runAgentTest = createServerFn({ method: "POST" }).
|
|
65
|
+
var runAgentTest = createServerFn({ method: "POST" }).validator((data) => data).handler(runAgentTest_createServerFn_handler, async ({ data }) => {
|
|
66
66
|
const result = await testAgent(data.agentId);
|
|
67
67
|
return {
|
|
68
68
|
passed: result.passed,
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { i as __toESM } from "../_runtime.mjs";
|
|
2
|
+
import { K as require_jsx_runtime, q as require_react } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
|
+
import { m as useRouter } from "../_libs/@tanstack/react-router+[...].mjs";
|
|
4
|
+
import { t as AGENT_MANIFESTS } from "./agents-B_qo1gpL.mjs";
|
|
5
|
+
import { L as ChevronDown, k as CirclePlay } from "../_libs/lucide-react.mjs";
|
|
6
|
+
import { n as toast } from "../_libs/sonner.mjs";
|
|
7
|
+
import { P as cn, _ as Badge, f as Route$16, g as Input$1, h as saveAgent, m as runAgentTest, p as chooseDefaultAgent, v as Button$1 } from "./router-DdwREiOf.mjs";
|
|
8
|
+
import { n as ProductIcon } from "./connector-icon-DrhVbhs6.mjs";
|
|
9
|
+
import { a as List, o as PageHeader, r as Label } from "./page-DZVxKvdn.mjs";
|
|
10
|
+
import { a as SelectValue, i as SelectTrigger, n as SelectContent, r as SelectItem, t as Select$1 } from "./select-BtndHhHb.mjs";
|
|
11
|
+
import { n as useLiveRefresh } from "./use-live-tasks-BzhTkEOL.mjs";
|
|
12
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/agents-CjbOUp3Z.js
|
|
13
|
+
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
14
|
+
var import_jsx_runtime = require_jsx_runtime();
|
|
15
|
+
var MODE_LABELS = {
|
|
16
|
+
read_only: "Read only",
|
|
17
|
+
workspace_write: "Can write in the workspace"
|
|
18
|
+
};
|
|
19
|
+
function AgentsPage() {
|
|
20
|
+
const { agents } = Route$16.useLoaderData();
|
|
21
|
+
useLiveRefresh();
|
|
22
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
23
|
+
className: "flex flex-col gap-6",
|
|
24
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageHeader, {
|
|
25
|
+
title: "Agents",
|
|
26
|
+
description: "The coding CLIs runners can use. Settings apply on every runner."
|
|
27
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { children: AGENT_MANIFESTS.map((manifest) => {
|
|
28
|
+
const view = agents.find((agent) => agent.agentId === manifest.id);
|
|
29
|
+
return view ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentRow, {
|
|
30
|
+
manifest,
|
|
31
|
+
view
|
|
32
|
+
}, manifest.id) : null;
|
|
33
|
+
}) })]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function presence(view) {
|
|
37
|
+
const signedIn = view.onRunners.filter((runner) => runner.signedIn);
|
|
38
|
+
const online = signedIn.filter((runner) => runner.status === "online");
|
|
39
|
+
if (online.length > 0) return online.length === 1 ? `Signed in on ${online[0].name}` : `Signed in on ${online.length} runners`;
|
|
40
|
+
if (signedIn.length > 0) return "Signed in, but every runner is offline";
|
|
41
|
+
if (view.onRunners.length > 0) return "Installed, not signed in";
|
|
42
|
+
return "Not on any runner";
|
|
43
|
+
}
|
|
44
|
+
function AgentRow({ manifest, view }) {
|
|
45
|
+
const router = useRouter();
|
|
46
|
+
const [open, setOpen] = (0, import_react.useState)(view.isDefault && !view.defaultIsImplicit);
|
|
47
|
+
const [mode, setMode] = (0, import_react.useState)(view.settings.permissionMode);
|
|
48
|
+
const [model, setModel] = (0, import_react.useState)(view.settings.model ?? "");
|
|
49
|
+
const [seconds, setSeconds] = (0, import_react.useState)(String(Math.round(view.settings.timeoutMs / 1e3)));
|
|
50
|
+
const [busy, setBusy] = (0, import_react.useState)(null);
|
|
51
|
+
const [testOutput, setTestOutput] = (0, import_react.useState)(null);
|
|
52
|
+
const online = view.onRunners.some((runner) => runner.signedIn && runner.status === "online");
|
|
53
|
+
const act = async (kind, run) => {
|
|
54
|
+
setBusy(kind);
|
|
55
|
+
try {
|
|
56
|
+
await run();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
toast.error(error instanceof Error ? error.message : String(error));
|
|
59
|
+
} finally {
|
|
60
|
+
setBusy(null);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
64
|
+
className: "flex items-center gap-3 px-4 py-3",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProductIcon, {
|
|
67
|
+
icon: manifest.icon,
|
|
68
|
+
className: cn("size-8", online ? void 0 : "opacity-50 grayscale")
|
|
69
|
+
}),
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
71
|
+
type: "button",
|
|
72
|
+
className: "min-w-0 flex-1 text-left",
|
|
73
|
+
onClick: () => setOpen((value) => !value),
|
|
74
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
75
|
+
className: "flex flex-wrap items-center gap-2",
|
|
76
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
77
|
+
className: "text-sm font-medium",
|
|
78
|
+
children: manifest.name
|
|
79
|
+
}), view.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
80
|
+
variant: "secondary",
|
|
81
|
+
children: "Default"
|
|
82
|
+
}) : null]
|
|
83
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
84
|
+
className: "mt-0.5 text-xs text-muted-foreground",
|
|
85
|
+
children: presence(view)
|
|
86
|
+
})]
|
|
87
|
+
}),
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
89
|
+
className: "flex shrink-0 items-center gap-1",
|
|
90
|
+
children: [!view.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
91
|
+
variant: "ghost",
|
|
92
|
+
size: "sm",
|
|
93
|
+
disabled: busy !== null,
|
|
94
|
+
onClick: () => act("default", async () => {
|
|
95
|
+
await chooseDefaultAgent({ data: { agentId: manifest.id } });
|
|
96
|
+
await router.invalidate();
|
|
97
|
+
toast.success(`${manifest.name} will run the loops`);
|
|
98
|
+
}),
|
|
99
|
+
children: "Make default"
|
|
100
|
+
}) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
101
|
+
variant: "ghost",
|
|
102
|
+
size: "icon-sm",
|
|
103
|
+
"aria-expanded": open,
|
|
104
|
+
"aria-label": "Settings",
|
|
105
|
+
onClick: () => setOpen((value) => !value),
|
|
106
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: cn("size-4 transition-transform", open && "rotate-180") })
|
|
107
|
+
})]
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
}), open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
111
|
+
className: "flex flex-col gap-4 border-t bg-muted/30 px-4 py-4 sm:pl-15",
|
|
112
|
+
children: [
|
|
113
|
+
!online ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
114
|
+
className: "text-xs text-muted-foreground",
|
|
115
|
+
children: manifest.installHint
|
|
116
|
+
}) : null,
|
|
117
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
118
|
+
className: "grid gap-4 sm:grid-cols-3",
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
121
|
+
className: "flex flex-col gap-2",
|
|
122
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, {
|
|
123
|
+
htmlFor: `${manifest.id}-mode`,
|
|
124
|
+
children: "Permission"
|
|
125
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
126
|
+
value: mode,
|
|
127
|
+
onValueChange: (value) => setMode(value),
|
|
128
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, {
|
|
129
|
+
id: `${manifest.id}-mode`,
|
|
130
|
+
className: "w-full",
|
|
131
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, { children: (value) => MODE_LABELS[value] ?? value })
|
|
132
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: manifest.permissionModes.map((value) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
133
|
+
value,
|
|
134
|
+
children: MODE_LABELS[value]
|
|
135
|
+
}, value)) })]
|
|
136
|
+
})]
|
|
137
|
+
}),
|
|
138
|
+
manifest.supportsModel ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
139
|
+
className: "flex flex-col gap-2",
|
|
140
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, {
|
|
141
|
+
htmlFor: `${manifest.id}-model`,
|
|
142
|
+
children: "Model"
|
|
143
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
|
|
144
|
+
id: `${manifest.id}-model`,
|
|
145
|
+
value: model,
|
|
146
|
+
placeholder: manifest.modelPlaceholder,
|
|
147
|
+
onChange: (event) => setModel(event.target.value)
|
|
148
|
+
})]
|
|
149
|
+
}) : null,
|
|
150
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
151
|
+
className: "flex flex-col gap-2",
|
|
152
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, {
|
|
153
|
+
htmlFor: `${manifest.id}-timeout`,
|
|
154
|
+
children: "Timeout (seconds)"
|
|
155
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
|
|
156
|
+
id: `${manifest.id}-timeout`,
|
|
157
|
+
value: seconds,
|
|
158
|
+
inputMode: "numeric",
|
|
159
|
+
onChange: (event) => setSeconds(event.target.value.replace(/\D/g, ""))
|
|
160
|
+
})]
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
165
|
+
className: "overflow-x-auto rounded-md bg-muted p-2.5 text-xs",
|
|
166
|
+
children: view.commandPreview
|
|
167
|
+
}),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
169
|
+
className: "flex flex-wrap items-center gap-2",
|
|
170
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
171
|
+
size: "sm",
|
|
172
|
+
disabled: busy !== null,
|
|
173
|
+
onClick: () => act("save", async () => {
|
|
174
|
+
await saveAgent({ data: {
|
|
175
|
+
agentId: manifest.id,
|
|
176
|
+
permissionMode: mode,
|
|
177
|
+
model: model.trim() ? model.trim() : null,
|
|
178
|
+
timeoutMs: Number(seconds) * 1e3
|
|
179
|
+
} });
|
|
180
|
+
await router.invalidate();
|
|
181
|
+
toast.success(`Saved ${manifest.name} settings`);
|
|
182
|
+
}),
|
|
183
|
+
children: busy === "save" ? "Saving..." : "Save"
|
|
184
|
+
}), view.installed ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
185
|
+
variant: "outline",
|
|
186
|
+
size: "sm",
|
|
187
|
+
disabled: busy !== null,
|
|
188
|
+
onClick: () => act("test", async () => {
|
|
189
|
+
setTestOutput(null);
|
|
190
|
+
const result = await runAgentTest({ data: { agentId: manifest.id } });
|
|
191
|
+
setTestOutput(result.passed ? `Answered correctly in ${(result.durationMs / 1e3).toFixed(1)}s.` : `${result.detail ?? "The agent did not answer as expected."}\n${result.output}`.trim());
|
|
192
|
+
if (result.passed) toast.success(`${manifest.name} is working`);
|
|
193
|
+
else toast.error(`${manifest.name} did not pass`);
|
|
194
|
+
}),
|
|
195
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CirclePlay, {}), busy === "test" ? "Running..." : "Test"]
|
|
196
|
+
}) : null]
|
|
197
|
+
}),
|
|
198
|
+
testOutput ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
199
|
+
className: "whitespace-pre-wrap text-xs text-muted-foreground",
|
|
200
|
+
children: testOutput
|
|
201
|
+
}) : null
|
|
202
|
+
]
|
|
203
|
+
}) : null] });
|
|
204
|
+
}
|
|
205
|
+
//#endregion
|
|
206
|
+
export { AgentsPage as component };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../_runtime.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { K as require_jsx_runtime, q as require_react } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
3
|
import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { P as cn } from "./router-DdwREiOf.mjs";
|
|
5
5
|
require_react();
|
|
6
6
|
var import_jsx_runtime = require_jsx_runtime();
|
|
7
7
|
var alertVariants = cva("group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import "../_runtime.mjs";
|
|
2
|
+
import { K as require_jsx_runtime, q as require_react } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
|
+
import { P as cn } from "./router-DdwREiOf.mjs";
|
|
4
|
+
require_react();
|
|
5
|
+
var import_jsx_runtime = require_jsx_runtime();
|
|
6
|
+
function Card({ className, size = "default", ...props }) {
|
|
7
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8
|
+
"data-slot": "card",
|
|
9
|
+
"data-size": size,
|
|
10
|
+
className: cn("group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", className),
|
|
11
|
+
...props
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function CardHeader({ className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
16
|
+
"data-slot": "card-header",
|
|
17
|
+
className: cn("group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)", className),
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function CardTitle({ className, ...props }) {
|
|
22
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
23
|
+
"data-slot": "card-title",
|
|
24
|
+
className: cn("font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm", className),
|
|
25
|
+
...props
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function CardContent({ className, ...props }) {
|
|
29
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
30
|
+
"data-slot": "card-content",
|
|
31
|
+
className: cn("px-(--card-spacing)", className),
|
|
32
|
+
...props
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { CardTitle as i, CardContent as n, CardHeader as r, Card as t };
|
|
@@ -4,7 +4,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { createClient } from "@libsql/client";
|
|
7
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/client-
|
|
7
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/client-Dk3SD8Il.js
|
|
8
8
|
var __defProp = Object.defineProperty;
|
|
9
9
|
var __exportAll = (all, no_symbols) => {
|
|
10
10
|
let target = {};
|
|
@@ -294,6 +294,10 @@ var runners = sqliteTable("runners", {
|
|
|
294
294
|
status: text("status").$type().notNull().default("offline"),
|
|
295
295
|
inventory: text("inventory", { mode: "json" }).$type().notNull().default([]),
|
|
296
296
|
lastSeenAt: integer("last_seen_at", { mode: "timestamp_ms" }),
|
|
297
|
+
/** The runner's loopable-cli version. Null for runners before 0.3. */
|
|
298
|
+
version: text("version"),
|
|
299
|
+
/** What jobs it understands; see RUNNER_PROTOCOL. Null means the first. */
|
|
300
|
+
protocol: integer("protocol"),
|
|
297
301
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(sql`(unixepoch() * 1000)`)
|
|
298
302
|
});
|
|
299
303
|
function databaseUrl() {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { K as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
|
|
2
|
+
import { P as cn } from "./router-DdwREiOf.mjs";
|
|
3
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/connection-status-BogAL-Fj.js
|
|
4
|
+
var import_jsx_runtime = require_jsx_runtime();
|
|
5
|
+
var LABELS = {
|
|
6
|
+
connected: {
|
|
7
|
+
text: "Connected",
|
|
8
|
+
dot: "bg-emerald-500"
|
|
9
|
+
},
|
|
10
|
+
needs_reauth: {
|
|
11
|
+
text: "Needs reconnecting",
|
|
12
|
+
dot: "bg-destructive"
|
|
13
|
+
},
|
|
14
|
+
error: {
|
|
15
|
+
text: "Error",
|
|
16
|
+
dot: "bg-destructive"
|
|
17
|
+
},
|
|
18
|
+
paused: {
|
|
19
|
+
text: "Paused",
|
|
20
|
+
dot: "bg-muted-foreground"
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
/** A dot and a word: quiet when all is well, red when it is not. */
|
|
24
|
+
function ConnectionStatusBadge({ status }) {
|
|
25
|
+
const label = LABELS[status] ?? LABELS.error;
|
|
26
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
27
|
+
className: cn("inline-flex items-center gap-1.5 text-xs", status === "connected" || status === "paused" ? "text-muted-foreground" : "text-destructive"),
|
|
28
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cn("size-1.5 rounded-full", label.dot) }), label.text]
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ConnectionStatusBadge as t };
|