@kilogent/runner-dev 0.1.8 → 0.1.9

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 +28 -11
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1257,7 +1257,7 @@ import os from "node:os";
1257
1257
  import path from "node:path";
1258
1258
 
1259
1259
  // src/version.ts
1260
- var RUNNER_VERSION = true ? "0.1.8" : "0.0.0-dev";
1260
+ var RUNNER_VERSION = true ? "0.1.9" : "0.0.0-dev";
1261
1261
  var RUNNER_PACKAGE = true ? "@kilogent/runner-dev" : "@kilogent/runner-dev";
1262
1262
  var RUNNER_BIN = true ? "kilogent-runner-dev" : "kilogent-runner-dev";
1263
1263
 
@@ -2563,6 +2563,7 @@ var DEFAULT_ENGINE_POLICIES = {
2563
2563
  var MAX_BLOCKED_VERSIONS = 20;
2564
2564
  var ENGINE_FIRST_CHECK_MS = 6e4;
2565
2565
  var ENGINE_CHECK_MS = 6 * 36e5;
2566
+ var ENGINE_INSTALL_HOLD_MS = 15 * 6e4;
2566
2567
  function resolveEnginePolicy(engineId, doc13) {
2567
2568
  const shipped = DEFAULT_ENGINE_POLICIES[engineId] ?? { knownGood: "", blocked: [], minAgeHours: 24 };
2568
2569
  const raw = doc13?.[engineId];
@@ -5419,9 +5420,9 @@ async function refreshOne(engineId, input, now) {
5419
5420
  }
5420
5421
  async function ensureEngineReady(engineId, input) {
5421
5422
  const [state] = await refreshEngineTools({ ...input, engineIds: [engineId] });
5422
- if (!state) return { ok: false, detail: `This runner does not know the engine "${engineId}".` };
5423
- if (state.state === "ready" || state.state === "unmanaged") return { ok: true, detail: state.detail ?? "" };
5424
- return { ok: false, detail: state.detail ?? `The "${engineId}" CLI is not installed on this machine.` };
5423
+ if (!state) return { ok: false, detail: `This runner does not know the engine "${engineId}".`, state: null };
5424
+ if (state.state === "ready" || state.state === "unmanaged") return { ok: true, detail: state.detail ?? "", state };
5425
+ return { ok: false, detail: state.detail ?? `The "${engineId}" CLI is not installed on this machine.`, state };
5425
5426
  }
5426
5427
  function describeCurrent(engineId, input, marker, record, reason) {
5427
5428
  if (marker && managedEngineBin(engineId, { root: input.root })) {
@@ -6292,7 +6293,9 @@ async function startDaemon() {
6292
6293
  function engineUsable(engineId) {
6293
6294
  const state = engineToolStates.get(engineId);
6294
6295
  if (!state) return true;
6295
- return state.state !== "installing";
6296
+ if (state.state !== "installing") return true;
6297
+ const since = engineInstallingSince.get(engineId);
6298
+ return since !== void 0 && Date.now() - since > ENGINE_INSTALL_HOLD_MS;
6296
6299
  }
6297
6300
  let dispatching = false;
6298
6301
  let pokeRequested = false;
@@ -6304,6 +6307,8 @@ async function startDaemon() {
6304
6307
  let updatePhase = null;
6305
6308
  const engineToolStates = /* @__PURE__ */ new Map();
6306
6309
  let checkingEngines = false;
6310
+ let engineCheckRequested = false;
6311
+ const engineInstallingSince = /* @__PURE__ */ new Map();
6307
6312
  let nextEngineCheckAt = Date.now() + ENGINE_FIRST_CHECK_MS + Math.floor(Math.random() * UPDATE_JITTER_MS);
6308
6313
  const loggedEngineRefusals = /* @__PURE__ */ new Set();
6309
6314
  function poke() {
@@ -7011,15 +7016,26 @@ async function startDaemon() {
7011
7016
  policyDoc: policySnap?.exists() ? policySnap.data() : null,
7012
7017
  log: (line) => log2(line),
7013
7018
  onState: (state) => {
7014
- engineToolStates.set(state.engineId, state);
7019
+ noteEngineState(state);
7015
7020
  void heartbeat();
7016
7021
  }
7017
7022
  });
7018
- void maybeCheckEnginesSoon();
7019
- return result;
7023
+ if (result.state) noteEngineState(result.state);
7024
+ void heartbeat();
7025
+ maybeCheckEnginesSoon();
7026
+ return { ok: result.ok, detail: result.detail };
7027
+ }
7028
+ function noteEngineState(state) {
7029
+ engineToolStates.set(state.engineId, state);
7030
+ if (state.state === "installing") {
7031
+ if (!engineInstallingSince.has(state.engineId)) engineInstallingSince.set(state.engineId, Date.now());
7032
+ } else {
7033
+ engineInstallingSince.delete(state.engineId);
7034
+ }
7020
7035
  }
7021
7036
  function maybeCheckEnginesSoon() {
7022
7037
  nextEngineCheckAt = 0;
7038
+ engineCheckRequested = true;
7023
7039
  }
7024
7040
  async function rollBackEngine(engineId, fault, say2) {
7025
7041
  const root = configDir();
@@ -7078,7 +7094,7 @@ async function startDaemon() {
7078
7094
  policyDoc: policySnap?.exists() ? policySnap.data() : null,
7079
7095
  log: (line) => log2(line),
7080
7096
  onState: (state) => {
7081
- engineToolStates.set(state.engineId, state);
7097
+ noteEngineState(state);
7082
7098
  void heartbeat();
7083
7099
  }
7084
7100
  });
@@ -7089,14 +7105,15 @@ async function startDaemon() {
7089
7105
  log2(`Engine "${state.engineId}": ${state.detail ?? "not installed on this machine"}`);
7090
7106
  }
7091
7107
  if (state.state === "ready") loggedEngineRefusals.delete(key);
7092
- engineToolStates.set(state.engineId, state);
7108
+ noteEngineState(state);
7093
7109
  }
7094
7110
  poke();
7095
7111
  } catch (e) {
7096
7112
  log2(`Engine check failed: ${e instanceof Error ? e.message : e}`);
7097
7113
  } finally {
7098
7114
  checkingEngines = false;
7099
- nextEngineCheckAt = Date.now() + ENGINE_CHECK_MS;
7115
+ nextEngineCheckAt = engineCheckRequested ? 0 : Date.now() + ENGINE_CHECK_MS;
7116
+ engineCheckRequested = false;
7100
7117
  }
7101
7118
  }
7102
7119
  function beginUpdate(target) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kilogent/runner-dev",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Lumi Crew runner daemon — claims jobs from your Ships and executes them as headless agent sessions (Claude Code today) 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.",