@kilogent/runner 0.1.8 → 0.1.10

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 CHANGED
@@ -1712,12 +1712,12 @@ import os from "node:os";
1712
1712
  import path from "node:path";
1713
1713
 
1714
1714
  // src/version.ts
1715
- var RUNNER_VERSION = true ? "0.1.8" : "0.0.0-dev";
1715
+ var RUNNER_VERSION = true ? "0.1.10" : "0.0.0-dev";
1716
1716
  var RUNNER_PACKAGE = true ? "@kilogent/runner" : "@kilogent/runner-dev";
1717
1717
  var RUNNER_BIN = true ? "kilogent-runner" : "kilogent-runner-dev";
1718
1718
  var SESSION_IMAGE = true ? "europe-west1-docker.pkg.dev/kilogent-crew-prod/sessions/session@sha256:247ecb20c7ee497a75cb02dc8397b6db2375a04923b727ab3e673ff0eccf0559" : "";
1719
1719
  var RUNSC_MIN = true ? "release-20260202.0" : "";
1720
- var LAUNCHER_SHA256 = true ? "75a75420b36364158139030300e53da806208fbbd9a8e07a80c10e48c1f87498" : "";
1720
+ var LAUNCHER_SHA256 = true ? "07d4570416e9feed4a7bd10dbd3d4eed645858e0cee5212f8883f23918b5adfb" : "";
1721
1721
 
1722
1722
  // src/config.ts
1723
1723
  var KNOWN_KEYS = ["apiKey", "projectId", "fleet", "mcpUrl", "notifications", "keepAwake", "autoInstallEngines"];
@@ -1750,6 +1750,13 @@ function connectedConfig(stored) {
1750
1750
  var IS_DEV_BUILD = RUNNER_PACKAGE.endsWith("-dev");
1751
1751
  var DEFAULT_PROJECT_ID = IS_DEV_BUILD ? "lumi-afb7d" : "kilogent-crew-prod";
1752
1752
  var DEFAULT_MCP_URL = IS_DEV_BUILD ? "https://dev-app-kilogent.web.app/mcp" : "https://app.kilogent.com/mcp";
1753
+ var FUNCTIONS_REGIONS = {
1754
+ "lumi-afb7d": "us-central1",
1755
+ "kilogent-crew-prod": "europe-west1"
1756
+ };
1757
+ function functionsRegionFor(projectId) {
1758
+ return FUNCTIONS_REGIONS[projectId] ?? "us-central1";
1759
+ }
1753
1760
  var LEGACY_DIR_NAME = ".crew-runner";
1754
1761
  var DIR_NAME = `.${RUNNER_BIN}`;
1755
1762
  var LUMI_DIR_NAME = ".lumi-runner";
@@ -1821,7 +1828,7 @@ function engineInstallAllowed(config2) {
1821
1828
  return config2?.autoInstallEngines ?? TOGGLE_DEFAULTS.autoInstallEngines;
1822
1829
  }
1823
1830
  function mcpUrl(config2) {
1824
- return process.env.CREW_MCP_URL || config2.mcpUrl || (config2.projectId === DEFAULT_PROJECT_ID ? DEFAULT_MCP_URL : `https://us-central1-${config2.projectId}.cloudfunctions.net/workspaceMcp`);
1831
+ return process.env.CREW_MCP_URL || config2.mcpUrl || (config2.projectId === DEFAULT_PROJECT_ID ? DEFAULT_MCP_URL : `https://${functionsRegionFor(config2.projectId)}-${config2.projectId}.cloudfunctions.net/workspaceMcp`);
1825
1832
  }
1826
1833
 
1827
1834
  // src/auth.ts
@@ -3774,7 +3781,7 @@ function classifyPullError(message2, code) {
3774
3781
  if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EACCES" || /cannot connect to the docker daemon/i.test(message2)) {
3775
3782
  return "docker";
3776
3783
  }
3777
- if (/unauthori[sz]ed|denied|forbidden|\b401\b|\b403\b|authentication required/i.test(message2)) return "auth";
3784
+ if (/unauthori[sz]ed|unauthenticated|denied|forbidden|\b401\b|\b403\b|authentication required/i.test(message2)) return "auth";
3778
3785
  if (/manifest unknown|not found|no such manifest|name unknown|\b404\b/i.test(message2)) return "registry";
3779
3786
  return "network";
3780
3787
  }
@@ -5329,7 +5336,7 @@ function functionsBaseUrl(config2) {
5329
5336
  return functionsBaseUrlFor(config2.projectId);
5330
5337
  }
5331
5338
  function functionsBaseUrlFor(projectId) {
5332
- return process.env.CREW_FUNCTIONS_URL?.replace(/\/$/, "") || `https://us-central1-${projectId}.cloudfunctions.net`;
5339
+ return process.env.CREW_FUNCTIONS_URL?.replace(/\/$/, "") || `https://${functionsRegionFor(projectId)}-${projectId}.cloudfunctions.net`;
5333
5340
  }
