@tablation/crew 0.130.0 → 0.130.1

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 -3
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -7314,6 +7314,27 @@ async function revokeSeatKeys(route2, o) {
7314
7314
  }
7315
7315
  const host = hostFromUrl2(route2.baseUrl);
7316
7316
  const base = route2.baseUrl.replace(/\/+$/, "");
7317
+ const headers = { Authorization: `Bearer ${resolveApiKey(route2)}`, "User-Agent": o.userAgent ?? "Mozilla/5.0 TablationCrewAgent/1.0" };
7318
+ const sweepNamedKeys = async (role, agentId) => {
7319
+ const prefix = `crew ${o.shipName} `;
7320
+ try {
7321
+ const res = await doFetch(`${base}/api/workspaces/${resolved.workspaceId}/agents/${agentId}/api-keys`, { headers });
7322
+ if (!res.ok) return;
7323
+ const keys = await res.json();
7324
+ for (const k of Array.isArray(keys) ? keys : []) {
7325
+ if (!k.id || k.revokedAt || !k.name?.startsWith(prefix)) continue;
7326
+ if (o.dryRun) {
7327
+ out.push({ role, action: "revoked", detail: `dry run; key "${k.name}" found on the server` });
7328
+ continue;
7329
+ }
7330
+ const del2 = await doFetch(`${base}/api/workspaces/${resolved.workspaceId}/agents/${agentId}/api-keys/${k.id}`, { method: "DELETE", headers });
7331
+ if (del2.ok || del2.status === 404) out.push({ role, action: "revoked", detail: `key "${k.name}" found on the server, not in the keychain` });
7332
+ else out.push({ role, action: "failed", detail: `key "${k.name}": ${del2.status} ${del2.statusText}` });
7333
+ }
7334
+ } catch (e) {
7335
+ out.push({ role, action: "failed", detail: `could not sweep keys named for this ship (${e.message})` });
7336
+ }
7337
+ };
7317
7338
  for (const { role, agentId } of targets) {
7318
7339
  if (!agentId) {
7319
7340
  out.push({ role, action: "no_agent" });
@@ -7324,6 +7345,7 @@ async function revokeSeatKeys(route2, o) {
7324
7345
  const session = await store.get(host, slug2);
7325
7346
  if (!session?.apiKey) {
7326
7347
  out.push({ role, action: "not_stored" });
7348
+ if (o.shipName) await sweepNamedKeys(role, agentId);
7327
7349
  continue;
7328
7350
  }
7329
7351
  if (!session.keyId) {
@@ -7344,6 +7366,7 @@ async function revokeSeatKeys(route2, o) {
7344
7366
  }
7345
7367
  await store.clear(host, slug2);
7346
7368
  out.push({ role, action: "revoked", detail: del2.ok ? void 0 : "server already had no such key" });
7369
+ if (o.shipName) await sweepNamedKeys(role, agentId);
7347
7370
  } catch (e) {
7348
7371
  out.push({ role, action: "failed", detail: /Command failed|security|sk_|-w /i.test(e.message) ? describeStoreError(e) : e.message });
7349
7372
  }
@@ -12904,7 +12927,12 @@ function labeledDocker() {
12904
12927
  if (!dockerAvailable()) return { volumes: [], images: [] };
12905
12928
  return {
12906
12929
  volumes: lines(docker(["volume", "ls", "-q", "--filter", `label=${DOCKER_LABEL_OWNER}`, "--filter", `label=${DOCKER_LABEL_CACHE}`])),
12907
- images: lines(docker(["image", "ls", "-q", "--filter", `label=${DOCKER_LABEL_OWNER}`, "--filter", `label=${DOCKER_LABEL_REPO_LAYER}`]))
12930
+ // CREW-2984: the repository and ship layers are tagged `crew-sandbox/<name>:<hash>` but carry only an `io.crew.sandbox.*` label,
12931
+ // so the label filter alone missed them. The tag namespace is crew's own; the base and crew layers are `crew-sandbox-base`/`-crew`.
12932
+ images: [.../* @__PURE__ */ new Set([
12933
+ ...lines(docker(["image", "ls", "--format", "{{.Repository}}:{{.Tag}}", "--filter", "reference=crew-sandbox/*"])),
12934
+ ...lines(docker(["image", "ls", "-q", "--filter", `label=${DOCKER_LABEL_OWNER}`, "--filter", `label=${DOCKER_LABEL_REPO_LAYER}`]))
12935
+ ])]
12908
12936
  };
12909
12937
  }
12910
12938
  function realDeprovisionDeps(cfg, emit, crewHome, getStore) {
@@ -28212,7 +28240,7 @@ ${cu.tail.trimEnd()}
28212
28240
  }
28213
28241
  const { personaResult, skillResult } = run3;
28214
28242
  if (flag("revoke-seat-keys")) {
28215
- for (const o of await revokeSeatKeys(target, { userAgent: cfg.ship.userAgent, dryRun })) {
28243
+ for (const o of await revokeSeatKeys(target, { userAgent: cfg.ship.userAgent, dryRun, shipName: cfg.ship.name })) {
28216
28244
  process.stdout.write(`${describeRevokeOutcome(o)}
28217
28245
  `);
28218
28246
  }
@@ -30585,7 +30613,7 @@ ${where.join("\n")}`);
30585
30613
  },
30586
30614
  removePair: removePairEntries,
30587
30615
  async revokeSeatKeys(r, dry) {
30588
- const outcomes = await revokeSeatKeys(r, { userAgent: cfg.ship.userAgent, dryRun: dry });
30616
+ const outcomes = await revokeSeatKeys(r, { userAgent: cfg.ship.userAgent, dryRun: dry, shipName: cfg.ship.name });
30589
30617
  return outcomes.map((o) => ({ line: describeRevokeOutcome(o), ok: o.action !== "failed" }));
30590
30618
  },
30591
30619
  async credential(r) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tablation/crew",
3
- "version": "0.130.0",
3
+ "version": "0.130.1",
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",