@lumi.ai/runner 0.3.1 → 0.3.2
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/dist/cli.js +46 -36
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -532,7 +532,7 @@ function mcpUrl(config2) {
|
|
|
532
532
|
}
|
|
533
533
|
|
|
534
534
|
// src/version.ts
|
|
535
|
-
var RUNNER_VERSION = true ? "0.3.
|
|
535
|
+
var RUNNER_VERSION = true ? "0.3.2" : "0.0.0-dev";
|
|
536
536
|
|
|
537
537
|
// src/auth.ts
|
|
538
538
|
import { signInWithCustomToken } from "firebase/auth";
|
|
@@ -2639,10 +2639,10 @@ function serviceStatus() {
|
|
|
2639
2639
|
};
|
|
2640
2640
|
}
|
|
2641
2641
|
if (process.platform === "win32") {
|
|
2642
|
-
const
|
|
2643
|
-
if (!
|
|
2642
|
+
const query5 = run("schtasks", ["/Query", "/TN", WINDOWS_TASK]);
|
|
2643
|
+
if (!query5.ok) return { state: "not-installed", detail: "No scheduled task installed." };
|
|
2644
2644
|
return {
|
|
2645
|
-
state: /\bRunning\b/i.test(
|
|
2645
|
+
state: /\bRunning\b/i.test(query5.out) ? "running" : "installed",
|
|
2646
2646
|
detail: "Scheduled task installed (runs at logon).",
|
|
2647
2647
|
unitPath: WINDOWS_TASK
|
|
2648
2648
|
};
|
|
@@ -2751,21 +2751,6 @@ async function openShipSession(shipId) {
|
|
|
2751
2751
|
const user = await signInToShip(fb, config2, shipId);
|
|
2752
2752
|
return { shipId, config: config2, fb, user };
|
|
2753
2753
|
}
|
|
2754
|
-
async function openSession() {
|
|
2755
|
-
const config2 = requireConfig();
|
|
2756
|
-
if (config2.ships.length === 0) {
|
|
2757
|
-
throw new AuthError("No Ships assigned. Run: lumi-runner ship add <shipId>");
|
|
2758
|
-
}
|
|
2759
|
-
let last;
|
|
2760
|
-
for (const shipId of config2.ships) {
|
|
2761
|
-
try {
|
|
2762
|
-
return await openShipSession(shipId);
|
|
2763
|
-
} catch (e) {
|
|
2764
|
-
last = e;
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
throw last instanceof Error ? last : new AuthError("Could not sign in to any Ship.");
|
|
2768
|
-
}
|
|
2769
2754
|
|
|
2770
2755
|
// src/cli/commands/doctor.ts
|
|
2771
2756
|
var ok = (id, label, detail) => ({ id, label, level: "ok", detail });
|
|
@@ -3280,17 +3265,19 @@ async function runUninstall(options) {
|
|
|
3280
3265
|
}
|
|
3281
3266
|
|
|
3282
3267
|
// src/cli/commands/ship.ts
|
|
3283
|
-
import {
|
|
3268
|
+
import { doc as doc9, getDoc as getDoc7 } from "firebase/firestore";
|
|
3284
3269
|
async function listMyShips() {
|
|
3285
|
-
const
|
|
3286
|
-
const
|
|
3287
|
-
query4(collectionGroup(fb.db, COLLECTIONS.members), where4("uid", "==", user.uid))
|
|
3288
|
-
);
|
|
3289
|
-
const shipIds = memberships.docs.map((d) => d.ref.parent.parent?.id).filter((id) => !!id);
|
|
3270
|
+
const config2 = requireConfig();
|
|
3271
|
+
const ids = Object.keys(config2.shipKeys ?? {});
|
|
3290
3272
|
const ships = await Promise.all(
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3273
|
+
ids.map(async (id) => {
|
|
3274
|
+
try {
|
|
3275
|
+
const { fb } = await openShipSession(id);
|
|
3276
|
+
const snap = await getDoc7(doc9(fb.db, COLLECTIONS.ships, id));
|
|
3277
|
+
return { id, ...snap.data() };
|
|
3278
|
+
} catch {
|
|
3279
|
+
return null;
|
|
3280
|
+
}
|
|
3294
3281
|
})
|
|
3295
3282
|
);
|
|
3296
3283
|
return ships.filter((s) => s !== null).sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0));
|
|
@@ -3298,7 +3285,9 @@ async function listMyShips() {
|
|
|
3298
3285
|
async function pickShips(current) {
|
|
3299
3286
|
const ships = await listMyShips();
|
|
3300
3287
|
if (ships.length === 0) {
|
|
3301
|
-
throw new CliError(
|
|
3288
|
+
throw new CliError(
|
|
3289
|
+
"This machine holds no Ship keys. Run `lumi-runner login` and have a captain approve it \u2014 a daemon can only serve Ships it was approved for."
|
|
3290
|
+
);
|
|
3302
3291
|
}
|
|
3303
3292
|
return promptMultiSelect({
|
|
3304
3293
|
message: "Which Ships should this machine serve?",
|
|
@@ -3408,9 +3397,9 @@ import {
|
|
|
3408
3397
|
doc as doc10,
|
|
3409
3398
|
getCountFromServer as getCountFromServer2,
|
|
3410
3399
|
getDoc as getDoc8,
|
|
3411
|
-
getDocs as
|
|
3412
|
-
query as
|
|
3413
|
-
where as
|
|
3400
|
+
getDocs as getDocs5,
|
|
3401
|
+
query as query4,
|
|
3402
|
+
where as where4
|
|
3414
3403
|
} from "firebase/firestore";
|
|
3415
3404
|
async function runStatus() {
|
|
3416
3405
|
const config2 = loadConfig();
|
|
@@ -3424,16 +3413,33 @@ async function runStatus() {
|
|
|
3424
3413
|
}
|
|
3425
3414
|
const progress = spinner2();
|
|
3426
3415
|
progress.start("Reading Ship state\u2026");
|
|
3427
|
-
const { fb } = await openSession();
|
|
3428
3416
|
const ships = [];
|
|
3429
3417
|
for (const shipId of config2.ships) {
|
|
3418
|
+
let fb;
|
|
3419
|
+
try {
|
|
3420
|
+
({ fb } = await openShipSession(shipId));
|
|
3421
|
+
} catch {
|
|
3422
|
+
ships.push({
|
|
3423
|
+
shipId,
|
|
3424
|
+
enrolled: false,
|
|
3425
|
+
approved: false,
|
|
3426
|
+
online: false,
|
|
3427
|
+
lastSeenAt: null,
|
|
3428
|
+
currentJob: null,
|
|
3429
|
+
queued: 0,
|
|
3430
|
+
today: { ...EMPTY_USAGE_TOTALS },
|
|
3431
|
+
engineLimits: [],
|
|
3432
|
+
unreachable: true
|
|
3433
|
+
});
|
|
3434
|
+
continue;
|
|
3435
|
+
}
|
|
3430
3436
|
const shipRef = doc10(fb.db, COLLECTIONS.ships, shipId);
|
|
3431
3437
|
const mirrorSnap = await getDoc8(doc10(shipRef, COLLECTIONS.runners, config2.runnerId));
|
|
3432
3438
|
const mirror = mirrorSnap.data();
|
|
3433
3439
|
let queued = 0;
|
|
3434
3440
|
try {
|
|
3435
3441
|
const counted = await getCountFromServer2(
|
|
3436
|
-
|
|
3442
|
+
query4(collection7(shipRef, COLLECTIONS.jobs), where4("status", "==", "queued"))
|
|
3437
3443
|
);
|
|
3438
3444
|
queued = counted.data().count;
|
|
3439
3445
|
} catch {
|
|
@@ -3442,7 +3448,7 @@ async function runStatus() {
|
|
|
3442
3448
|
const usageSnap = await getDoc8(doc10(shipRef, COLLECTIONS.usageDaily, utcDay(Date.now())));
|
|
3443
3449
|
const today = { ...EMPTY_USAGE_TOTALS, ...usageSnap.data()?.totals ?? {} };
|
|
3444
3450
|
const now = Date.now();
|
|
3445
|
-
const limitsSnap = await
|
|
3451
|
+
const limitsSnap = await getDocs5(collection7(shipRef, COLLECTIONS.engineLimits));
|
|
3446
3452
|
const engineLimits = limitsSnap.docs.map((d) => ({ id: d.id, ...d.data() })).filter((l) => isEngineLimited(l, now));
|
|
3447
3453
|
ships.push({
|
|
3448
3454
|
shipId,
|
|
@@ -3479,8 +3485,12 @@ async function runStatus() {
|
|
|
3479
3485
|
return 0;
|
|
3480
3486
|
}
|
|
3481
3487
|
for (const ship2 of ships) {
|
|
3482
|
-
const state = !ship2.enrolled ? pc.dim("not enrolled") : !ship2.approved ? pc.yellow("awaiting approval") : ship2.online ? pc.green("online") : pc.red("offline");
|
|
3488
|
+
const state = ship2.unreachable ? pc.red("no access") : !ship2.enrolled ? pc.dim("not enrolled") : !ship2.approved ? pc.yellow("awaiting approval") : ship2.online ? pc.green("online") : pc.red("offline");
|
|
3483
3489
|
say.line(` ${pc.bold(ship2.shipId)} ${state}`);
|
|
3490
|
+
if (ship2.unreachable) {
|
|
3491
|
+
say.line(` ${pc.dim("this machine\u2019s key for that Ship was revoked \u2014 re-approve it on the Daemons page")}`);
|
|
3492
|
+
continue;
|
|
3493
|
+
}
|
|
3484
3494
|
if (ship2.lastSeenAt) say.line(` last seen ${new Date(ship2.lastSeenAt).toLocaleString()}`);
|
|
3485
3495
|
say.line(
|
|
3486
3496
|
ship2.currentJob ? ` running job ${ship2.currentJob.jobId} on task ${ship2.currentJob.taskId} (agent ${ship2.currentJob.agentId})` : " running nothing"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumi.ai/runner",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lumi Crew runner daemon — claims jobs from your Ships and executes them as headless Claude sessions on your own machine.",
|
|
6
6
|
"//name": "The ONLY package in this monorepo published to the public registry, so it is the one that does not follow the internal @lumi/crew-* convention: `@lumi` is not a scope we own, `@lumi.ai` is (the npm org). The workspace DIRECTORY stays packages/crew/runner — renaming the package is not renaming the folder.",
|