@tablation/crew 0.113.0 → 0.114.0
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 +87 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3030,7 +3030,9 @@ var SHIP_KEYS = /* @__PURE__ */ new Set([
|
|
|
3030
3030
|
"maxPeriscopes",
|
|
3031
3031
|
"periscopeIdleMinutes",
|
|
3032
3032
|
"secretStore",
|
|
3033
|
-
"env"
|
|
3033
|
+
"env",
|
|
3034
|
+
"runner",
|
|
3035
|
+
"sandbox"
|
|
3034
3036
|
]);
|
|
3035
3037
|
var ROUTE_KEYS = /* @__PURE__ */ new Set([
|
|
3036
3038
|
"route",
|
|
@@ -12164,6 +12166,17 @@ function roleCapWarnings(ship) {
|
|
|
12164
12166
|
if (!ship.maxConcurrentAgentsSet) return [];
|
|
12165
12167
|
return Object.entries(ship.roleConcurrency).filter(([, n]) => (n ?? 0) > ship.maxConcurrentAgents).map(([role, n]) => `ship.roleConcurrency.${role} is ${n}, above ship.maxConcurrentAgents (${ship.maxConcurrentAgents}); the ship-wide cap wins`);
|
|
12166
12168
|
}
|
|
12169
|
+
function managedRuntimeWarnings(kind, ship) {
|
|
12170
|
+
if (kind !== "managed_instance" && kind !== "pooled_instance" && kind !== "pooled") return [];
|
|
12171
|
+
const out = [];
|
|
12172
|
+
const explicit = ship.toolchains ?? [];
|
|
12173
|
+
const effectiveToolchains = explicit.some((t) => t.name === "claude") ? explicit : [{ name: "claude", harness: "claude" }, ...explicit];
|
|
12174
|
+
if ((ship.runner ?? "host") !== "sandbox") out.push(`ship.runner is "${ship.runner ?? "host"}" on a ${kind} ship; a managed ship should run agents in the sandbox (set ship.runner: sandbox)`);
|
|
12175
|
+
for (const t of effectiveToolchains) {
|
|
12176
|
+
if (t.harness === "claude" && t.auth !== "workspace") out.push(`ship.toolchains.${t.name}.auth is "${t.auth ?? "inherit"}" on a ${kind} ship; a managed ship reaches a model only through the workspace endpoint (set auth: workspace)`);
|
|
12177
|
+
}
|
|
12178
|
+
return out;
|
|
12179
|
+
}
|
|
12167
12180
|
|
|
12168
12181
|
// src/selftest.ts
|
|
12169
12182
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -13248,7 +13261,7 @@ function matchShipRows(ships, shipName2, machineId) {
|
|
|
13248
13261
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
13249
13262
|
import { existsSync as existsSync28, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
|
|
13250
13263
|
import { hostname as hostname2 } from "os";
|
|
13251
|
-
import { parseDocument as parseDocument3 } from "yaml";
|
|
13264
|
+
import { parseDocument as parseDocument3, isMap as isMap2, isScalar } from "yaml";
|
|
13252
13265
|
|
|
13253
13266
|
// src/doctor-fix.ts
|
|
13254
13267
|
import { parseDocument as parseDocument2 } from "yaml";
|
|
@@ -13684,6 +13697,15 @@ async function runProvision(o, deps, write, human) {
|
|
|
13684
13697
|
emit("connect", `set ship.${key}`, { setting: key });
|
|
13685
13698
|
}
|
|
13686
13699
|
}
|
|
13700
|
+
if (o.runner === "host") {
|
|
13701
|
+
emit("connect", "runner: host chosen explicitly (--runner host); not applying the managed sandbox defaults", { setting: "ship.runner", value: "host" });
|
|
13702
|
+
if (deps.setShipSetting("runner", "host")) summary.changed = true;
|
|
13703
|
+
} else if (o.runner === "sandbox" || isManagedShipKind(o.shipKind)) {
|
|
13704
|
+
for (const key of deps.applyManagedDefaults()) {
|
|
13705
|
+
summary.changed = true;
|
|
13706
|
+
emit("connect", `set ${key}`, { setting: key });
|
|
13707
|
+
}
|
|
13708
|
+
}
|
|
13687
13709
|
for (const host of o.forgeHosts) {
|
|
13688
13710
|
const token = o.tokens[host];
|
|
13689
13711
|
const stored = deps.storedToken(host);
|
|
@@ -13727,6 +13749,38 @@ async function runProvision(o, deps, write, human) {
|
|
|
13727
13749
|
emit("done", summary.state, { summary });
|
|
13728
13750
|
return { code: PROVISION_EXIT.ok, summary };
|
|
13729
13751
|
}
|
|
13752
|
+
function isManagedShipKind(kind) {
|
|
13753
|
+
return kind === "managed_instance" || kind === "pooled_instance" || kind === "pooled";
|
|
13754
|
+
}
|
|
13755
|
+
var MANAGED_CACHE_VOLUME = "crew-cache";
|
|
13756
|
+
function applyManagedDefaultsToDoc(doc) {
|
|
13757
|
+
const wrote = [];
|
|
13758
|
+
if (doc.getIn(["ship", "runner"]) === void 0) {
|
|
13759
|
+
doc.setIn(["ship", "runner"], "sandbox");
|
|
13760
|
+
wrote.push("ship.runner");
|
|
13761
|
+
}
|
|
13762
|
+
if (doc.getIn(["ship", "sandbox", "cacheVolume"]) === void 0) {
|
|
13763
|
+
doc.setIn(["ship", "sandbox", "cacheVolume"], MANAGED_CACHE_VOLUME);
|
|
13764
|
+
wrote.push("ship.sandbox.cacheVolume");
|
|
13765
|
+
}
|
|
13766
|
+
const existing = doc.getIn(["ship", "toolchains"]);
|
|
13767
|
+
const hasClaude = isMap2(existing) && existing.items.some((i) => (isScalar(i.key) ? i.key.value : i.key) === "claude");
|
|
13768
|
+
if (!hasClaude) {
|
|
13769
|
+
doc.setIn(["ship", "toolchains", "claude", "harness"], "claude");
|
|
13770
|
+
for (const k of ["bin", "model", "maxThinkingTokens"]) {
|
|
13771
|
+
const v = doc.getIn(["ship", "agent", k]);
|
|
13772
|
+
if (v !== void 0) doc.setIn(["ship", "toolchains", "claude", k], v);
|
|
13773
|
+
}
|
|
13774
|
+
}
|
|
13775
|
+
const toolchains = doc.getIn(["ship", "toolchains"]);
|
|
13776
|
+
for (const name of isMap2(toolchains) ? toolchains.items.map((i) => String(isScalar(i.key) ? i.key.value : i.key)) : []) {
|
|
13777
|
+
if (doc.getIn(["ship", "toolchains", name, "harness"]) !== "claude") continue;
|
|
13778
|
+
if (doc.getIn(["ship", "toolchains", name, "auth"]) !== void 0) continue;
|
|
13779
|
+
doc.setIn(["ship", "toolchains", name, "auth"], "workspace");
|
|
13780
|
+
wrote.push(`ship.toolchains.${name}.auth`);
|
|
13781
|
+
}
|
|
13782
|
+
return wrote;
|
|
13783
|
+
}
|
|
13730
13784
|
function envKey(host) {
|
|
13731
13785
|
return host.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
13732
13786
|
}
|
|
@@ -13778,6 +13832,7 @@ function provisionOptionsFrom(argv2, env) {
|
|
|
13778
13832
|
relayHost: one("relay-host"),
|
|
13779
13833
|
maxConcurrentAgents: Number.isInteger(Number(one("max-concurrent-agents"))) && Number(one("max-concurrent-agents")) > 0 ? Number(one("max-concurrent-agents")) : void 0,
|
|
13780
13834
|
agentBin: one("agent-bin"),
|
|
13835
|
+
runner: one("runner") === "host" || one("runner") === "sandbox" ? one("runner") : void 0,
|
|
13781
13836
|
extraPath: one("extra-path"),
|
|
13782
13837
|
baseUrl: one("base-url"),
|
|
13783
13838
|
forgeHosts,
|
|
@@ -13862,6 +13917,14 @@ function realProvisionDeps(crewHome) {
|
|
|
13862
13917
|
writeFileSync21(file, doc.toString());
|
|
13863
13918
|
return true;
|
|
13864
13919
|
},
|
|
13920
|
+
applyManagedDefaults() {
|
|
13921
|
+
const file = configFile();
|
|
13922
|
+
if (!file) return [];
|
|
13923
|
+
const doc = parseDocument3(readFileSync27(file, "utf8"));
|
|
13924
|
+
const wrote = applyManagedDefaultsToDoc(doc);
|
|
13925
|
+
if (wrote.length) writeFileSync21(file, doc.toString());
|
|
13926
|
+
return wrote;
|
|
13927
|
+
},
|
|
13865
13928
|
storedToken(host) {
|
|
13866
13929
|
const res = spawnCrew(["credential", "get"], { input: `protocol=https
|
|
13867
13930
|
host=${host}
|
|
@@ -19371,7 +19434,7 @@ function renderRepoCheck(r) {
|
|
|
19371
19434
|
}
|
|
19372
19435
|
|
|
19373
19436
|
// src/repos-hooks.ts
|
|
19374
|
-
import { isMap as
|
|
19437
|
+
import { isMap as isMap3, parseDocument as parseDocument6, YAMLMap } from "yaml";
|
|
19375
19438
|
function packageManager(f) {
|
|
19376
19439
|
if (f.exists("pnpm-lock.yaml")) return "pnpm";
|
|
19377
19440
|
if (f.exists("yarn.lock")) return "yarn";
|
|
@@ -19517,9 +19580,9 @@ function planRouteHooks(text2, route2, name, hooks, opts = {}) {
|
|
|
19517
19580
|
const m = routeMapOf(doc, route2);
|
|
19518
19581
|
const repos = m.get("repos", true);
|
|
19519
19582
|
let target = m;
|
|
19520
|
-
if (
|
|
19583
|
+
if (isMap3(repos)) {
|
|
19521
19584
|
const entry = repos.get(name, true);
|
|
19522
|
-
if (
|
|
19585
|
+
if (isMap3(entry)) target = entry;
|
|
19523
19586
|
else {
|
|
19524
19587
|
const created = new YAMLMap();
|
|
19525
19588
|
created.set("dir", String(repos.get(name)));
|
|
@@ -19529,7 +19592,7 @@ function planRouteHooks(text2, route2, name, hooks, opts = {}) {
|
|
|
19529
19592
|
}
|
|
19530
19593
|
const current = target.get("hooks", true);
|
|
19531
19594
|
let hooksMap;
|
|
19532
|
-
if (
|
|
19595
|
+
if (isMap3(current)) hooksMap = current;
|
|
19533
19596
|
else {
|
|
19534
19597
|
hooksMap = new YAMLMap();
|
|
19535
19598
|
target.set("hooks", hooksMap);
|
|
@@ -19554,13 +19617,13 @@ function clearRouteHooks(text2, route2, name) {
|
|
|
19554
19617
|
const m = routeMapOf(doc, route2);
|
|
19555
19618
|
const repos = m.get("repos", true);
|
|
19556
19619
|
let target = m;
|
|
19557
|
-
if (
|
|
19620
|
+
if (isMap3(repos)) {
|
|
19558
19621
|
const entry = repos.get(name, true);
|
|
19559
|
-
if (!
|
|
19622
|
+
if (!isMap3(entry)) return { text: text2, removed: [] };
|
|
19560
19623
|
target = entry;
|
|
19561
19624
|
}
|
|
19562
19625
|
const current = target.get("hooks", true);
|
|
19563
|
-
if (!
|
|
19626
|
+
if (!isMap3(current)) return { text: text2, removed: [] };
|
|
19564
19627
|
const removed = current.items.map((i) => String(i.key.value ?? i.key));
|
|
19565
19628
|
target.delete("hooks");
|
|
19566
19629
|
return { text: String(doc), removed };
|
|
@@ -23881,6 +23944,15 @@ if (command === "passenger-sync-daemon") {
|
|
|
23881
23944
|
}
|
|
23882
23945
|
return { problems, readiness };
|
|
23883
23946
|
}
|
|
23947
|
+
async function doctorShipKind(route3, ship) {
|
|
23948
|
+
try {
|
|
23949
|
+
const rows = await new Tracker(route3, ship).shipRows();
|
|
23950
|
+
const mine = matchShipRows(rows, ship.name, doctorMachineId(ship.stateDir)).rows;
|
|
23951
|
+
return mine.length === 1 ? mine[0].kind ?? null : null;
|
|
23952
|
+
} catch {
|
|
23953
|
+
return null;
|
|
23954
|
+
}
|
|
23955
|
+
}
|
|
23884
23956
|
async function doctorFix(o) {
|
|
23885
23957
|
const routes = await Promise.all(routesInScope(cfg.routes, named).map((c) => gatherHealth({ route: c.route, enabled: c.enabled, hasRepos: reposOf(c).length > 0 }, () => routeProblems(c))));
|
|
23886
23958
|
const unitExists = (p) => existsSync45(p);
|
|
@@ -26327,7 +26399,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
26327
26399
|
}
|
|
26328
26400
|
let apiKeyFile;
|
|
26329
26401
|
const apiKeyVar = "CREW_API_KEY";
|
|
26330
|
-
if (firstRunFromFlags && agentBinSearched && !dryRun) {
|
|
26402
|
+
if (firstRunFromFlags && agentBinSearched && !dryRun && !isManagedShipKind(value("ship-kind"))) {
|
|
26331
26403
|
const msg = `no agent binary: "claude" was not found on PATH or in ${agentBinSearched.join(", ")} \u2014 pass --agent-bin /absolute/path`;
|
|
26332
26404
|
process.stderr.write(`crew connect: ${msg}
|
|
26333
26405
|
`);
|
|
@@ -28234,6 +28306,9 @@ watermark: ${state.watermark()}
|
|
|
28234
28306
|
}
|
|
28235
28307
|
}
|
|
28236
28308
|
for (const message of roleCapWarnings(cfg.ship)) problems.push({ severity: "note", kind: "role_cap_above_ship_cap", message });
|
|
28309
|
+
if (!flag("offline")) {
|
|
28310
|
+
for (const message of managedRuntimeWarnings(await doctorShipKind(route2, cfg.ship), cfg.ship)) problems.push({ severity: "attention", kind: "managed_runtime_default", message });
|
|
28311
|
+
}
|
|
28237
28312
|
const previewProblem2 = await previewHostProblem(cfg);
|
|
28238
28313
|
if (previewProblem2) problems.push(previewHostFinding(previewProblem2));
|
|
28239
28314
|
if (cfg.routes.some((x) => x.route === route2.route && x.enabled && x.hostPeriscopes)) {
|
|
@@ -28472,6 +28547,8 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
|
|
|
28472
28547
|
crew manifest: ${seats2.length ? seats2.map((c) => c.name).join(", ") : "none"}
|
|
28473
28548
|
`
|
|
28474
28549
|
);
|
|
28550
|
+
for (const w of managedRuntimeWarnings(row.kind, cfg.ship)) process.stdout.write(`managed runtime: WARN ${w}
|
|
28551
|
+
`);
|
|
28475
28552
|
}
|
|
28476
28553
|
}
|
|
28477
28554
|
{
|
package/package.json
CHANGED