@tablation/crew 0.112.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 +117 -20
- 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",
|
|
@@ -11784,7 +11786,13 @@ function syncAllPassengerCheckouts(cfg) {
|
|
|
11784
11786
|
|
|
11785
11787
|
// src/sandbox-image.ts
|
|
11786
11788
|
var SANDBOX_BASE_IMAGE = "nvcr.io/nvidia/base/ubuntu:24.04";
|
|
11787
|
-
var
|
|
11789
|
+
var SANDBOX_OPENSHELL_VERSION = "0.1.6";
|
|
11790
|
+
var SANDBOX_CLAUDE_VERSION = "2.1.309";
|
|
11791
|
+
var SANDBOX_CLAUDE_DIST = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases";
|
|
11792
|
+
var SANDBOX_CLAUDE_SHA256 = {
|
|
11793
|
+
x86_64: { platform: "linux-x64", sha256: "4d704a8aecbe038affa3000f498ae17c1b4f753add8facb8764120affc99b658" },
|
|
11794
|
+
aarch64: { platform: "linux-arm64", sha256: "9796dd26899337f687739a0b39a7353b639f062a3436a7b941fcf19a1b757a9b" }
|
|
11795
|
+
};
|
|
11788
11796
|
var SANDBOX_UID = 1e3;
|
|
11789
11797
|
var CREW_PREFIX = "/opt/crew";
|
|
11790
11798
|
var SANDBOX_RETRY_AFTER_MS = 60 * 60 * 1e3;
|
|
@@ -11808,15 +11816,28 @@ var CREW_ENV = {
|
|
|
11808
11816
|
XDG_CACHE_HOME: `${CREW_PREFIX}/cache`,
|
|
11809
11817
|
npm_config_cache: `${CREW_PREFIX}/cache/npm`,
|
|
11810
11818
|
npm_config_store_dir: `${CREW_PREFIX}/pnpm-store`,
|
|
11811
|
-
PNPM_HOME: `${CREW_PREFIX}/pnpm
|
|
11819
|
+
PNPM_HOME: `${CREW_PREFIX}/pnpm`,
|
|
11820
|
+
// A run cannot reach the download host, so an in-run update attempt is only noise.
|
|
11821
|
+
DISABLE_AUTOUPDATER: "1"
|
|
11812
11822
|
};
|
|
11823
|
+
function claudeInstallCommand() {
|
|
11824
|
+
const cases = Object.entries(SANDBOX_CLAUDE_SHA256).map(([arch, { platform: platform2, sha256: sha2562 }]) => `${arch}) p=${platform2}; sum=${sha2562};;`).join(" ");
|
|
11825
|
+
return [
|
|
11826
|
+
`case "$(uname -m)" in ${cases} *) echo "no pinned Claude Code binary for $(uname -m)" >&2; exit 1;; esac`,
|
|
11827
|
+
`mkdir -p ${CREW_PREFIX}/bin`,
|
|
11828
|
+
`curl -fsSL --retry 3 -o ${CREW_PREFIX}/bin/claude "${SANDBOX_CLAUDE_DIST}/${SANDBOX_CLAUDE_VERSION}/$p/claude"`,
|
|
11829
|
+
`echo "$sum ${CREW_PREFIX}/bin/claude" | sha256sum -c -`,
|
|
11830
|
+
`chmod 0755 ${CREW_PREFIX}/bin/claude`,
|
|
11831
|
+
`${CREW_PREFIX}/bin/claude --version | grep -F "${SANDBOX_CLAUDE_VERSION}"`
|
|
11832
|
+
].join("; ");
|
|
11833
|
+
}
|
|
11813
11834
|
function baseLayer() {
|
|
11814
11835
|
const dockerfile = [
|
|
11815
11836
|
`FROM ${SANDBOX_BASE_IMAGE}`,
|
|
11816
|
-
`LABEL io.crew.sandbox.layer="base" io.crew.sandbox.
|
|
11837
|
+
`LABEL io.crew.sandbox.layer="base" io.crew.sandbox.openshell="${SANDBOX_OPENSHELL_VERSION}"`,
|
|
11817
11838
|
""
|
|
11818
11839
|
].join("\n");
|
|
11819
|
-
return { name: "base", tag: `crew-sandbox-base:${hash({ SANDBOX_BASE_IMAGE,
|
|
11840
|
+
return { name: "base", tag: `crew-sandbox-base:${hash({ SANDBOX_BASE_IMAGE, SANDBOX_OPENSHELL_VERSION })}`, dockerfile, files: {} };
|
|
11820
11841
|
}
|
|
11821
11842
|
function crewLayer(base) {
|
|
11822
11843
|
const files = { "credential-helper": CREDENTIAL_HELPER, "mcp.json": MCP_CONFIG };
|
|
@@ -11827,10 +11848,11 @@ function crewLayer(base) {
|
|
|
11827
11848
|
run2("apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git && rm -rf /var/lib/apt/lists/*"),
|
|
11828
11849
|
`COPY credential-helper ${CREW_PREFIX}/bin/credential-helper`,
|
|
11829
11850
|
`COPY mcp.json ${CREW_PREFIX}/mcp/mcp.json`,
|
|
11851
|
+
run2(claudeInstallCommand()),
|
|
11830
11852
|
run2(`chmod 0755 ${CREW_PREFIX}/bin/credential-helper && git config --system credential.helper ${CREW_PREFIX}/bin/credential-helper`),
|
|
11831
11853
|
run2(`mkdir -p ${CREW_PREFIX}/cache ${CREW_PREFIX}/pnpm-store ${CREW_PREFIX}/pnpm /sandbox && chown -R ${SANDBOX_UID}:${SANDBOX_UID} ${CREW_PREFIX} /sandbox`),
|
|
11832
11854
|
`ENV ${env} PATH=${CREW_PREFIX}/pnpm:${CREW_PREFIX}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`,
|
|
11833
|
-
`LABEL io.crew.sandbox.layer="crew"`,
|
|
11855
|
+
`LABEL io.crew.sandbox.layer="crew" io.crew.sandbox.claude="${SANDBOX_CLAUDE_VERSION}"`,
|
|
11834
11856
|
""
|
|
11835
11857
|
].join("\n");
|
|
11836
11858
|
return { name: "crew", tag: `crew-sandbox-crew:${hash({ base: base.tag, dockerfile, files })}`, dockerfile, files };
|
|
@@ -11891,7 +11913,7 @@ function planSandbox(repo, decl, warm = {}) {
|
|
|
11891
11913
|
const base = baseLayer();
|
|
11892
11914
|
const crew = crewLayer(base);
|
|
11893
11915
|
const layer = repoLayer(repo, decl, crew, warm);
|
|
11894
|
-
return { repo, tag: layer.tag, layers: [base, crew, layer] };
|
|
11916
|
+
return { repo, tag: layer.tag, claude: SANDBOX_CLAUDE_VERSION, layers: [base, crew, layer] };
|
|
11895
11917
|
}
|
|
11896
11918
|
var sandboxStatePath = (stateDir) => join26(stateDir, "sandbox-images.json");
|
|
11897
11919
|
function readSandboxState(stateDir) {
|
|
@@ -11916,8 +11938,8 @@ function sandboxImageStatus(state, plan) {
|
|
|
11916
11938
|
return { status: "failed", detail: `last build of ${plan.tag} failed at ${s.failure.at}; log ${s.failure.logPath}${current ? `; running ${current.tag}` : ""}` };
|
|
11917
11939
|
}
|
|
11918
11940
|
if (!current) return { status: "missing", detail: `no image built yet (wants ${plan.tag}); run \`crew sandbox build\`` };
|
|
11919
|
-
if (current.tag !== plan.tag) return { status: "stale", detail: `running ${current.tag}, declaration now builds ${plan.tag}` };
|
|
11920
|
-
return { status: "ok", detail: `${current.tag} built ${current.builtAt}` };
|
|
11941
|
+
if (current.tag !== plan.tag) return { status: "stale", detail: `running ${current.tag} (claude ${current.claude ?? "unknown"}), declaration now builds ${plan.tag} (claude ${plan.claude})` };
|
|
11942
|
+
return { status: "ok", detail: `${current.tag} built ${current.builtAt}, claude ${current.claude ?? "unknown"}` };
|
|
11921
11943
|
}
|
|
11922
11944
|
var spawnBuildRunner = (engine = "docker") => (args, logPath) => new Promise((resolve7) => {
|
|
11923
11945
|
const child = spawn4(engine, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -11980,7 +12002,7 @@ async function buildSandboxImage(plan, deps) {
|
|
|
11980
12002
|
rmSync13(ctx, { recursive: true, force: true });
|
|
11981
12003
|
}
|
|
11982
12004
|
}
|
|
11983
|
-
const tags = [{ tag: plan.tag, builtAt: now().toISOString() }, ...entry.tags.filter((t) => t.tag !== plan.tag)];
|
|
12005
|
+
const tags = [{ tag: plan.tag, builtAt: now().toISOString(), claude: plan.claude }, ...entry.tags.filter((t) => t.tag !== plan.tag)];
|
|
11984
12006
|
const dropped = tags.slice(KEEP_TAGS);
|
|
11985
12007
|
state[plan.repo] = { tags: tags.slice(0, KEEP_TAGS) };
|
|
11986
12008
|
writeSandboxState(deps.stateDir, state);
|
|
@@ -12144,6 +12166,17 @@ function roleCapWarnings(ship) {
|
|
|
12144
12166
|
if (!ship.maxConcurrentAgentsSet) return [];
|
|
12145
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`);
|
|
12146
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
|
+
}
|
|
12147
12180
|
|
|
12148
12181
|
// src/selftest.ts
|
|
12149
12182
|
import { spawn as spawn5 } from "child_process";
|
|
@@ -13228,7 +13261,7 @@ function matchShipRows(ships, shipName2, machineId) {
|
|
|
13228
13261
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
13229
13262
|
import { existsSync as existsSync28, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
|
|
13230
13263
|
import { hostname as hostname2 } from "os";
|
|
13231
|
-
import { parseDocument as parseDocument3 } from "yaml";
|
|
13264
|
+
import { parseDocument as parseDocument3, isMap as isMap2, isScalar } from "yaml";
|
|
13232
13265
|
|
|
13233
13266
|
// src/doctor-fix.ts
|
|
13234
13267
|
import { parseDocument as parseDocument2 } from "yaml";
|
|
@@ -13664,6 +13697,15 @@ async function runProvision(o, deps, write, human) {
|
|
|
13664
13697
|
emit("connect", `set ship.${key}`, { setting: key });
|
|
13665
13698
|
}
|
|
13666
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
|
+
}
|
|
13667
13709
|
for (const host of o.forgeHosts) {
|
|
13668
13710
|
const token = o.tokens[host];
|
|
13669
13711
|
const stored = deps.storedToken(host);
|
|
@@ -13707,6 +13749,38 @@ async function runProvision(o, deps, write, human) {
|
|
|
13707
13749
|
emit("done", summary.state, { summary });
|
|
13708
13750
|
return { code: PROVISION_EXIT.ok, summary };
|
|
13709
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
|
+
}
|
|
13710
13784
|
function envKey(host) {
|
|
13711
13785
|
return host.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
13712
13786
|
}
|
|
@@ -13758,6 +13832,7 @@ function provisionOptionsFrom(argv2, env) {
|
|
|
13758
13832
|
relayHost: one("relay-host"),
|
|
13759
13833
|
maxConcurrentAgents: Number.isInteger(Number(one("max-concurrent-agents"))) && Number(one("max-concurrent-agents")) > 0 ? Number(one("max-concurrent-agents")) : void 0,
|
|
13760
13834
|
agentBin: one("agent-bin"),
|
|
13835
|
+
runner: one("runner") === "host" || one("runner") === "sandbox" ? one("runner") : void 0,
|
|
13761
13836
|
extraPath: one("extra-path"),
|
|
13762
13837
|
baseUrl: one("base-url"),
|
|
13763
13838
|
forgeHosts,
|
|
@@ -13842,6 +13917,14 @@ function realProvisionDeps(crewHome) {
|
|
|
13842
13917
|
writeFileSync21(file, doc.toString());
|
|
13843
13918
|
return true;
|
|
13844
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
|
+
},
|
|
13845
13928
|
storedToken(host) {
|
|
13846
13929
|
const res = spawnCrew(["credential", "get"], { input: `protocol=https
|
|
13847
13930
|
host=${host}
|
|
@@ -19351,7 +19434,7 @@ function renderRepoCheck(r) {
|
|
|
19351
19434
|
}
|
|
19352
19435
|
|
|
19353
19436
|
// src/repos-hooks.ts
|
|
19354
|
-
import { isMap as
|
|
19437
|
+
import { isMap as isMap3, parseDocument as parseDocument6, YAMLMap } from "yaml";
|
|
19355
19438
|
function packageManager(f) {
|
|
19356
19439
|
if (f.exists("pnpm-lock.yaml")) return "pnpm";
|
|
19357
19440
|
if (f.exists("yarn.lock")) return "yarn";
|
|
@@ -19497,9 +19580,9 @@ function planRouteHooks(text2, route2, name, hooks, opts = {}) {
|
|
|
19497
19580
|
const m = routeMapOf(doc, route2);
|
|
19498
19581
|
const repos = m.get("repos", true);
|
|
19499
19582
|
let target = m;
|
|
19500
|
-
if (
|
|
19583
|
+
if (isMap3(repos)) {
|
|
19501
19584
|
const entry = repos.get(name, true);
|
|
19502
|
-
if (
|
|
19585
|
+
if (isMap3(entry)) target = entry;
|
|
19503
19586
|
else {
|
|
19504
19587
|
const created = new YAMLMap();
|
|
19505
19588
|
created.set("dir", String(repos.get(name)));
|
|
@@ -19509,7 +19592,7 @@ function planRouteHooks(text2, route2, name, hooks, opts = {}) {
|
|
|
19509
19592
|
}
|
|
19510
19593
|
const current = target.get("hooks", true);
|
|
19511
19594
|
let hooksMap;
|
|
19512
|
-
if (
|
|
19595
|
+
if (isMap3(current)) hooksMap = current;
|
|
19513
19596
|
else {
|
|
19514
19597
|
hooksMap = new YAMLMap();
|
|
19515
19598
|
target.set("hooks", hooksMap);
|
|
@@ -19534,13 +19617,13 @@ function clearRouteHooks(text2, route2, name) {
|
|
|
19534
19617
|
const m = routeMapOf(doc, route2);
|
|
19535
19618
|
const repos = m.get("repos", true);
|
|
19536
19619
|
let target = m;
|
|
19537
|
-
if (
|
|
19620
|
+
if (isMap3(repos)) {
|
|
19538
19621
|
const entry = repos.get(name, true);
|
|
19539
|
-
if (!
|
|
19622
|
+
if (!isMap3(entry)) return { text: text2, removed: [] };
|
|
19540
19623
|
target = entry;
|
|
19541
19624
|
}
|
|
19542
19625
|
const current = target.get("hooks", true);
|
|
19543
|
-
if (!
|
|
19626
|
+
if (!isMap3(current)) return { text: text2, removed: [] };
|
|
19544
19627
|
const removed = current.items.map((i) => String(i.key.value ?? i.key));
|
|
19545
19628
|
target.delete("hooks");
|
|
19546
19629
|
return { text: String(doc), removed };
|
|
@@ -23861,6 +23944,15 @@ if (command === "passenger-sync-daemon") {
|
|
|
23861
23944
|
}
|
|
23862
23945
|
return { problems, readiness };
|
|
23863
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
|
+
}
|
|
23864
23956
|
async function doctorFix(o) {
|
|
23865
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))));
|
|
23866
23958
|
const unitExists = (p) => existsSync45(p);
|
|
@@ -26307,7 +26399,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
26307
26399
|
}
|
|
26308
26400
|
let apiKeyFile;
|
|
26309
26401
|
const apiKeyVar = "CREW_API_KEY";
|
|
26310
|
-
if (firstRunFromFlags && agentBinSearched && !dryRun) {
|
|
26402
|
+
if (firstRunFromFlags && agentBinSearched && !dryRun && !isManagedShipKind(value("ship-kind"))) {
|
|
26311
26403
|
const msg = `no agent binary: "claude" was not found on PATH or in ${agentBinSearched.join(", ")} \u2014 pass --agent-bin /absolute/path`;
|
|
26312
26404
|
process.stderr.write(`crew connect: ${msg}
|
|
26313
26405
|
`);
|
|
@@ -26683,7 +26775,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
|
|
|
26683
26775
|
`);
|
|
26684
26776
|
for (const t of r.tags) {
|
|
26685
26777
|
const ageH = Math.max(0, Math.round((Date.now() - Date.parse(t.builtAt)) / 36e5));
|
|
26686
|
-
process.stdout.write(` ${t.tag} built ${t.builtAt} (${ageH}h ago)
|
|
26778
|
+
process.stdout.write(` ${t.tag} built ${t.builtAt} (${ageH}h ago), claude ${t.claude ?? "unknown"}
|
|
26687
26779
|
`);
|
|
26688
26780
|
}
|
|
26689
26781
|
}
|
|
@@ -28214,6 +28306,9 @@ watermark: ${state.watermark()}
|
|
|
28214
28306
|
}
|
|
28215
28307
|
}
|
|
28216
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
|
+
}
|
|
28217
28312
|
const previewProblem2 = await previewHostProblem(cfg);
|
|
28218
28313
|
if (previewProblem2) problems.push(previewHostFinding(previewProblem2));
|
|
28219
28314
|
if (cfg.routes.some((x) => x.route === route2.route && x.enabled && x.hostPeriscopes)) {
|
|
@@ -28452,6 +28547,8 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
|
|
|
28452
28547
|
crew manifest: ${seats2.length ? seats2.map((c) => c.name).join(", ") : "none"}
|
|
28453
28548
|
`
|
|
28454
28549
|
);
|
|
28550
|
+
for (const w of managedRuntimeWarnings(row.kind, cfg.ship)) process.stdout.write(`managed runtime: WARN ${w}
|
|
28551
|
+
`);
|
|
28455
28552
|
}
|
|
28456
28553
|
}
|
|
28457
28554
|
{
|
package/package.json
CHANGED