@bivy/bivy 0.1.0-staging.3 → 0.1.0-staging.5
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/bin/bivy.mjs +43 -3
- package/dist/relay-client.js +28 -0
- package/dist/server.js +8 -1
- package/package.json +1 -1
package/bin/bivy.mjs
CHANGED
|
@@ -3265,15 +3265,47 @@ async function cmdStatus(args = []) {
|
|
|
3265
3265
|
try { status = await localApi(config, "/api/status"); } catch {}
|
|
3266
3266
|
}
|
|
3267
3267
|
if (json) {
|
|
3268
|
-
|
|
3268
|
+
const relayCfgJson = loadRelayConfig();
|
|
3269
|
+
console.log(JSON.stringify({
|
|
3270
|
+
reachable,
|
|
3271
|
+
url: url(config),
|
|
3272
|
+
workspace: status?.workspace || config.workspace,
|
|
3273
|
+
service: serviceStatusLine(),
|
|
3274
|
+
remoteConfigured: Boolean(status?.relay?.configured || relayCfgJson),
|
|
3275
|
+
relay: {
|
|
3276
|
+
configured: Boolean(status?.relay?.configured || relayCfgJson),
|
|
3277
|
+
connected: status?.relay?.connected ?? null,
|
|
3278
|
+
app: status?.relay?.controlPlaneUrl || relayCfgJson?.controlPlaneUrl || null,
|
|
3279
|
+
relay: status?.relay?.relayUrl || relayCfgJson?.url || null,
|
|
3280
|
+
lastError: status?.relay?.lastError || null,
|
|
3281
|
+
},
|
|
3282
|
+
status,
|
|
3283
|
+
}, null, 2));
|
|
3269
3284
|
return;
|
|
3270
3285
|
}
|
|
3271
3286
|
console.log(c.bold("\n Bivy node\n"));
|
|
3272
3287
|
console.log(` url: ${url(config)} ${reachable ? c.green("● reachable") : c.dim("○ not reachable")}`);
|
|
3273
3288
|
console.log(` workspace: ${status?.workspace || config.workspace}`);
|
|
3274
3289
|
console.log(` ${serviceStatusLine()}`);
|
|
3275
|
-
console.log(` remote: ${status?.relay?.configured || fs.existsSync(relayConfigPath) ? c.green("relay configured") : "local only"}`);
|
|
3276
3290
|
const relay = loadRelayConfig();
|
|
3291
|
+
const relaySt = status?.relay;
|
|
3292
|
+
const relayConfigured = Boolean(relaySt?.configured || relay);
|
|
3293
|
+
if (!relayConfigured) {
|
|
3294
|
+
console.log(` remote: ${c.dim("local only")} ${c.dim("('bivy relay:setup' to enable remote access)")}`);
|
|
3295
|
+
} else {
|
|
3296
|
+
// The live link state is only knowable when the node is running; if it's
|
|
3297
|
+
// down we can say it's configured but not whether it's currently connected.
|
|
3298
|
+
let state;
|
|
3299
|
+
if (!reachable) state = c.yellow("configured (node not running)");
|
|
3300
|
+
else if (relaySt?.connected) state = c.green("● connected");
|
|
3301
|
+
else state = c.yellow("○ configured, not connected");
|
|
3302
|
+
const relErr = relaySt?.lastError ? c.dim(` (${relaySt.lastError})`) : "";
|
|
3303
|
+
console.log(` remote: ${state}${relErr}`);
|
|
3304
|
+
const cpUrl = relaySt?.controlPlaneUrl || relay?.controlPlaneUrl;
|
|
3305
|
+
const rlUrl = relaySt?.relayUrl || relay?.url;
|
|
3306
|
+
if (cpUrl) console.log(` app: ${cpUrl}`);
|
|
3307
|
+
if (rlUrl) console.log(` relay: ${rlUrl}`);
|
|
3308
|
+
}
|
|
3277
3309
|
if (relay?.controlPlaneUrl && relay?.enrollmentToken) {
|
|
3278
3310
|
try {
|
|
3279
3311
|
const acct = await controlPlaneNodeApi(relay, "/node/account");
|
|
@@ -3331,7 +3363,15 @@ async function cmdDoctor(args = []) {
|
|
|
3331
3363
|
console.log(` ${mark(agentAvailable, true)} agent ${runtimeInfo?.displayName || defaultAgent}${agentAvailable ? "" : c.dim(" not available — install it or run 'bivy setup'")}`);
|
|
3332
3364
|
console.log(` ${mark(hasModelConfig(config), authOwner !== "bivy")} model ${hasModelConfig(config) ? "configured" : authOwner === "bivy" ? c.dim("not configured — run 'bivy login'") : c.dim("agent-native auth — use the agent's CLI login if needed")}`);
|
|
3333
3365
|
const relayConfigured = Boolean(status?.relay?.configured || fs.existsSync(relayConfigPath));
|
|
3334
|
-
|
|
3366
|
+
const relayConnected = Boolean(status?.relay?.connected);
|
|
3367
|
+
const relayApp = status?.relay?.controlPlaneUrl;
|
|
3368
|
+
const relayErr = status?.relay?.lastError;
|
|
3369
|
+
const relayLine = !relayConfigured
|
|
3370
|
+
? c.dim("local only — 'bivy relay:setup' to enable")
|
|
3371
|
+
: relayConnected
|
|
3372
|
+
? c.green("relay connected") + (relayApp ? c.dim(` ${relayApp}`) : "")
|
|
3373
|
+
: c.yellow("configured, not connected") + (relayErr ? c.dim(` (${relayErr})`) : "");
|
|
3374
|
+
console.log(` ${relayConfigured ? (relayConnected ? ok : warn) : c.dim("○")} remote ${relayLine}`);
|
|
3335
3375
|
// Derived from BUILTIN_TERMINAL_AGENTS (the same list 'bivy agents'/'bivy run'
|
|
3336
3376
|
// use) rather than a hand-maintained list, so it can't drift out of sync (#113).
|
|
3337
3377
|
const agentCommands = [...BUILTIN_TERMINAL_AGENTS.values()].filter((a) => a.type === "command").map((a) => a.command);
|
package/dist/relay-client.js
CHANGED
|
@@ -51,6 +51,14 @@ export class RelayConnector {
|
|
|
51
51
|
heartbeatTimer;
|
|
52
52
|
stableTimer;
|
|
53
53
|
lastPongAt = 0;
|
|
54
|
+
// True only between the relay's `ready` message (auth + entitlement passed)
|
|
55
|
+
// and the socket closing. This — not "a connector object exists" — is what
|
|
56
|
+
// "connected" means to the control plane, so it's what `bivy status` reports.
|
|
57
|
+
ready = false;
|
|
58
|
+
// Most recent relay-side failure (ticket mint, socket error, or an `error`
|
|
59
|
+
// frame), surfaced by `bivy status`/`doctor` so a node that never connects
|
|
60
|
+
// explains why instead of silently showing "configured".
|
|
61
|
+
lastErrorMessage;
|
|
54
62
|
replay = new ReplayGuard();
|
|
55
63
|
reassembler = new FrameReassembler();
|
|
56
64
|
pairing;
|
|
@@ -71,12 +79,26 @@ export class RelayConnector {
|
|
|
71
79
|
return;
|
|
72
80
|
this.ws.send(JSON.stringify({ t: "pair", p: JSON.stringify({ k: "key.rotate", deliveries }) }));
|
|
73
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* True only while the relay link is live AND the relay has sent `ready`
|
|
84
|
+
* (auth/entitlement checks passed) — i.e. the node is actually reachable from
|
|
85
|
+
* the control plane. A socket that opened but was rejected, or one still
|
|
86
|
+
* reconnecting, reads false.
|
|
87
|
+
*/
|
|
88
|
+
get connected() {
|
|
89
|
+
return this.ready && this.ws?.readyState === WebSocket.OPEN;
|
|
90
|
+
}
|
|
91
|
+
/** Most recent relay-side failure, if any — for status/diagnostics. */
|
|
92
|
+
get lastError() {
|
|
93
|
+
return this.lastErrorMessage;
|
|
94
|
+
}
|
|
74
95
|
start() {
|
|
75
96
|
this.closed = false;
|
|
76
97
|
void this.connect();
|
|
77
98
|
}
|
|
78
99
|
stop() {
|
|
79
100
|
this.closed = true;
|
|
101
|
+
this.ready = false;
|
|
80
102
|
this.stopHeartbeat();
|
|
81
103
|
this.clearBackoffReset();
|
|
82
104
|
this.ws?.close();
|
|
@@ -250,6 +272,7 @@ export class RelayConnector {
|
|
|
250
272
|
({ ticket, relayUrl } = await this.mintTicket());
|
|
251
273
|
}
|
|
252
274
|
catch (error) {
|
|
275
|
+
this.lastErrorMessage = `ticket mint failed: ${error.message}`;
|
|
253
276
|
console.warn("[relay] could not mint relay ticket:", error.message);
|
|
254
277
|
this.scheduleReconnect();
|
|
255
278
|
return;
|
|
@@ -276,6 +299,8 @@ export class RelayConnector {
|
|
|
276
299
|
return;
|
|
277
300
|
}
|
|
278
301
|
if (env.t === "ready") {
|
|
302
|
+
this.ready = true;
|
|
303
|
+
this.lastErrorMessage = undefined;
|
|
279
304
|
this.startHeartbeat(ws);
|
|
280
305
|
this.scheduleBackoffReset(ws);
|
|
281
306
|
console.log("[relay] connected");
|
|
@@ -311,6 +336,7 @@ export class RelayConnector {
|
|
|
311
336
|
}
|
|
312
337
|
if (env.t === "error") {
|
|
313
338
|
const message = env.error || "Relay error";
|
|
339
|
+
this.lastErrorMessage = message;
|
|
314
340
|
console.warn("[relay] error:", message);
|
|
315
341
|
if (isFatalRelayError(message)) {
|
|
316
342
|
console.warn("[relay] disabling connector; fix relay setup/plan and restart the node dev server");
|
|
@@ -323,11 +349,13 @@ export class RelayConnector {
|
|
|
323
349
|
this.lastPongAt = Date.now();
|
|
324
350
|
});
|
|
325
351
|
ws.on("close", () => {
|
|
352
|
+
this.ready = false;
|
|
326
353
|
this.stopHeartbeat();
|
|
327
354
|
this.clearBackoffReset();
|
|
328
355
|
this.scheduleReconnect();
|
|
329
356
|
});
|
|
330
357
|
ws.on("error", (error) => {
|
|
358
|
+
this.lastErrorMessage = error.message;
|
|
331
359
|
console.warn("[relay] socket error:", error.message);
|
|
332
360
|
});
|
|
333
361
|
}
|
package/dist/server.js
CHANGED
|
@@ -7577,7 +7577,14 @@ app.get("/api/status", (_req, res) => {
|
|
|
7577
7577
|
workspaceBoundary: true,
|
|
7578
7578
|
strictApprovalOptIn: true,
|
|
7579
7579
|
},
|
|
7580
|
-
relay: {
|
|
7580
|
+
relay: {
|
|
7581
|
+
configured: Boolean(relayConfig),
|
|
7582
|
+
// Real link state (relay sent `ready`), not merely "a connector exists".
|
|
7583
|
+
connected: Boolean(relay?.connected),
|
|
7584
|
+
controlPlaneUrl: relayConfig?.controlPlaneUrl,
|
|
7585
|
+
relayUrl: relayConfig?.url,
|
|
7586
|
+
...(relay?.lastError ? { lastError: relay.lastError } : {}),
|
|
7587
|
+
},
|
|
7581
7588
|
sessions: {
|
|
7582
7589
|
open: new Set(openSessions.values()).size,
|
|
7583
7590
|
indexed: metadata.listSessions().length,
|
package/package.json
CHANGED