5334
5341
  var CallableError = class extends Error {
5335
5342
  constructor(status, message2, details) {
@@ -53,7 +53,7 @@ function classifyPullError(message, code) {
53
53
  if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EACCES" || /cannot connect to the docker daemon/i.test(message)) {
54
54
  return "docker";
55
55
  }
56
- if (/unauthori[sz]ed|denied|forbidden|\b401\b|\b403\b|authentication required/i.test(message)) return "auth";
56
+ if (/unauthori[sz]ed|unauthenticated|denied|forbidden|\b401\b|\b403\b|authentication required/i.test(message)) return "auth";
57
57
  if (/manifest unknown|not found|no such manifest|name unknown|\b404\b/i.test(message)) return "registry";
58
58
  return "network";
59
59
  }
@@ -126,6 +126,7 @@ function unsupportedHostSentence(os3) {
126
126
  return `This is ${os3.id || "an unknown system"} ${os3.versionId}; provision installs on ${names}. With Docker Engine and gVisor (runsc) installed by hand, it checks them instead.`;
127
127
  }
128
128
  var RUNSC_PATH = "/usr/bin/runsc";
129
+ var IMAGE_STORE_FEATURE = "containerd-snapshotter";
129
130
  function mergeDaemonJson(existing) {
130
131
  let doc = {};
131
132
  if (existing && existing.trim()) {
@@ -145,9 +146,22 @@ function mergeDaemonJson(existing) {
145
146
  if ("live-restore" in doc && doc["live-restore"] !== true) {
146
147
  return { ok: false, reason: "daemon.json sets live-restore to false. Provision needs it on; change it by hand if that is safe here." };
147
148
  }
148
- const changed = !runsc || doc["live-restore"] !== true;
149
- const next = { ...doc, runtimes: { ...runtimes, runsc: { path: RUNSC_PATH } }, "live-restore": true };
150
- return { ok: true, changed, text: `${JSON.stringify(next, null, 2)}
149
+ const features = doc.features && typeof doc.features === "object" && !Array.isArray(doc.features) ? doc.features : {};
150
+ if (features[IMAGE_STORE_FEATURE] === true) {
151
+ return {
152
+ ok: false,
153
+ reason: `daemon.json turns on Docker's containerd image store ("${IMAGE_STORE_FEATURE}": true), which pulls the session image without its token. Set it to false by hand if nothing else on this host needs it, then run provision again.`
154
+ };
155
+ }
156
+ const restart = features[IMAGE_STORE_FEATURE] !== false;
157
+ const changed = !runsc || doc["live-restore"] !== true || restart;
158
+ const next = {
159
+ ...doc,
160
+ runtimes: { ...runtimes, runsc: { path: RUNSC_PATH } },
161
+ "live-restore": true,
162
+ features: { ...features, [IMAGE_STORE_FEATURE]: false }
163
+ };
164
+ return { ok: true, changed, restart, text: `${JSON.stringify(next, null, 2)}
151
165
  ` };
152
166
  }
153
167
  var SESSION_BRIDGE = "kg-sessions";
@@ -265,7 +279,13 @@ function planLinuxProvision(facts, options) {
265
279
  else add("gvisor", "root", supported ? "do" : "check", supported ? "Install gVisor from gVisor's signed repository." : "gVisor must be installed by hand here.");
266
280
  const merged = mergeDaemonJson(facts.daemonJson);
267
281
  if (!merged.ok) add("daemon-json", "root", "check", merged.reason);
268
- else add("daemon-json", "root", merged.changed ? "do" : "check", merged.changed ? "Register runsc and turn live-restore on, then reload Docker (never restart it)." : "runsc is registered and live-restore is on.");
282
+ else
283
+ add(
284
+ "daemon-json",
285
+ "root",
286
+ merged.changed ? "do" : "check",
287
+ merged.changed ? "Register runsc, turn live-restore on and use the classic image store, then reload Docker \u2014 restart it only when nothing runs." : "runsc is registered, live-restore is on, and Docker uses the classic image store."
288
+ );
269
289
  if (facts.network.exists && facts.network.iccDisabled === true) {
270
290
  add("network", "root", "check", "The kg-sessions network exists, and its sessions cannot reach each other.");
271
291
  } else if (facts.network.exists && facts.network.attachedContainers > 0) {
@@ -579,8 +599,16 @@ async function runStep(step, ctx) {
579
599
  else fs3.rmSync("/etc/docker/daemon.json", { force: true });
580
600
  throw new StepFailure(`Docker refused the merged daemon.json, so the old one was put back: ${valid.err.trim().slice(0, 200)}`);
581
601
  }
602
+ const kept = backup ? `; the old file is at ${backup}` : "";
603
+ if (merged.restart) {
604
+ const containers = run("docker", ["ps", "-q"]);
605
+ if (containers.ok && containers.out.trim() === "") {
606
+ must("systemctl", ["restart", "docker"], "Restarting Docker for the classic image store");
607
+ return `runsc registered, live-restore on, and the classic image store in use${kept}.`;
608
+ }
609
+ }
582
610
  must("systemctl", ["reload", "docker"], "Reloading Docker");
583
- return `runsc registered and live-restore on${backup ? `; the old file is at ${backup}` : ""}.`;
611
+ return merged.restart ? `runsc registered and live-restore on. The classic image store needs Docker restarted, and containers are running: run provision again with --upgrade-host, which lets the jobs finish first${kept}.` : `runsc registered and live-restore on${kept}.`;
584
612
  }
585
613
  case "network": {
586
614
  if (step.action === "check") {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@kilogent/runner",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@kilogent/runner",
9
- "version": "0.1.8",
9
+ "version": "0.1.10",
10
10
  "dependencies": {
11
11
  "@clack/prompts": "^1.7.0",
12
12
  "commander": "^15.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kilogent/runner",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "Kilogent's internal server runner — leases the agent jobs Kilogent's scheduler places on this server and runs each as a sandboxed headless agent session. Not for customer installation.",
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.",