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
package/dist/cli.mjs
CHANGED
|
@@ -14,68 +14,17 @@ var __export = (target, all) => {
|
|
|
14
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
// src/lib/
|
|
18
|
-
var
|
|
19
|
-
__export(
|
|
20
|
-
appOrigin: () => appOrigin,
|
|
21
|
-
callbackUrl: () => callbackUrl,
|
|
22
|
-
isLoopbackHost: () => isLoopbackHost,
|
|
17
|
+
// src/lib/lan.ts
|
|
18
|
+
var lan_exports = {};
|
|
19
|
+
__export(lan_exports, {
|
|
23
20
|
lanIPv4: () => lanIPv4,
|
|
24
|
-
loopableOrigin: () => loopableOrigin
|
|
25
|
-
registrableCallbackUrl: () => registrableCallbackUrl
|
|
21
|
+
loopableOrigin: () => loopableOrigin
|
|
26
22
|
});
|
|
27
23
|
import { networkInterfaces } from "node:os";
|
|
28
24
|
function configuredOrigin() {
|
|
29
25
|
const base = process.env.LOOPABLE_BASE_URL?.replace(/\/$/, "");
|
|
30
26
|
return base || null;
|
|
31
27
|
}
|
|
32
|
-
function isLoopbackHost(hostname) {
|
|
33
|
-
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1";
|
|
34
|
-
}
|
|
35
|
-
function isPrivateHostname(hostname) {
|
|
36
|
-
if (isLoopbackHost(hostname)) return true;
|
|
37
|
-
const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
38
|
-
if (v4) {
|
|
39
|
-
const a = Number(v4[1]);
|
|
40
|
-
const b = Number(v4[2]);
|
|
41
|
-
if (a === 10) return true;
|
|
42
|
-
if (a === 127) return true;
|
|
43
|
-
if (a === 192 && b === 168) return true;
|
|
44
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
45
|
-
if (a === 169 && b === 254) return true;
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
const host = hostname.toLowerCase();
|
|
49
|
-
if (host.includes(":")) {
|
|
50
|
-
if (host.startsWith("fe80:") || host.startsWith("fc") || host.startsWith("fd")) return true;
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
function publicConfiguredOrigin() {
|
|
55
|
-
const base = configuredOrigin();
|
|
56
|
-
if (!base) return null;
|
|
57
|
-
try {
|
|
58
|
-
const url = new URL(base);
|
|
59
|
-
if (isPrivateHostname(url.hostname)) return null;
|
|
60
|
-
return base;
|
|
61
|
-
} catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function appOrigin(requestUrl) {
|
|
66
|
-
const hosted = publicConfiguredOrigin();
|
|
67
|
-
if (hosted) return hosted;
|
|
68
|
-
const url = new URL(requestUrl);
|
|
69
|
-
return `http://127.0.0.1${url.port ? `:${url.port}` : ""}`;
|
|
70
|
-
}
|
|
71
|
-
function callbackUrl(requestUrl, connectorId) {
|
|
72
|
-
return `${appOrigin(requestUrl)}/api/connectors/${connectorId}/callback`;
|
|
73
|
-
}
|
|
74
|
-
function registrableCallbackUrl(connectorId) {
|
|
75
|
-
const hosted = publicConfiguredOrigin();
|
|
76
|
-
if (hosted) return `${hosted}/api/connectors/${connectorId}/callback`;
|
|
77
|
-
return `http://127.0.0.1/api/connectors/${connectorId}/callback`;
|
|
78
|
-
}
|
|
79
28
|
function lanIPv4(nics = networkInterfaces()) {
|
|
80
29
|
const found = [];
|
|
81
30
|
for (const addrs of Object.values(nics)) {
|
|
@@ -96,8 +45,8 @@ function loopableOrigin(nics = networkInterfaces()) {
|
|
|
96
45
|
const port = process.env.PORT ?? process.env.NITRO_PORT ?? "4321";
|
|
97
46
|
return `http://${lanIPv4(nics) ?? "127.0.0.1"}:${port}`;
|
|
98
47
|
}
|
|
99
|
-
var
|
|
100
|
-
"src/lib/
|
|
48
|
+
var init_lan = __esm({
|
|
49
|
+
"src/lib/lan.ts"() {
|
|
101
50
|
"use strict";
|
|
102
51
|
}
|
|
103
52
|
});
|
|
@@ -2240,6 +2189,130 @@ var init_drizzle_orm = __esm({
|
|
|
2240
2189
|
}
|
|
2241
2190
|
});
|
|
2242
2191
|
|
|
2192
|
+
// package.json
|
|
2193
|
+
var package_default;
|
|
2194
|
+
var init_package = __esm({
|
|
2195
|
+
"package.json"() {
|
|
2196
|
+
package_default = {
|
|
2197
|
+
name: "loopable-cli",
|
|
2198
|
+
version: "0.2.1",
|
|
2199
|
+
description: "CLI to run Loopable: App, Dispatcher, and Runner.",
|
|
2200
|
+
license: "MIT",
|
|
2201
|
+
type: "module",
|
|
2202
|
+
bin: {
|
|
2203
|
+
loopable: "./dist/cli.mjs"
|
|
2204
|
+
},
|
|
2205
|
+
files: [
|
|
2206
|
+
".output",
|
|
2207
|
+
"dist",
|
|
2208
|
+
"drizzle"
|
|
2209
|
+
],
|
|
2210
|
+
engines: {
|
|
2211
|
+
node: ">=22"
|
|
2212
|
+
},
|
|
2213
|
+
packageManager: "pnpm@11.22.0",
|
|
2214
|
+
repository: {
|
|
2215
|
+
type: "git",
|
|
2216
|
+
url: "git+https://github.com/imsobear/loopable.git"
|
|
2217
|
+
},
|
|
2218
|
+
bugs: {
|
|
2219
|
+
url: "https://github.com/imsobear/loopable/issues"
|
|
2220
|
+
},
|
|
2221
|
+
homepage: "https://github.com/imsobear/loopable#readme",
|
|
2222
|
+
publishConfig: {
|
|
2223
|
+
access: "public"
|
|
2224
|
+
},
|
|
2225
|
+
imports: {
|
|
2226
|
+
"#/*": "./src/*"
|
|
2227
|
+
},
|
|
2228
|
+
scripts: {
|
|
2229
|
+
dev: "node --experimental-strip-types scripts/dev.ts",
|
|
2230
|
+
start: "node dist/cli.mjs start",
|
|
2231
|
+
dispatcher: "LOOPABLE_DEV=1 node --experimental-strip-types src/cli.ts dispatcher",
|
|
2232
|
+
runner: "LOOPABLE_DEV=1 node --experimental-strip-types src/cli.ts runner",
|
|
2233
|
+
"generate-routes": "tsr generate",
|
|
2234
|
+
build: "vite build && node scripts/build-cli.mjs",
|
|
2235
|
+
preview: "vite preview",
|
|
2236
|
+
test: "vitest run",
|
|
2237
|
+
"test:watch": "vitest",
|
|
2238
|
+
"db:generate": "drizzle-kit generate",
|
|
2239
|
+
"db:studio": "LOOPABLE_DEV=1 drizzle-kit studio",
|
|
2240
|
+
typecheck: "tsc --noEmit",
|
|
2241
|
+
release: "node scripts/release.mjs",
|
|
2242
|
+
deploy: "LOOPABLE_CF=1 vite build && wrangler deploy",
|
|
2243
|
+
"site:dev": "pnpm --filter loopable-site dev",
|
|
2244
|
+
"site:build": "pnpm --filter loopable-site build",
|
|
2245
|
+
"site:deploy": "pnpm --filter loopable-site deploy",
|
|
2246
|
+
prepublishOnly: "pnpm typecheck && pnpm test && pnpm build"
|
|
2247
|
+
},
|
|
2248
|
+
dependencies: {
|
|
2249
|
+
"@libsql/client": "^0.18.0"
|
|
2250
|
+
},
|
|
2251
|
+
devDependencies: {
|
|
2252
|
+
"@base-ui/react": "^1.7.0",
|
|
2253
|
+
"@cloudflare/containers": "^0.3.7",
|
|
2254
|
+
"@cloudflare/vite-plugin": "^1.54.10",
|
|
2255
|
+
"@fontsource-variable/geist": "^5.3.0",
|
|
2256
|
+
"@tailwindcss/vite": "4.1.18",
|
|
2257
|
+
"@tanstack/devtools-vite": "0.8.5",
|
|
2258
|
+
"@tanstack/react-devtools": "0.10.12",
|
|
2259
|
+
"@tanstack/react-router": "1.170.32",
|
|
2260
|
+
"@tanstack/react-router-devtools": "1.167.1",
|
|
2261
|
+
"@tanstack/react-start": "1.168.49",
|
|
2262
|
+
"@tanstack/router-cli": "1.167.33",
|
|
2263
|
+
"@types/node": "^22.10.2",
|
|
2264
|
+
"@types/qrcode": "^1.5.6",
|
|
2265
|
+
"@types/react": "^19.2.0",
|
|
2266
|
+
"@types/react-dom": "^19.2.0",
|
|
2267
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
2268
|
+
"class-variance-authority": "^0.7.1",
|
|
2269
|
+
clsx: "^2.1.1",
|
|
2270
|
+
"drizzle-kit": "^0.31.10",
|
|
2271
|
+
"drizzle-orm": "^0.45.2",
|
|
2272
|
+
esbuild: "^0.28.2",
|
|
2273
|
+
"lucide-react": "^1.39.0",
|
|
2274
|
+
"next-themes": "^0.4.6",
|
|
2275
|
+
nitro: "3.0.260610-beta",
|
|
2276
|
+
qrcode: "^1.5.4",
|
|
2277
|
+
react: "19.2.0",
|
|
2278
|
+
"react-dom": "19.2.0",
|
|
2279
|
+
shadcn: "^4.19.1",
|
|
2280
|
+
sonner: "^2.0.8",
|
|
2281
|
+
"tailwind-merge": "^3.6.0",
|
|
2282
|
+
tailwindcss: "4.1.18",
|
|
2283
|
+
"tw-animate-css": "^1.4.0",
|
|
2284
|
+
typescript: "^6.0.2",
|
|
2285
|
+
vite: "^8.0.0",
|
|
2286
|
+
vitest: "^4.1.11",
|
|
2287
|
+
wrangler: "^4.132.0"
|
|
2288
|
+
}
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
});
|
|
2292
|
+
|
|
2293
|
+
// src/lib/version.ts
|
|
2294
|
+
function olderThan(a, b) {
|
|
2295
|
+
if (!a) return true;
|
|
2296
|
+
const pa = a.split(".").map((part) => Number.parseInt(part, 10));
|
|
2297
|
+
const pb = b.split(".").map((part) => Number.parseInt(part, 10));
|
|
2298
|
+
for (let i = 0; i < 3; i++) {
|
|
2299
|
+
const x = pa[i] ?? 0;
|
|
2300
|
+
const y = pb[i] ?? 0;
|
|
2301
|
+
if (Number.isNaN(x)) return true;
|
|
2302
|
+
if (x !== y) return x < y;
|
|
2303
|
+
}
|
|
2304
|
+
return false;
|
|
2305
|
+
}
|
|
2306
|
+
var VERSION, RUNNER_PROTOCOL, LEGACY_RUNNER_PROTOCOL;
|
|
2307
|
+
var init_version2 = __esm({
|
|
2308
|
+
"src/lib/version.ts"() {
|
|
2309
|
+
init_package();
|
|
2310
|
+
VERSION = package_default.version;
|
|
2311
|
+
RUNNER_PROTOCOL = 2;
|
|
2312
|
+
LEGACY_RUNNER_PROTOCOL = 1;
|
|
2313
|
+
}
|
|
2314
|
+
});
|
|
2315
|
+
|
|
2243
2316
|
// node_modules/.pnpm/drizzle-orm@0.45.2_@libsql+client@0.18.0_@types+better-sqlite3@9.6.0_better-sqlite3@13.0.3/node_modules/drizzle-orm/selection-proxy.js
|
|
2244
2317
|
var SelectionProxyHandler;
|
|
2245
2318
|
var init_selection_proxy = __esm({
|
|
@@ -6756,6 +6829,10 @@ var init_schema = __esm({
|
|
|
6756
6829
|
status: text("status").$type().notNull().default("offline"),
|
|
6757
6830
|
inventory: text("inventory", { mode: "json" }).$type().notNull().default([]),
|
|
6758
6831
|
lastSeenAt: integer("last_seen_at", { mode: "timestamp_ms" }),
|
|
6832
|
+
/** The runner's loopable-cli version. Null for runners before 0.3. */
|
|
6833
|
+
version: text("version"),
|
|
6834
|
+
/** What jobs it understands; see RUNNER_PROTOCOL. Null means the first. */
|
|
6835
|
+
protocol: integer("protocol"),
|
|
6759
6836
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(sql`(unixepoch() * 1000)`)
|
|
6760
6837
|
});
|
|
6761
6838
|
}
|
|
@@ -6963,11 +7040,21 @@ __export(runners_exports, {
|
|
|
6963
7040
|
listRunners: () => listRunners,
|
|
6964
7041
|
onlineRunnerCount: () => onlineRunnerCount,
|
|
6965
7042
|
pickRunner: () => pickRunner,
|
|
7043
|
+
protocolOf: () => protocolOf,
|
|
6966
7044
|
rotateJoinToken: () => rotateJoinToken,
|
|
6967
7045
|
runnerIdForToken: () => runnerIdForToken
|
|
6968
7046
|
});
|
|
6969
7047
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
6970
7048
|
import { hostname as osHostname } from "node:os";
|
|
7049
|
+
function protocolOf(row) {
|
|
7050
|
+
return row.protocol ?? LEGACY_RUNNER_PROTOCOL;
|
|
7051
|
+
}
|
|
7052
|
+
function buildFields(build) {
|
|
7053
|
+
return {
|
|
7054
|
+
version: typeof build.version === "string" && build.version ? build.version : null,
|
|
7055
|
+
protocol: typeof build.protocol === "number" ? build.protocol : null
|
|
7056
|
+
};
|
|
7057
|
+
}
|
|
6971
7058
|
function isRunnerOnline(row, now = Date.now()) {
|
|
6972
7059
|
if (row.status !== "online") return false;
|
|
6973
7060
|
if (!row.lastSeenAt) return false;
|
|
@@ -6981,7 +7068,10 @@ function toView(row, now = Date.now()) {
|
|
|
6981
7068
|
hostname: row.hostname,
|
|
6982
7069
|
status: online ? "online" : "offline",
|
|
6983
7070
|
inventory: row.inventory,
|
|
6984
|
-
lastSeenAt: row.lastSeenAt?.toISOString() ?? null
|
|
7071
|
+
lastSeenAt: row.lastSeenAt?.toISOString() ?? null,
|
|
7072
|
+
version: row.version,
|
|
7073
|
+
protocol: protocolOf(row),
|
|
7074
|
+
outdated: protocolOf(row) < RUNNER_PROTOCOL || olderThan(row.version, VERSION)
|
|
6985
7075
|
};
|
|
6986
7076
|
}
|
|
6987
7077
|
async function listRunners() {
|
|
@@ -7011,11 +7101,13 @@ async function busyRunnerIds() {
|
|
|
7011
7101
|
)
|
|
7012
7102
|
);
|
|
7013
7103
|
}
|
|
7014
|
-
async function availableAgentIds(requiresHost = false) {
|
|
7104
|
+
async function availableAgentIds(requiresHost = false, minProtocol = 0) {
|
|
7015
7105
|
const local = osHostname();
|
|
7016
7106
|
return [
|
|
7017
7107
|
...new Set(
|
|
7018
|
-
(await listRunners()).filter(
|
|
7108
|
+
(await listRunners()).filter(
|
|
7109
|
+
(row) => row.status === "online" && (!requiresHost || row.hostname === local) && row.protocol >= minProtocol
|
|
7110
|
+
).flatMap(
|
|
7019
7111
|
(row) => row.inventory.filter((entry) => entry.installed && entry.signedIn).map((entry) => entry.agentId)
|
|
7020
7112
|
)
|
|
7021
7113
|
)
|
|
@@ -7024,9 +7116,11 @@ async function availableAgentIds(requiresHost = false) {
|
|
|
7024
7116
|
async function pickRunner(input) {
|
|
7025
7117
|
const now = Date.now();
|
|
7026
7118
|
const local = osHostname();
|
|
7027
|
-
|
|
7119
|
+
const minProtocol = input.minProtocol ?? 0;
|
|
7120
|
+
const capable = (await db().select().from(runners).all()).filter(
|
|
7028
7121
|
(row) => isRunnerOnline(row, now) && runnerCanRun(row, input.agentId)
|
|
7029
7122
|
);
|
|
7123
|
+
let candidates = capable.filter((row) => protocolOf(row) >= minProtocol);
|
|
7030
7124
|
if (input.requiresHost) {
|
|
7031
7125
|
candidates = candidates.filter((row) => row.hostname === local);
|
|
7032
7126
|
}
|
|
@@ -7037,6 +7131,11 @@ async function pickRunner(input) {
|
|
|
7037
7131
|
if (input.requiresHost) {
|
|
7038
7132
|
throw new Error("This job needs a runner on the same host as Loopable.");
|
|
7039
7133
|
}
|
|
7134
|
+
if (capable.length > 0) {
|
|
7135
|
+
throw new Error(
|
|
7136
|
+
"Every runner with this agent is too old for this job. Upgrade them with npm install -g loopable-cli."
|
|
7137
|
+
);
|
|
7138
|
+
}
|
|
7040
7139
|
throw new Error("No runner is online that can run this agent.");
|
|
7041
7140
|
}
|
|
7042
7141
|
async function getJoinToken() {
|
|
@@ -7051,10 +7150,10 @@ async function rotateJoinToken() {
|
|
|
7051
7150
|
await secretStore().set(joinTokenKey(), token);
|
|
7052
7151
|
return token;
|
|
7053
7152
|
}
|
|
7054
|
-
async function heartbeatRunner(runnerId, inventory) {
|
|
7153
|
+
async function heartbeatRunner(runnerId, inventory, build = {}) {
|
|
7055
7154
|
const row = await getRunner(runnerId);
|
|
7056
7155
|
if (!row) throw new Error("Unknown runner.");
|
|
7057
|
-
await db().update(runners).set({ status: "online", inventory, lastSeenAt: /* @__PURE__ */ new Date() }).where(eq(runners.id, runnerId)).run();
|
|
7156
|
+
await db().update(runners).set({ status: "online", inventory, lastSeenAt: /* @__PURE__ */ new Date(), ...buildFields(build) }).where(eq(runners.id, runnerId)).run();
|
|
7058
7157
|
return toView(await getRunner(runnerId));
|
|
7059
7158
|
}
|
|
7060
7159
|
async function joinRunner(input) {
|
|
@@ -7073,7 +7172,8 @@ async function joinRunner(input) {
|
|
|
7073
7172
|
status: "online",
|
|
7074
7173
|
inventory: input.inventory,
|
|
7075
7174
|
lastSeenAt: now,
|
|
7076
|
-
hostname: input.hostname
|
|
7175
|
+
hostname: input.hostname,
|
|
7176
|
+
...buildFields(input)
|
|
7077
7177
|
}).where(eq(runners.id, id)).run();
|
|
7078
7178
|
} else {
|
|
7079
7179
|
await db().insert(runners).values({
|
|
@@ -7082,7 +7182,8 @@ async function joinRunner(input) {
|
|
|
7082
7182
|
hostname: input.hostname,
|
|
7083
7183
|
status: "online",
|
|
7084
7184
|
inventory: input.inventory,
|
|
7085
|
-
lastSeenAt: now
|
|
7185
|
+
lastSeenAt: now,
|
|
7186
|
+
...buildFields(input)
|
|
7086
7187
|
}).run();
|
|
7087
7188
|
}
|
|
7088
7189
|
const token = randomBytes(24).toString("base64url");
|
|
@@ -7113,6 +7214,7 @@ var init_runners = __esm({
|
|
|
7113
7214
|
"src/server/runners.ts"() {
|
|
7114
7215
|
"use strict";
|
|
7115
7216
|
init_drizzle_orm();
|
|
7217
|
+
init_version2();
|
|
7116
7218
|
init_client();
|
|
7117
7219
|
init_schema();
|
|
7118
7220
|
init_secrets();
|
|
@@ -7122,7 +7224,7 @@ var init_runners = __esm({
|
|
|
7122
7224
|
|
|
7123
7225
|
// src/cli.ts
|
|
7124
7226
|
import { spawn } from "node:child_process";
|
|
7125
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
7227
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
7126
7228
|
import { dirname, join as join3 } from "node:path";
|
|
7127
7229
|
import { createInterface } from "node:readline";
|
|
7128
7230
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -7141,8 +7243,18 @@ function usage() {
|
|
|
7141
7243
|
|
|
7142
7244
|
loopable dispatcher
|
|
7143
7245
|
Dispatcher only.
|
|
7246
|
+
|
|
7247
|
+
loopable --version
|
|
7144
7248
|
`;
|
|
7145
7249
|
}
|
|
7250
|
+
function cliVersion() {
|
|
7251
|
+
try {
|
|
7252
|
+
const pkg = JSON.parse(readFileSync2(join3(root, "package.json"), "utf8"));
|
|
7253
|
+
return pkg.version;
|
|
7254
|
+
} catch {
|
|
7255
|
+
return "unknown";
|
|
7256
|
+
}
|
|
7257
|
+
}
|
|
7146
7258
|
function fail(message) {
|
|
7147
7259
|
process.stderr.write(`${message}
|
|
7148
7260
|
`);
|
|
@@ -7162,6 +7274,7 @@ function parse(argv) {
|
|
|
7162
7274
|
return value;
|
|
7163
7275
|
};
|
|
7164
7276
|
if (arg === "-h" || arg === "--help") return { command: "help", flags };
|
|
7277
|
+
if (arg === "-v" || arg === "--version") return { command: "version", flags };
|
|
7165
7278
|
if (arg === "--host") flags.host = next();
|
|
7166
7279
|
else if (arg === "--port") flags.port = next();
|
|
7167
7280
|
else if (arg === "--url") flags.url = next();
|
|
@@ -7248,7 +7361,7 @@ async function waitForApp(port) {
|
|
|
7248
7361
|
}
|
|
7249
7362
|
async function printRunnerHint(flags) {
|
|
7250
7363
|
await waitForApp(flags.port);
|
|
7251
|
-
const { lanIPv4: lanIPv42 } = await Promise.resolve().then(() => (
|
|
7364
|
+
const { lanIPv4: lanIPv42 } = await Promise.resolve().then(() => (init_lan(), lan_exports));
|
|
7252
7365
|
const { getJoinToken: getJoinToken2 } = await Promise.resolve().then(() => (init_runners(), runners_exports));
|
|
7253
7366
|
const ip = lanIPv42() ?? "127.0.0.1";
|
|
7254
7367
|
const url = `http://${ip}:${flags.port}`;
|
|
@@ -7279,6 +7392,11 @@ async function main() {
|
|
|
7279
7392
|
process.stdout.write(usage());
|
|
7280
7393
|
return;
|
|
7281
7394
|
}
|
|
7395
|
+
if (command === "version") {
|
|
7396
|
+
process.stdout.write(`${cliVersion()}
|
|
7397
|
+
`);
|
|
7398
|
+
return;
|
|
7399
|
+
}
|
|
7282
7400
|
if (command === "runner") {
|
|
7283
7401
|
if (flags.url) process.env.LOOPABLE_URL = flags.url;
|
|
7284
7402
|
if (flags.token) process.env.LOOPABLE_RUNNER_TOKEN = flags.token;
|