@tablation/crew 0.126.7 → 0.126.9
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 +55 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14892,6 +14892,20 @@ async function runProvision(o, deps, write, human) {
|
|
|
14892
14892
|
emit("route_enabled", `enabled route ${route2}`, { route: route2 });
|
|
14893
14893
|
}
|
|
14894
14894
|
}
|
|
14895
|
+
summary.seatKeys = [];
|
|
14896
|
+
for (const route2 of routeNames) {
|
|
14897
|
+
const res = deps.crew(["agents", "sync", route2]);
|
|
14898
|
+
const lines2 = res.stdout.split("\n").map((l) => l.trim());
|
|
14899
|
+
const minted = lines2.flatMap((l) => /^(\w+): agent key minted/.exec(l)?.[1] ?? []);
|
|
14900
|
+
const refused = lines2.filter((l) => /could not mint an agent key|^seat keys: not minted/.test(l));
|
|
14901
|
+
summary.seatKeys.push({ route: route2, minted });
|
|
14902
|
+
if (minted.length > 0) summary.changed = true;
|
|
14903
|
+
emit("seat_keys", `seat keys: ${minted.length} minted${minted.length > 0 ? ` (${minted.join(", ")})` : ""} for ${route2}`, { route: route2, minted });
|
|
14904
|
+
if (res.status >= 2 || refused.length > 0) {
|
|
14905
|
+
const why = refused[0] ?? (res.stderr.trim().split("\n").pop() || `crew agents sync exited ${res.status}`);
|
|
14906
|
+
return fail2(PROVISION_EXIT.failed, `seat keys for ${route2}: ${why}`, { stage: "seat_keys", route: route2 });
|
|
14907
|
+
}
|
|
14908
|
+
}
|
|
14895
14909
|
const before = deps.installState();
|
|
14896
14910
|
if (before.unitsStale || !before.running || !before.lingering) {
|
|
14897
14911
|
const res = deps.crew(["install"]);
|
|
@@ -15222,13 +15236,30 @@ function isPidAlive(pid) {
|
|
|
15222
15236
|
}
|
|
15223
15237
|
var CONTROL_ONLY_HASH = "control-only";
|
|
15224
15238
|
var TUNNEL_REJECTED_AFTER = 2;
|
|
15239
|
+
var CONTROL_RETRY_MS = 60 * 60 * 1e3;
|
|
15240
|
+
var RELAY_CONTROL_UNSUPPORTED_KEY = "relay_control_unsupported";
|
|
15241
|
+
function relayControlUnsupportedMessage(workspaceId) {
|
|
15242
|
+
return `the relay refused the control-path forward for workspace ${workspaceId}, so the passengers tunnel runs without the control API (remote ship transport and periscopes will not reach this ship); the relay is too old for \`-path-control\` (crew-relay 0.2.0+) \u2014 deploy it with scripts/deploy-relay.sh`;
|
|
15243
|
+
}
|
|
15244
|
+
function controlRefusedTunnels(stateDir, now = Date.now()) {
|
|
15245
|
+
const out = [];
|
|
15246
|
+
for (const workspaceId of readAllPersistedWorkspaceIds(stateDir)) {
|
|
15247
|
+
const at = readPersistedTunnel(stateDir, workspaceId)?.controlRefusedAt;
|
|
15248
|
+
if (at && now - Date.parse(at) < CONTROL_RETRY_MS) out.push(workspaceId);
|
|
15249
|
+
}
|
|
15250
|
+
return out;
|
|
15251
|
+
}
|
|
15225
15252
|
function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, stateDir, mcpSecrets = /* @__PURE__ */ new Map(), deps = {}) {
|
|
15226
15253
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
15227
15254
|
const plannedIds = new Set(plans.map((p) => p.workspaceId));
|
|
15228
15255
|
for (const plan of plans) {
|
|
15229
15256
|
const existing = readPersistedTunnel(stateDir, plan.workspaceId);
|
|
15230
15257
|
const mountsHash = plan.mountsHash ?? CONTROL_ONLY_HASH;
|
|
15231
|
-
const
|
|
15258
|
+
const refusedAt = existing?.controlRefusedAt;
|
|
15259
|
+
const refusalFresh = refusedAt !== void 0 && Date.now() - Date.parse(refusedAt) < CONTROL_RETRY_MS;
|
|
15260
|
+
let controlSocket = deps.controlSocket && refusalFresh ? void 0 : deps.controlSocket;
|
|
15261
|
+
let controlRefusedAt = refusalFresh ? refusedAt : void 0;
|
|
15262
|
+
const controlUnchanged = existing?.controlSocket === controlSocket;
|
|
15232
15263
|
const currentSecret = mcpSecrets.get(plan.workspaceId);
|
|
15233
15264
|
const secretUnchanged = (existing?.mcpSecret ?? void 0) === (currentSecret ?? void 0);
|
|
15234
15265
|
const slug2 = existing?.slug ?? generateTunnelSlug();
|
|
@@ -15253,7 +15284,12 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15253
15284
|
continue;
|
|
15254
15285
|
}
|
|
15255
15286
|
const diedQuickly = existing !== void 0 && existing.status === "connecting" && !alive(existing.pid) && controlUnchanged && secretUnchanged && slugUnchanged && existing.mountsHash === mountsHash;
|
|
15256
|
-
|
|
15287
|
+
let quickExits = diedQuickly ? (existing.quickExits ?? 0) + 1 : 0;
|
|
15288
|
+
if (diedQuickly && controlSocket && plan.port !== void 0) {
|
|
15289
|
+
controlSocket = void 0;
|
|
15290
|
+
controlRefusedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15291
|
+
quickExits = 0;
|
|
15292
|
+
}
|
|
15257
15293
|
let settledStatus = "connecting";
|
|
15258
15294
|
const tunnel = startTunnel({
|
|
15259
15295
|
relayHost,
|
|
@@ -15262,7 +15298,7 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15262
15298
|
slug: slug2,
|
|
15263
15299
|
apiKey,
|
|
15264
15300
|
localPort: plan.port,
|
|
15265
|
-
controlSocket
|
|
15301
|
+
controlSocket,
|
|
15266
15302
|
privateKeyPath,
|
|
15267
15303
|
mcpSecret: currentSecret,
|
|
15268
15304
|
spawnFn: deps.spawnFn,
|
|
@@ -15275,7 +15311,8 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15275
15311
|
containerName: plan.containerName ?? "",
|
|
15276
15312
|
workspaceId: plan.workspaceId,
|
|
15277
15313
|
mountsHash,
|
|
15278
|
-
controlSocket
|
|
15314
|
+
controlSocket,
|
|
15315
|
+
controlRefusedAt,
|
|
15279
15316
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15280
15317
|
status: settledStatus,
|
|
15281
15318
|
mcpSecret: currentSecret,
|
|
@@ -25545,6 +25582,15 @@ if (command === "passenger-sync-daemon") {
|
|
|
25545
25582
|
since: (/* @__PURE__ */ new Date()).toISOString()
|
|
25546
25583
|
}).then(() => void 0).catch(() => void 0));
|
|
25547
25584
|
} else if (status2 === "connected") clearShipAttention(state, rejectedKey);
|
|
25585
|
+
const controlKey = `${RELAY_CONTROL_UNSUPPORTED_KEY}:${workspaceId}`;
|
|
25586
|
+
if (info?.controlRefusedAt) {
|
|
25587
|
+
pending.push(raiseShipAttention({ state, emit, route: owningRoute, ship: cfg.ship }, {
|
|
25588
|
+
kind: RELAY_CONTROL_UNSUPPORTED_KEY,
|
|
25589
|
+
key: controlKey,
|
|
25590
|
+
message: relayControlUnsupportedMessage(workspaceId),
|
|
25591
|
+
since: (/* @__PURE__ */ new Date()).toISOString()
|
|
25592
|
+
}).then(() => void 0).catch(() => void 0));
|
|
25593
|
+
} else if (status2 === "connected") clearShipAttention(state, controlKey);
|
|
25548
25594
|
}
|
|
25549
25595
|
});
|
|
25550
25596
|
for (const plan of containerPlans) pending.push(reconcileEndpoint(plan.workspaceId, reconcile));
|
|
@@ -30245,6 +30291,9 @@ watermark: ${state.watermark()}
|
|
|
30245
30291
|
for (const t of rejectedTunnels(cfg.ship.stateDir)) {
|
|
30246
30292
|
problems.push({ severity: "attention", kind: TUNNEL_REJECTED_KEY, message: tunnelRejectedMessage(t.workspaceId, t.quickExits), remedy: "rotate the slug with `crew rotate-passenger-url`" });
|
|
30247
30293
|
}
|
|
30294
|
+
for (const workspaceId of controlRefusedTunnels(cfg.ship.stateDir)) {
|
|
30295
|
+
problems.push({ severity: "attention", kind: RELAY_CONTROL_UNSUPPORTED_KEY, message: relayControlUnsupportedMessage(workspaceId), remedy: "deploy crew-relay 0.2.0 or later (scripts/deploy-relay.sh in the crew-relay repository)" });
|
|
30296
|
+
}
|
|
30248
30297
|
const previewProblem2 = await previewHostProblem(cfg);
|
|
30249
30298
|
if (previewProblem2) problems.push(previewHostFinding(previewProblem2));
|
|
30250
30299
|
if (cfg.routes.some((x) => x.route === route2.route && x.enabled && x.hostPeriscopes)) {
|
|
@@ -30267,6 +30316,8 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
|
|
|
30267
30316
|
for (const w of roleCapWarnings(cfg.ship)) process.stdout.write(`role concurrency: WARN ${w}
|
|
30268
30317
|
`);
|
|
30269
30318
|
for (const t of rejectedTunnels(cfg.ship.stateDir)) process.stdout.write(`relay tunnel: ATTENTION ${tunnelRejectedMessage(t.workspaceId, t.quickExits)}
|
|
30319
|
+
`);
|
|
30320
|
+
for (const workspaceId of controlRefusedTunnels(cfg.ship.stateDir)) process.stdout.write(`relay tunnel: ATTENTION ${relayControlUnsupportedMessage(workspaceId)}
|
|
30270
30321
|
`);
|
|
30271
30322
|
process.stdout.write(`periscopes: ${periscopeSummary(cfg)}
|
|
30272
30323
|
`);
|
package/package.json
CHANGED