@tablation/crew 0.127.2 → 0.127.3

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 +27 -6
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -6215,7 +6215,8 @@ async function raiseShipAttention(o, item) {
6215
6215
  const previous = store.previous();
6216
6216
  const next = upsert(previous, item);
6217
6217
  store.persist(next);
6218
- if (transitions(previous, next).length === 0) return false;
6218
+ const changed2 = item.kind === "sandbox_cache" && previous.some((i) => i.key === item.key && i.message !== item.message);
6219
+ if (transitions(previous, next).length === 0 && !changed2) return false;
6219
6220
  announce(o.emit, item);
6220
6221
  if (o.route && o.ship) {
6221
6222
  await notify(o.route, o.ship, { level: "warn", headline: item.message }, o.emit);
@@ -12704,7 +12705,7 @@ var SandboxCache = class {
12704
12705
  try {
12705
12706
  await this.helper(this.s.helperImage, REFRESH_SCRIPT, [mirrorRelPath(r), forgeDescriptorFor(r.host).httpsUrl(r.host, r.path)], env);
12706
12707
  } catch (e) {
12707
- out.push({ repo: r, ok: false, detail: describe(e) });
12708
+ out.push({ repo: r, ok: false, detail: r.token ? describe(e) : `no readable forge token for ${r.host} (see \`crew forge list\`); ${describe(e)}` });
12708
12709
  continue;
12709
12710
  }
12710
12711
  if (this.s.depsCommand && this.s.depsImage) {
@@ -12808,6 +12809,10 @@ function cacheSettingsOf(cfg) {
12808
12809
  };
12809
12810
  }
12810
12811
  var sandboxCacheKey = (volume, r) => `sandbox_cache:${volume}:${r.host}/${r.path}`;
12812
+ function unmirroredRepos(served, mirrors) {
12813
+ const have = new Set(mirrors.map((m) => `${m.repo.host}/${m.repo.path}`));
12814
+ return served.map((r) => `${r.host}/${r.path}`).filter((k, i, a) => !have.has(k) && a.indexOf(k) === i);
12815
+ }
12811
12816
  var CACHE_REFRESH_INTERVAL_MS = 6e4;
12812
12817
  function makeCachePass(o) {
12813
12818
  const now = o.now ?? Date.now;
@@ -12830,7 +12835,7 @@ function makeCachePass(o) {
12830
12835
  for (const out of all) {
12831
12836
  const key = sandboxCacheKey(o.volume, out.repo);
12832
12837
  if (out.ok) o.ok(key);
12833
- else await o.fail(key, `sandbox cache: ${out.repo.host}/${out.repo.path} did not refresh (${out.detail}); runs use the previous mirror. Resumes automatically when a later pass refreshes it`);
12838
+ else await o.fail(key, `sandbox cache: ${out.repo.host}/${out.repo.path} did not refresh (${out.detail}); runs use the previous mirror. Resumes automatically when a later pass refreshes it`, new Date(now()).toISOString());
12834
12839
  }
12835
12840
  return all;
12836
12841
  };
@@ -19336,6 +19341,7 @@ function runForge(a, io) {
19336
19341
  const tok = sourceFromArgs(a);
19337
19342
  if (typeof tok === "string") return fail2(tok);
19338
19343
  const doc = parseDocument4(io.readFile(io.configFile));
19344
+ doc.setIn(["ship", "forges", host, "username"], forgeDescriptorFor(host).credentialUsername);
19339
19345
  doc.setIn(["ship", "forges", host, "token"], tok);
19340
19346
  io.writeFile(io.configFile, doc.toString());
19341
19347
  io.forges = { ...io.forges ?? {}, [host]: { username: forgeDescriptorFor(host).credentialUsername, token: tok } };
@@ -25540,7 +25546,7 @@ if (command === "passenger-sync-daemon") {
25540
25546
  if (intelFlavor(loadRepoConfig(t.dir)?.hooks.intel) === "serena") intelImage = sandboxImageFor(images ??= readSandboxState(ship.stateDir), t.name);
25541
25547
  } catch {
25542
25548
  }
25543
- out.push({ ...repo, dir: t.dir, token, username: forgeFor(ship.forges, repo.host)?.entry.username, intelImage });
25549
+ out.push({ ...repo, dir: t.dir, token, username: forgeFor(ship.forges, repo.host)?.entry.username || forgeDescriptorFor(repo.host).credentialUsername, intelImage });
25544
25550
  }
25545
25551
  return out;
25546
25552
  }, buildSandboxCachePass = function(c, ship, state2, emit2) {
@@ -25551,7 +25557,7 @@ if (command === "passenger-sync-daemon") {
25551
25557
  volume: settings.volume,
25552
25558
  repos: () => sandboxCacheRepos(c, ship),
25553
25559
  lock: (dir) => acquireCheckoutLock(dir),
25554
- fail: (key, message) => raiseShipAttention({ state: state2, emit: emit2, route: c, ship }, { kind: "sandbox_cache", key, message, since: (/* @__PURE__ */ new Date()).toISOString() }).then(() => void 0),
25560
+ fail: (key, message, failedAt) => raiseShipAttention({ state: state2, emit: emit2, route: c, ship }, { kind: "sandbox_cache", key, message, since: failedAt, lastFailedAt: failedAt }).then(() => void 0),
25555
25561
  ok: (key) => clearShipAttention(state2, key)
25556
25562
  });
25557
25563
  return async () => {
@@ -28963,8 +28969,13 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
28963
28969
  }
28964
28970
  const dropped = flag("prune") ? await cache.prune(served) : [];
28965
28971
  const mirrors = await cache.list();
28972
+ const open = openShipAttention(new State(cfg.ship.stateDir));
28973
+ const failures = served.flatMap((r) => {
28974
+ const item = open.find((i) => i.kind === "sandbox_cache" && i.key === sandboxCacheKey(settings.volume, r));
28975
+ return item ? [{ repo: `${r.host}/${r.path}`, lastFailedAt: item.lastFailedAt ?? item.since, message: item.message }] : [];
28976
+ });
28966
28977
  if (flag("json")) {
28967
- process.stdout.write(`${JSON.stringify({ volume: settings.volume, mirrors, dropped }, null, 2)}
28978
+ process.stdout.write(`${JSON.stringify({ volume: settings.volume, mirrors, failures, dropped }, null, 2)}
28968
28979
  `);
28969
28980
  } else {
28970
28981
  for (const d of dropped) process.stdout.write(`dropped ${d.host}/${d.path}
@@ -28975,6 +28986,8 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
28975
28986
  process.stdout.write(`${m.repo.host}/${m.repo.path} last refresh ${m.lastRefresh ?? "never"}${m.intel ? ` intel ${m.intel.commit.slice(0, 12)} (${m.intel.indexedAt ?? "age unknown"})` : ""}
28976
28987
  `);
28977
28988
  }
28989
+ for (const f of failures) process.stdout.write(`${f.repo} REFRESH FAILING (last failed ${f.lastFailedAt}): ${f.message}
28990
+ `);
28978
28991
  }
28979
28992
  } catch (e) {
28980
28993
  process.stderr.write(`crew sandbox cache: ${e instanceof Error ? e.message : String(e)}
@@ -30524,6 +30537,14 @@ watermark: ${state.watermark()}
30524
30537
  for (const message of managedRuntimeWarnings(shipKind, cfg.ship)) problems.push({ severity: "attention", kind: "managed_runtime_default", message });
30525
30538
  for (const message of managedGitIdentityWarnings(shipKind, readGlobalGitIdentity())) problems.push({ severity: "attention", kind: "managed_git_identity", message });
30526
30539
  }
30540
+ const cacheSettings = cfg.ship.runner === "sandbox" ? cacheSettingsOf(cfg.ship.sandbox) : null;
30541
+ if (cacheSettings && !flag("offline")) {
30542
+ try {
30543
+ const missing = unmirroredRepos(sandboxCacheRepos(route2, cfg.ship), await new SandboxCache(cacheSettings).list());
30544
+ for (const r of missing) problems.push({ severity: "attention", kind: "sandbox_cache_unmirrored", route: route2.route, message: `${r} has no mirror in the cache volume ${cacheSettings.volume}, so sandboxed runs cannot clone it`, remedy: "see `crew sandbox cache` for the last refresh failure" });
30545
+ } catch {
30546
+ }
30547
+ }
30527
30548
  for (const t of rejectedTunnels(cfg.ship.stateDir)) {
30528
30549
  problems.push({ severity: "attention", kind: TUNNEL_REJECTED_KEY, message: tunnelRejectedMessage(t.workspaceId, t.quickExits), remedy: "rotate the slug with `crew rotate-passenger-url`" });
30529
30550
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.127.2",
3
+ "version": "0.127.3",
4
4
  "description": "A standing team of headless agents that picks work off a Tablation board, does it on a machine you control, and reports back.",
5
5
  "type": "module",
6
6
  "license": "MIT",