@tablation/crew 0.126.7 → 0.126.8
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 +41 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15222,13 +15222,30 @@ function isPidAlive(pid) {
|
|
|
15222
15222
|
}
|
|
15223
15223
|
var CONTROL_ONLY_HASH = "control-only";
|
|
15224
15224
|
var TUNNEL_REJECTED_AFTER = 2;
|
|
15225
|
+
var CONTROL_RETRY_MS = 60 * 60 * 1e3;
|
|
15226
|
+
var RELAY_CONTROL_UNSUPPORTED_KEY = "relay_control_unsupported";
|
|
15227
|
+
function relayControlUnsupportedMessage(workspaceId) {
|
|
15228
|
+
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`;
|
|
15229
|
+
}
|
|
15230
|
+
function controlRefusedTunnels(stateDir, now = Date.now()) {
|
|
15231
|
+
const out = [];
|
|
15232
|
+
for (const workspaceId of readAllPersistedWorkspaceIds(stateDir)) {
|
|
15233
|
+
const at = readPersistedTunnel(stateDir, workspaceId)?.controlRefusedAt;
|
|
15234
|
+
if (at && now - Date.parse(at) < CONTROL_RETRY_MS) out.push(workspaceId);
|
|
15235
|
+
}
|
|
15236
|
+
return out;
|
|
15237
|
+
}
|
|
15225
15238
|
function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, stateDir, mcpSecrets = /* @__PURE__ */ new Map(), deps = {}) {
|
|
15226
15239
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
15227
15240
|
const plannedIds = new Set(plans.map((p) => p.workspaceId));
|
|
15228
15241
|
for (const plan of plans) {
|
|
15229
15242
|
const existing = readPersistedTunnel(stateDir, plan.workspaceId);
|
|
15230
15243
|
const mountsHash = plan.mountsHash ?? CONTROL_ONLY_HASH;
|
|
15231
|
-
const
|
|
15244
|
+
const refusedAt = existing?.controlRefusedAt;
|
|
15245
|
+
const refusalFresh = refusedAt !== void 0 && Date.now() - Date.parse(refusedAt) < CONTROL_RETRY_MS;
|
|
15246
|
+
let controlSocket = deps.controlSocket && refusalFresh ? void 0 : deps.controlSocket;
|
|
15247
|
+
let controlRefusedAt = refusalFresh ? refusedAt : void 0;
|
|
15248
|
+
const controlUnchanged = existing?.controlSocket === controlSocket;
|
|
15232
15249
|
const currentSecret = mcpSecrets.get(plan.workspaceId);
|
|
15233
15250
|
const secretUnchanged = (existing?.mcpSecret ?? void 0) === (currentSecret ?? void 0);
|
|
15234
15251
|
const slug2 = existing?.slug ?? generateTunnelSlug();
|
|
@@ -15253,7 +15270,12 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15253
15270
|
continue;
|
|
15254
15271
|
}
|
|
15255
15272
|
const diedQuickly = existing !== void 0 && existing.status === "connecting" && !alive(existing.pid) && controlUnchanged && secretUnchanged && slugUnchanged && existing.mountsHash === mountsHash;
|
|
15256
|
-
|
|
15273
|
+
let quickExits = diedQuickly ? (existing.quickExits ?? 0) + 1 : 0;
|
|
15274
|
+
if (diedQuickly && controlSocket && plan.port !== void 0) {
|
|
15275
|
+
controlSocket = void 0;
|
|
15276
|
+
controlRefusedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15277
|
+
quickExits = 0;
|
|
15278
|
+
}
|
|
15257
15279
|
let settledStatus = "connecting";
|
|
15258
15280
|
const tunnel = startTunnel({
|
|
15259
15281
|
relayHost,
|
|
@@ -15262,7 +15284,7 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15262
15284
|
slug: slug2,
|
|
15263
15285
|
apiKey,
|
|
15264
15286
|
localPort: plan.port,
|
|
15265
|
-
controlSocket
|
|
15287
|
+
controlSocket,
|
|
15266
15288
|
privateKeyPath,
|
|
15267
15289
|
mcpSecret: currentSecret,
|
|
15268
15290
|
spawnFn: deps.spawnFn,
|
|
@@ -15275,7 +15297,8 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
|
|
|
15275
15297
|
containerName: plan.containerName ?? "",
|
|
15276
15298
|
workspaceId: plan.workspaceId,
|
|
15277
15299
|
mountsHash,
|
|
15278
|
-
controlSocket
|
|
15300
|
+
controlSocket,
|
|
15301
|
+
controlRefusedAt,
|
|
15279
15302
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15280
15303
|
status: settledStatus,
|
|
15281
15304
|
mcpSecret: currentSecret,
|
|
@@ -25545,6 +25568,15 @@ if (command === "passenger-sync-daemon") {
|
|
|
25545
25568
|
since: (/* @__PURE__ */ new Date()).toISOString()
|
|
25546
25569
|
}).then(() => void 0).catch(() => void 0));
|
|
25547
25570
|
} else if (status2 === "connected") clearShipAttention(state, rejectedKey);
|
|
25571
|
+
const controlKey = `${RELAY_CONTROL_UNSUPPORTED_KEY}:${workspaceId}`;
|
|
25572
|
+
if (info?.controlRefusedAt) {
|
|
25573
|
+
pending.push(raiseShipAttention({ state, emit, route: owningRoute, ship: cfg.ship }, {
|
|
25574
|
+
kind: RELAY_CONTROL_UNSUPPORTED_KEY,
|
|
25575
|
+
key: controlKey,
|
|
25576
|
+
message: relayControlUnsupportedMessage(workspaceId),
|
|
25577
|
+
since: (/* @__PURE__ */ new Date()).toISOString()
|
|
25578
|
+
}).then(() => void 0).catch(() => void 0));
|
|
25579
|
+
} else if (status2 === "connected") clearShipAttention(state, controlKey);
|
|
25548
25580
|
}
|
|
25549
25581
|
});
|
|
25550
25582
|
for (const plan of containerPlans) pending.push(reconcileEndpoint(plan.workspaceId, reconcile));
|
|
@@ -30245,6 +30277,9 @@ watermark: ${state.watermark()}
|
|
|
30245
30277
|
for (const t of rejectedTunnels(cfg.ship.stateDir)) {
|
|
30246
30278
|
problems.push({ severity: "attention", kind: TUNNEL_REJECTED_KEY, message: tunnelRejectedMessage(t.workspaceId, t.quickExits), remedy: "rotate the slug with `crew rotate-passenger-url`" });
|
|
30247
30279
|
}
|
|
30280
|
+
for (const workspaceId of controlRefusedTunnels(cfg.ship.stateDir)) {
|
|
30281
|
+
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)" });
|
|
30282
|
+
}
|
|
30248
30283
|
const previewProblem2 = await previewHostProblem(cfg);
|
|
30249
30284
|
if (previewProblem2) problems.push(previewHostFinding(previewProblem2));
|
|
30250
30285
|
if (cfg.routes.some((x) => x.route === route2.route && x.enabled && x.hostPeriscopes)) {
|
|
@@ -30267,6 +30302,8 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
|
|
|
30267
30302
|
for (const w of roleCapWarnings(cfg.ship)) process.stdout.write(`role concurrency: WARN ${w}
|
|
30268
30303
|
`);
|
|
30269
30304
|
for (const t of rejectedTunnels(cfg.ship.stateDir)) process.stdout.write(`relay tunnel: ATTENTION ${tunnelRejectedMessage(t.workspaceId, t.quickExits)}
|
|
30305
|
+
`);
|
|
30306
|
+
for (const workspaceId of controlRefusedTunnels(cfg.ship.stateDir)) process.stdout.write(`relay tunnel: ATTENTION ${relayControlUnsupportedMessage(workspaceId)}
|
|
30270
30307
|
`);
|
|
30271
30308
|
process.stdout.write(`periscopes: ${periscopeSummary(cfg)}
|
|
30272
30309
|
`);
|
package/package.json
CHANGED