@lumi.ai/runner 0.15.17 → 0.15.18

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.
Files changed (2) hide show
  1. package/dist/cli.js +60 -88
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8,8 +8,8 @@ import os4 from "node:os";
8
8
  import {
9
9
  collection as collection7,
10
10
  deleteField as deleteField2,
11
- doc as doc8,
12
- getDoc as getDoc7,
11
+ doc as doc7,
12
+ getDoc as getDoc6,
13
13
  getDocs as getDocs6,
14
14
  onSnapshot as onSnapshot2,
15
15
  orderBy as orderBy4,
@@ -844,21 +844,6 @@ function firstStatusIn(statuses, category) {
844
844
  var RUNNER_OFFLINE_AFTER_MS = 2 * 60 * 1e3;
845
845
 
846
846
  // ../shared/dist/secrets.js
847
- var SECRET_DOCS = {
848
- /** Captain-provided runner credentials (this file's shape). */
849
- runner: "runner",
850
- /** `{ tokenHash }` for the Workspace MCP bearer — backend-only, never client-readable. */
851
- mcp: "mcp",
852
- /**
853
- * `{ runnerId, keyHash }` for THIS Ship's daemon credential (PRD §8.1) — backend-only.
854
- *
855
- * One document, not one per machine, because a Ship runs one daemon: issuing a key is
856
- * therefore also how the previous one is revoked, exactly like rotating the MCP bearer.
857
- * Only `docId == 'runner'` is released by packages/crew/firestore.rules, so this falls
858
- * through to deny for every client without needing a rule of its own.
859
- */
860
- runnerKey: "runnerKey"
861
- };
862
847
  function missingSecretsFor(engineId, secrets) {
863
848
  const bag = secrets;
864
849
  return getEngine(engineId).requiredSecrets.filter((req) => !bag?.[req.key]).map((req) => req.label);
@@ -1038,7 +1023,7 @@ function mcpUrl(config2) {
1038
1023
  }
1039
1024
 
1040
1025
  // src/version.ts
1041
- var RUNNER_VERSION = true ? "0.15.17" : "0.0.0-dev";
1026
+ var RUNNER_VERSION = true ? "0.15.18" : "0.0.0-dev";
1042
1027
 
1043
1028
  // src/auth.ts
1044
1029
  import { signInWithCustomToken } from "firebase/auth";
@@ -2420,13 +2405,12 @@ async function resolveGithubToken(input) {
2420
2405
  throw e;
2421
2406
  }
2422
2407
  }
2423
- if (integration && !input.githubPat) {
2408
+ if (integration) {
2424
2409
  return {
2425
2410
  source: "none",
2426
2411
  unavailable: `The Ship's GitHub connection is ${integration.status}. A captain can fix it in Ship Settings \u203A GitHub.`
2427
2412
  };
2428
2413
  }
2429
- if (input.githubPat) return { token: input.githubPat, source: "pat" };
2430
2414
  return null;
2431
2415
  }
2432
2416
 
@@ -2738,17 +2722,8 @@ function serversNeedingProbe(servers) {
2738
2722
  );
2739
2723
  }
2740
2724
 
2741
- // src/jobs/secrets.ts
2742
- import { doc as doc4, getDoc as getDoc4 } from "firebase/firestore";
2743
- async function loadRunnerSecrets(db, shipId) {
2744
- const snap = await withFirestoreRetry(
2745
- () => getDoc4(doc4(db, COLLECTIONS.ships, shipId, COLLECTIONS.secrets, SECRET_DOCS.runner))
2746
- );
2747
- return snap.exists() ? snap.data() : null;
2748
- }
2749
-
2750
2725
  // src/jobs/credentials.ts
2751
- import { collection as collection4, doc as doc5, getDoc as getDoc5, getDocs as getDocs4 } from "firebase/firestore";
2726
+ import { collection as collection4, doc as doc4, getDoc as getDoc4, getDocs as getDocs4 } from "firebase/firestore";
2752
2727
  async function loadShipCredentials(db, shipId) {
2753
2728
  const snap = await withFirestoreRetry(
2754
2729
  () => getDocs4(collection4(db, COLLECTIONS.ships, shipId, COLLECTIONS.credentials))
@@ -2757,35 +2732,41 @@ async function loadShipCredentials(db, shipId) {
2757
2732
  }
2758
2733
  async function loadCredentialToken(db, shipId, credentialId) {
2759
2734
  const snap = await withFirestoreRetry(
2760
- () => getDoc5(doc5(db, COLLECTIONS.ships, shipId, COLLECTIONS.secrets, credentialId))
2735
+ () => getDoc4(doc4(db, COLLECTIONS.ships, shipId, COLLECTIONS.secrets, credentialId))
2761
2736
  );
2762
2737
  if (!snap.exists()) return null;
2763
2738
  const token = snap.data().token;
2764
2739
  return typeof token === "string" && token.trim() ? token : null;
2765
2740
  }
2766
2741
  async function resolveJobSecrets(input) {
2767
- const { agent, credentials, runnerSecrets } = input;
2742
+ const { agent, credentials } = input;
2768
2743
  const engineId = agentEngine(agent);
2769
2744
  const resolved = resolveAgentCredential(agent, credentials, DEFAULT_ENGINE_ID);
2770
- if (resolved === void 0) return { secrets: runnerSecrets };
2745
+ if (resolved === void 0) {
2746
+ return {
2747
+ secrets: null,
2748
+ problem: `This workspace has no AI credential for ${engineId}. Add one in Settings \u203A AI credentials and the crew starts taking work again.`
2749
+ };
2750
+ }
2771
2751
  if (resolved === null) {
2772
2752
  return {
2773
- secrets: runnerSecrets,
2753
+ secrets: null,
2774
2754
  problem: `This agent is set to an AI credential that no longer exists on the Ship. Point it at another one in Settings \u203A AI credentials, or add the credential back.`
2775
2755
  };
2776
2756
  }
2777
2757
  const token = await loadCredentialToken(input.db, input.shipId, resolved.id);
2778
2758
  if (!token) {
2779
2759
  return {
2780
- secrets: runnerSecrets,
2760
+ secrets: null,
2781
2761
  problem: `The AI credential "${resolved.label}" has no token stored. Erase it in Settings \u203A AI credentials and add it again.`
2782
2762
  };
2783
2763
  }
2784
2764
  const key = getEngine(engineId).requiredSecrets[0]?.key;
2785
- if (!key) return { secrets: runnerSecrets };
2765
+ if (!key) return { secrets: null };
2786
2766
  return {
2787
2767
  secrets: {
2788
- ...runnerSecrets ?? { updatedAt: resolved.updatedAt, updatedBy: resolved.createdBy },
2768
+ updatedAt: resolved.updatedAt,
2769
+ updatedBy: resolved.createdBy,
2789
2770
  [key]: token,
2790
2771
  [`${key}Tail`]: resolved.tail
2791
2772
  }
@@ -2796,7 +2777,7 @@ async function resolveJobSecrets(input) {
2796
2777
  import {
2797
2778
  collection as collection5,
2798
2779
  deleteDoc,
2799
- doc as doc6,
2780
+ doc as doc5,
2800
2781
  onSnapshot,
2801
2782
  setDoc
2802
2783
  } from "firebase/firestore";
@@ -2825,7 +2806,7 @@ function nextResetAt(limits, now) {
2825
2806
  return soonest;
2826
2807
  }
2827
2808
  function limitRef(db, shipId, engineId) {
2828
- return doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.engineLimits, engineId);
2809
+ return doc5(db, COLLECTIONS.ships, shipId, COLLECTIONS.engineLimits, engineId);
2829
2810
  }
2830
2811
  async function noteEngineLimit(db, shipId, engineId, limit3, runnerId) {
2831
2812
  await setDoc(limitRef(db, shipId, engineId), {
@@ -2924,8 +2905,8 @@ import {
2924
2905
  addDoc,
2925
2906
  collection as collection6,
2926
2907
  deleteField,
2927
- doc as doc7,
2928
- getDoc as getDoc6,
2908
+ doc as doc6,
2909
+ getDoc as getDoc5,
2929
2910
  getDocs as getDocs5,
2930
2911
  limit as fsLimit,
2931
2912
  orderBy as orderBy3,
@@ -2971,10 +2952,10 @@ function backstopReportContent(resultText2) {
2971
2952
  return { report: report4, summary };
2972
2953
  }
2973
2954
  async function finalizeJob(db, shipId, job, input) {
2974
- const shipRef = doc7(db, COLLECTIONS.ships, shipId);
2975
- const jobRef = doc7(shipRef, COLLECTIONS.jobs, job.id);
2955
+ const shipRef = doc6(db, COLLECTIONS.ships, shipId);
2956
+ const jobRef = doc6(shipRef, COLLECTIONS.jobs, job.id);
2976
2957
  const now = Date.now();
2977
- const usageRef = doc7(shipRef, COLLECTIONS.usageDaily, utcDay(now));
2958
+ const usageRef = doc6(shipRef, COLLECTIONS.usageDaily, utcDay(now));
2978
2959
  await runTransaction(db, async (tx) => {
2979
2960
  const usageSnap = await tx.get(usageRef);
2980
2961
  const jobSnap = await tx.get(jobRef);
@@ -3036,7 +3017,7 @@ async function finalizeJob(db, shipId, job, input) {
3036
3017
  }
3037
3018
  async function requeueForRetry(db, shipId, job, error) {
3038
3019
  await runTransaction(db, async (tx) => {
3039
- tx.update(doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
3020
+ tx.update(doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
3040
3021
  status: "queued",
3041
3022
  attempt: job.attempt + 1,
3042
3023
  error: error.slice(0, 1500),
@@ -3046,7 +3027,7 @@ async function requeueForRetry(db, shipId, job, error) {
3046
3027
  });
3047
3028
  }
3048
3029
  async function releaseJob(db, shipId, job, reason) {
3049
- await updateDoc(doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
3030
+ await updateDoc(doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
3050
3031
  status: "queued",
3051
3032
  runnerId: "",
3052
3033
  startedAt: 0,
@@ -3062,13 +3043,13 @@ async function releaseJob(db, shipId, job, reason) {
3062
3043
  });
3063
3044
  }
3064
3045
  async function markTaskFailed(db, shipId, job, error, statuses) {
3065
- const shipRef = doc7(db, COLLECTIONS.ships, shipId);
3066
- const taskRef = doc7(shipRef, COLLECTIONS.tasks, job.taskId);
3046
+ const shipRef = doc6(db, COLLECTIONS.ships, shipId);
3047
+ const taskRef = doc6(shipRef, COLLECTIONS.tasks, job.taskId);
3067
3048
  const now = Date.now();
3068
3049
  const failedStatus = firstStatusIn(statuses, "failed")?.id ?? "failed";
3069
3050
  await runTransaction(db, async (tx) => {
3070
3051
  tx.update(taskRef, { status: failedStatus, updatedAt: now });
3071
- tx.set(doc7(collection6(taskRef, COLLECTIONS.activity)), {
3052
+ tx.set(doc6(collection6(taskRef, COLLECTIONS.activity)), {
3072
3053
  author: { type: "agent", id: job.agentId },
3073
3054
  createdAt: now,
3074
3055
  kind: "comment",
@@ -3082,7 +3063,7 @@ ${error.slice(0, 800)}
3082
3063
  });
3083
3064
  }
3084
3065
  async function markTaskStopped(db, shipId, job, stoppedBy) {
3085
- const taskRef = doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.tasks, job.taskId);
3066
+ const taskRef = doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.tasks, job.taskId);
3086
3067
  const who = await actorName(db, shipId, stoppedBy);
3087
3068
  await addDoc(collection6(taskRef, COLLECTIONS.activity), {
3088
3069
  author: { type: "agent", id: job.agentId },
@@ -3093,7 +3074,7 @@ async function markTaskStopped(db, shipId, job, stoppedBy) {
3093
3074
  }
3094
3075
  async function actorName(db, shipId, actorId) {
3095
3076
  try {
3096
- const snap = await getDoc6(doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.members, actorId));
3077
+ const snap = await getDoc5(doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.members, actorId));
3097
3078
  const m = snap.data();
3098
3079
  return m?.displayName || m?.email || actorId;
3099
3080
  } catch {
@@ -3101,7 +3082,7 @@ async function actorName(db, shipId, actorId) {
3101
3082
  }
3102
3083
  }
3103
3084
  async function markChatStopped(db, shipId, job, stoppedBy) {
3104
- const chatRef = doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.chats, job.chatId);
3085
+ const chatRef = doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.chats, job.chatId);
3105
3086
  const who = await actorName(db, shipId, stoppedBy);
3106
3087
  const content = `Stopped by ${who} before I finished. Write again to start a fresh run.`;
3107
3088
  await addDoc(collection6(chatRef, COLLECTIONS.chatMessages), {
@@ -3116,8 +3097,8 @@ async function markChatStopped(db, shipId, job, stoppedBy) {
3116
3097
  });
3117
3098
  }
3118
3099
  async function markChatFailed(db, shipId, job, error) {
3119
- const shipRef = doc7(db, COLLECTIONS.ships, shipId);
3120
- const chatRef = doc7(shipRef, COLLECTIONS.chats, job.chatId);
3100
+ const shipRef = doc6(db, COLLECTIONS.ships, shipId);
3101
+ const chatRef = doc6(shipRef, COLLECTIONS.chats, job.chatId);
3121
3102
  const now = Date.now();
3122
3103
  const content = `I could not finish replying \u2014 the run failed after ${job.attempt} attempt(s).
3123
3104
 
@@ -3145,7 +3126,7 @@ function backstopReplyContent(resultText2) {
3145
3126
  return `${text.slice(0, MAX_CHAT_MESSAGE_CHARS - marker.length)}${marker}`;
3146
3127
  }
3147
3128
  async function ensureChatReply(db, shipId, job, resultText2) {
3148
- const chatRef = doc7(db, COLLECTIONS.ships, shipId, COLLECTIONS.chats, job.chatId);
3129
+ const chatRef = doc6(db, COLLECTIONS.ships, shipId, COLLECTIONS.chats, job.chatId);
3149
3130
  const messagesCol = collection6(chatRef, COLLECTIONS.chatMessages);
3150
3131
  const snap = await getDocs5(
3151
3132
  query3(
@@ -3971,7 +3952,7 @@ async function startDaemon() {
3971
3952
  const warnedUnapproved = /* @__PURE__ */ new Set();
3972
3953
  const shipRunnerRef = (shipId) => {
3973
3954
  const session = sess(shipId);
3974
- return doc8(session.fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.runners, session.runnerId);
3955
+ return doc7(session.fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.runners, session.runnerId);
3975
3956
  };
3976
3957
  const needsRefill = /* @__PURE__ */ new Set();
3977
3958
  let beating = false;
@@ -3982,7 +3963,7 @@ async function startDaemon() {
3982
3963
  try {
3983
3964
  for (const shipId of [...serving]) {
3984
3965
  try {
3985
- const snap = await getDoc7(shipRunnerRef(shipId));
3966
+ const snap = await getDoc6(shipRunnerRef(shipId));
3986
3967
  if (!snap.exists()) {
3987
3968
  forgetShipLocally(shipId, "a captain removed this machine on the Daemons page");
3988
3969
  continue;
@@ -4327,7 +4308,7 @@ async function startDaemon() {
4327
4308
  pending.set(`${shipId}/${job.id}`, { shipId, job });
4328
4309
  return null;
4329
4310
  }
4330
- const jobRef = doc8(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id);
4311
+ const jobRef = doc7(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id);
4331
4312
  try {
4332
4313
  let claimed = null;
4333
4314
  await runTransaction2(sess(shipId).fb.db, async (tx) => {
@@ -4350,14 +4331,11 @@ async function startDaemon() {
4350
4331
  }
4351
4332
  async function setAgentStatus(shipId, agentId, status) {
4352
4333
  try {
4353
- await updateDoc2(doc8(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.agents, agentId), { status });
4334
+ await updateDoc2(doc7(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.agents, agentId), { status });
4354
4335
  } catch (e) {
4355
4336
  log2(`agent status update failed: ${e instanceof Error ? e.message : e}`);
4356
4337
  }
4357
4338
  }
4358
- async function loadSecrets(shipId) {
4359
- return loadRunnerSecrets(sess(shipId).fb.db, shipId);
4360
- }
4361
4339
  async function processJob(shipId, queuedJob, slot) {
4362
4340
  const job = await claim(shipId, queuedJob);
4363
4341
  if (!job) return;
@@ -4397,8 +4375,8 @@ async function startDaemon() {
4397
4375
  void (async () => {
4398
4376
  if (slot.stop) return;
4399
4377
  try {
4400
- const snap = await getDoc7(
4401
- doc8(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id)
4378
+ const snap = await getDoc6(
4379
+ doc7(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id)
4402
4380
  );
4403
4381
  const fresh = snap.data();
4404
4382
  if (!fresh?.stopRequestedAt || slot.stop) return;
@@ -4438,7 +4416,7 @@ async function startDaemon() {
4438
4416
  let statuses = DEFAULT_TASK_STATUSES;
4439
4417
  let knownSecrets = [];
4440
4418
  const progress = createProgressWriter({
4441
- write: (p) => updateDoc2(doc8(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
4419
+ write: (p) => updateDoc2(doc7(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id), {
4442
4420
  progress: p
4443
4421
  }),
4444
4422
  secrets: () => knownSecrets,
@@ -4452,8 +4430,8 @@ async function startDaemon() {
4452
4430
  onDenied: () => {
4453
4431
  void (async () => {
4454
4432
  try {
4455
- const snap = await getDoc7(
4456
- doc8(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id)
4433
+ const snap = await getDoc6(
4434
+ doc7(sess(shipId).fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.jobs, job.id)
4457
4435
  );
4458
4436
  const fresh = snap.data();
4459
4437
  if (!fresh || fresh.status !== "running" || fresh.runnerId !== sess(shipId).runnerId) {
@@ -4468,7 +4446,7 @@ async function startDaemon() {
4468
4446
  });
4469
4447
  progress.push({ kind: "start", label: "Starting up" });
4470
4448
  try {
4471
- let secrets = await loadSecrets(shipId);
4449
+ let secrets = null;
4472
4450
  const packed = target.kind === "chat" ? { kind: "chat", ctx: await loadChatContext(sess(shipId).fb.db, shipId, { ...job, chatId: target.chatId }) } : { kind: "task", ctx: await loadJobContext(sess(shipId).fb.db, shipId, { ...job, taskId: target.taskId }) };
4473
4451
  if (packed.kind === "task" && !isWorkflowSentinel(job.workflowId) && !packed.ctx.workflow) {
4474
4452
  log2(
@@ -4483,7 +4461,6 @@ async function startDaemon() {
4483
4461
  db: sess(shipId).fb.db,
4484
4462
  shipId,
4485
4463
  agent,
4486
- runnerSecrets: secrets,
4487
4464
  credentials: await loadShipCredentials(sess(shipId).fb.db, shipId).catch(() => [])
4488
4465
  });
4489
4466
  if (resolvedSecrets.problem) {
@@ -4521,8 +4498,7 @@ async function startDaemon() {
4521
4498
  idToken,
4522
4499
  shipId,
4523
4500
  jobId: job.id,
4524
- agent,
4525
- githubPat: secrets?.githubPat
4501
+ agent
4526
4502
  });
4527
4503
  githubToken = gh?.token;
4528
4504
  githubRepos = gh?.repos;
@@ -4562,7 +4538,6 @@ async function startDaemon() {
4562
4538
  idToken,
4563
4539
  secrets?.claudeToken,
4564
4540
  githubToken,
4565
- secrets?.githubPat,
4566
4541
  // §15.31. BOTH the composed header value and the bare credential — see
4567
4542
  // `mcpSecretsToRedact` for why one of them is not enough.
4568
4543
  ...mcpSecretsToRedact(extraMcpServers)
@@ -4747,7 +4722,6 @@ async function startDaemon() {
4747
4722
  if (serving.has(shipId)) await setAgentStatus(shipId, job.agentId, "idle");
4748
4723
  if (!shuttingDown) void heartbeat();
4749
4724
  }
4750
- await Promise.all([...serving].map((shipId) => loadSecrets(shipId).catch(() => null)));
4751
4725
  await heartbeat();
4752
4726
  const heartbeatTimer = setInterval(() => {
4753
4727
  void heartbeat();
@@ -5288,7 +5262,7 @@ function setParallel(config2, value, ship2) {
5288
5262
  import { spawnSync as spawnSync3 } from "node:child_process";
5289
5263
  import fs7 from "node:fs";
5290
5264
  import path8 from "node:path";
5291
- import { collection as collection8, doc as doc9, getDoc as getDoc8, getDocs as getDocs7 } from "firebase/firestore";
5265
+ import { collection as collection8, doc as doc8, getDoc as getDoc7, getDocs as getDocs7 } from "firebase/firestore";
5292
5266
 
5293
5267
  // src/cli/session.ts
5294
5268
  async function openShipSession(shipId) {
@@ -5457,8 +5431,8 @@ async function checkShips(config2) {
5457
5431
  continue;
5458
5432
  }
5459
5433
  try {
5460
- const snap = await getDoc8(
5461
- doc9(session.fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.runners, session.runnerId)
5434
+ const snap = await getDoc7(
5435
+ doc8(session.fb.db, COLLECTIONS.ships, shipId, COLLECTIONS.runners, session.runnerId)
5462
5436
  );
5463
5437
  if (!snap.exists()) {
5464
5438
  checks.push(
@@ -5508,14 +5482,12 @@ async function checkShips(config2) {
5508
5482
  for (const id of shipEngines) engines.add(id);
5509
5483
  if (agents.some((agent) => effectiveAgentTools(agent).github.enabled)) needsGithub = true;
5510
5484
  try {
5511
- const secrets = await loadRunnerSecrets(session.fb.db, shipId);
5512
5485
  const credentials = await loadShipCredentials(session.fb.db, shipId).catch(() => []);
5513
5486
  const missing = [
5514
5487
  ...new Set(
5515
- [...shipEngines].flatMap((id) => {
5516
- if (credentials.some((c) => c.engine === id)) return [];
5517
- return missingSecretsFor(id, secrets);
5518
- })
5488
+ [...shipEngines].flatMap(
5489
+ (id) => credentials.some((c) => c.engine === id) ? [] : missingSecretsFor(id, null)
5490
+ )
5519
5491
  )
5520
5492
  ];
5521
5493
  const orphaned = agents.filter(
@@ -5999,7 +5971,7 @@ async function runUninstall(options) {
5999
5971
  }
6000
5972
 
6001
5973
  // src/cli/commands/ship.ts
6002
- import { doc as doc10, getDoc as getDoc9 } from "firebase/firestore";
5974
+ import { doc as doc9, getDoc as getDoc8 } from "firebase/firestore";
6003
5975
  async function listMyShips() {
6004
5976
  const config2 = requireConfig();
6005
5977
  const ids = Object.keys(config2.shipKeys ?? {});
@@ -6007,7 +5979,7 @@ async function listMyShips() {
6007
5979
  ids.map(async (id) => {
6008
5980
  try {
6009
5981
  const { fb } = await openShipSession(id);
6010
- const snap = await getDoc9(doc10(fb.db, COLLECTIONS.ships, id));
5982
+ const snap = await getDoc8(doc9(fb.db, COLLECTIONS.ships, id));
6011
5983
  return { id, ...snap.data() };
6012
5984
  } catch {
6013
5985
  return null;
@@ -6168,9 +6140,9 @@ async function runSetup(options) {
6168
6140
  // src/cli/commands/status.ts
6169
6141
  import {
6170
6142
  collection as collection9,
6171
- doc as doc11,
6143
+ doc as doc10,
6172
6144
  getCountFromServer as getCountFromServer2,
6173
- getDoc as getDoc10,
6145
+ getDoc as getDoc9,
6174
6146
  getDocs as getDocs8,
6175
6147
  query as query5,
6176
6148
  where as where5
@@ -6208,8 +6180,8 @@ async function runStatus() {
6208
6180
  });
6209
6181
  continue;
6210
6182
  }
6211
- const shipRef = doc11(session.fb.db, COLLECTIONS.ships, shipId);
6212
- const mirrorSnap = await getDoc10(doc11(shipRef, COLLECTIONS.runners, session.runnerId));
6183
+ const shipRef = doc10(session.fb.db, COLLECTIONS.ships, shipId);
6184
+ const mirrorSnap = await getDoc9(doc10(shipRef, COLLECTIONS.runners, session.runnerId));
6213
6185
  const mirror = mirrorSnap.data();
6214
6186
  let queued = 0;
6215
6187
  try {
@@ -6220,7 +6192,7 @@ async function runStatus() {
6220
6192
  } catch {
6221
6193
  queued = 0;
6222
6194
  }
6223
- const usageSnap = await getDoc10(doc11(shipRef, COLLECTIONS.usageDaily, utcDay(Date.now())));
6195
+ const usageSnap = await getDoc9(doc10(shipRef, COLLECTIONS.usageDaily, utcDay(Date.now())));
6224
6196
  const today = { ...EMPTY_USAGE_TOTALS, ...usageSnap.data()?.totals ?? {} };
6225
6197
  const now = Date.now();
6226
6198
  const limitsSnap = await getDocs8(collection9(shipRef, COLLECTIONS.engineLimits));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumi.ai/runner",
3
- "version": "0.15.17",
3
+ "version": "0.15.18",
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.",