@kilogent/runner-dev 0.1.7 → 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 +31 -13
  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.7" : "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
 
@@ -2495,7 +2495,7 @@ async function resolveAssistantCredential(db, shipId, machine) {
2495
2495
  const credentialId = settings?.assistant?.credentialId ?? settings?.defaultCredentialId;
2496
2496
  const credentials = await loadShipCredentials(db, shipId).catch(() => []);
2497
2497
  const credential = credentialId ? credentials.find((c) => c.id === credentialId) : void 0;
2498
- const engine2 = credential?.engine ?? DEFAULT_ENGINE_ID;
2498
+ const engine2 = isKnownEngine(credential?.engine) ? credential.engine : DEFAULT_ENGINE_ID;
2499
2499
  const secrets = await resolveJobSecrets({
2500
2500
  db,
2501
2501
  shipId,
@@ -2506,6 +2506,7 @@ async function resolveAssistantCredential(db, shipId, machine) {
2506
2506
  });
2507
2507
  return {
2508
2508
  secrets,
2509
+ engine: engine2,
2509
2510
  // A MODEL, ALWAYS. `engines/claude.ts` puts this straight onto `--model`, and an empty string
2510
2511
  // is an empty flag — a failure that reads as the model misbehaving rather than as a missing
2511
2512
  // value. The engine's own default is the right answer when nothing has been chosen.
@@ -2562,6 +2563,7 @@ var DEFAULT_ENGINE_POLICIES = {
2562
2563
  var MAX_BLOCKED_VERSIONS = 20;
2563
2564
  var ENGINE_FIRST_CHECK_MS = 6e4;
2564
2565
  var ENGINE_CHECK_MS = 6 * 36e5;
2566
+ var ENGINE_INSTALL_HOLD_MS = 15 * 6e4;
2565
2567
  function resolveEnginePolicy(engineId, doc13) {
2566
2568
  const shipped = DEFAULT_ENGINE_POLICIES[engineId] ?? { knownGood: "", blocked: [], minAgeHours: 24 };
2567
2569
  const raw = doc13?.[engineId];
@@ -5418,9 +5420,9 @@ async function refreshOne(engineId, input, now) {
5418
5420
  }
5419
5421
  async function ensureEngineReady(engineId, input) {
5420
5422
  const [state] = await refreshEngineTools({ ...input, engineIds: [engineId] });
5421
- if (!state) return { ok: false, detail: `This runner does not know the engine "${engineId}".` };
5422
- if (state.state === "ready" || state.state === "unmanaged") return { ok: true, detail: state.detail ?? "" };
5423
- 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 };
5424
5426
  }
5425
5427
  function describeCurrent(engineId, input, marker, record, reason) {
5426
5428
  if (marker && managedEngineBin(engineId, { root: input.root })) {
@@ -6291,7 +6293,9 @@ async function startDaemon() {
6291
6293
  function engineUsable(engineId) {
6292
6294
  const state = engineToolStates.get(engineId);
6293
6295
  if (!state) return true;
6294
- 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;
6295
6299
  }
6296
6300
  let dispatching = false;
6297
6301
  let pokeRequested = false;
@@ -6303,6 +6307,8 @@ async function startDaemon() {
6303
6307
  let updatePhase = null;
6304
6308
  const engineToolStates = /* @__PURE__ */ new Map();
6305
6309
  let checkingEngines = false;
6310
+ let engineCheckRequested = false;
6311
+ const engineInstallingSince = /* @__PURE__ */ new Map();
6306
6312
  let nextEngineCheckAt = Date.now() + ENGINE_FIRST_CHECK_MS + Math.floor(Math.random() * UPDATE_JITTER_MS);
6307
6313
  const loggedEngineRefusals = /* @__PURE__ */ new Set();
6308
6314
  function poke() {
@@ -6576,7 +6582,7 @@ async function startDaemon() {
6576
6582
  );
6577
6583
  }
6578
6584
  const { ship: ship2, agent } = packed.ctx;
6579
- engineId = agentEngine(agent);
6585
+ engineId = assistantCredential ? assistantCredential.engine : agentEngine(agent);
6580
6586
  usage = { ...usage, engine: engineId };
6581
6587
  statuses = shipTaskStatuses(ship2);
6582
6588
  const resolvedSecrets = assistantCredential ? assistantCredential.secrets : await resolveJobSecrets({
@@ -7010,15 +7016,26 @@ async function startDaemon() {
7010
7016
  policyDoc: policySnap?.exists() ? policySnap.data() : null,
7011
7017
  log: (line) => log2(line),
7012
7018
  onState: (state) => {
7013
- engineToolStates.set(state.engineId, state);
7019
+ noteEngineState(state);
7014
7020
  void heartbeat();
7015
7021
  }
7016
7022
  });
7017
- void maybeCheckEnginesSoon();
7018
- 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
+ }
7019
7035
  }
7020
7036
  function maybeCheckEnginesSoon() {
7021
7037
  nextEngineCheckAt = 0;
7038
+ engineCheckRequested = true;
7022
7039
  }
7023
7040
  async function rollBackEngine(engineId, fault, say2) {
7024
7041
  const root = configDir();
@@ -7077,7 +7094,7 @@ async function startDaemon() {
7077
7094
  policyDoc: policySnap?.exists() ? policySnap.data() : null,
7078
7095
  log: (line) => log2(line),
7079
7096
  onState: (state) => {
7080
- engineToolStates.set(state.engineId, state);
7097
+ noteEngineState(state);
7081
7098
  void heartbeat();
7082
7099
  }
7083
7100
  });
@@ -7088,14 +7105,15 @@ async function startDaemon() {
7088
7105
  log2(`Engine "${state.engineId}": ${state.detail ?? "not installed on this machine"}`);
7089
7106
  }
7090
7107
  if (state.state === "ready") loggedEngineRefusals.delete(key);
7091
- engineToolStates.set(state.engineId, state);
7108
+ noteEngineState(state);
7092
7109
  }
7093
7110
  poke();
7094
7111
  } catch (e) {
7095
7112
  log2(`Engine check failed: ${e instanceof Error ? e.message : e}`);
7096
7113
  } finally {
7097
7114
  checkingEngines = false;
7098
- nextEngineCheckAt = Date.now() + ENGINE_CHECK_MS;
7115
+ nextEngineCheckAt = engineCheckRequested ? 0 : Date.now() + ENGINE_CHECK_MS;
7116
+ engineCheckRequested = false;
7099
7117
  }
7100
7118
  }
7101
7119
  function beginUpdate(target) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kilogent/runner-dev",
3
- "version": "0.1.7",
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.",