@h-rig/cli 0.0.6-alpha.32 → 0.0.6-alpha.34
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/bin/rig.js +67 -17
- package/dist/src/commands/_operator-surface.js +16 -0
- package/dist/src/commands/_operator-view.js +67 -17
- package/dist/src/commands/_pi-frontend.js +51 -17
- package/dist/src/commands/_pi-worker-bridge-extension.js +51 -17
- package/dist/src/commands/run.js +67 -17
- package/dist/src/commands/task.js +67 -17
- package/dist/src/commands.js +67 -17
- package/dist/src/index.js +67 -17
- package/package.json +6 -6
package/dist/bin/rig.js
CHANGED
|
@@ -7120,7 +7120,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7120
7120
|
}
|
|
7121
7121
|
if (entry.type === "timeline_warning") {
|
|
7122
7122
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
7123
|
+
continue;
|
|
7124
|
+
}
|
|
7125
|
+
if (entry.type === "action") {
|
|
7126
|
+
const text2 = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
7127
|
+
if (text2)
|
|
7128
|
+
writeLine(`[Rig action] ${text2}`);
|
|
7129
|
+
continue;
|
|
7123
7130
|
}
|
|
7131
|
+
if (entry.type === "user_message") {
|
|
7132
|
+
const text2 = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
7133
|
+
if (text2)
|
|
7134
|
+
writeLine(`[Operator] ${text2}`);
|
|
7135
|
+
continue;
|
|
7136
|
+
}
|
|
7137
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
7138
|
+
if (fallback)
|
|
7139
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
7124
7140
|
}
|
|
7125
7141
|
},
|
|
7126
7142
|
renderLogs(entries) {
|
|
@@ -7273,12 +7289,12 @@ function parseExtensionUiRequest(value) {
|
|
|
7273
7289
|
}
|
|
7274
7290
|
function renderBridgeWidget(state) {
|
|
7275
7291
|
const statusParts = [
|
|
7276
|
-
state.wsConnected ? "live
|
|
7292
|
+
state.wsConnected ? "live" : "connecting",
|
|
7277
7293
|
state.status,
|
|
7278
7294
|
state.model,
|
|
7279
7295
|
state.cwd
|
|
7280
7296
|
].filter(Boolean);
|
|
7281
|
-
const lines = [`
|
|
7297
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
7282
7298
|
if (state.activity)
|
|
7283
7299
|
lines.push(state.activity);
|
|
7284
7300
|
if (state.commands.length > 0) {
|
|
@@ -7288,27 +7304,35 @@ function renderBridgeWidget(state) {
|
|
|
7288
7304
|
if (state.transcript.length > 0) {
|
|
7289
7305
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
7290
7306
|
} else {
|
|
7291
|
-
lines.push("Waiting for worker
|
|
7307
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
7292
7308
|
}
|
|
7293
7309
|
if (state.pendingUi) {
|
|
7294
7310
|
lines.push("");
|
|
7295
|
-
lines.push(`
|
|
7311
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
7296
7312
|
lines.push(state.pendingUi.prompt);
|
|
7297
7313
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
7298
|
-
lines.push("Reply in the
|
|
7314
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
7299
7315
|
}
|
|
7300
7316
|
return lines;
|
|
7301
7317
|
}
|
|
7318
|
+
function reportBridgeError(ctx, state, message2) {
|
|
7319
|
+
appendTranscript(state, "Error", message2);
|
|
7320
|
+
state.status = message2;
|
|
7321
|
+
try {
|
|
7322
|
+
ctx.ui.notify(message2, "error");
|
|
7323
|
+
} catch {}
|
|
7324
|
+
updatePiUi(ctx, state);
|
|
7325
|
+
}
|
|
7302
7326
|
function updatePiUi(ctx, state) {
|
|
7303
|
-
ctx.ui.setTitle("
|
|
7304
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
7327
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
7328
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
7305
7329
|
syncNativeDisplayCwd(ctx, state);
|
|
7306
7330
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
7307
7331
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
7308
7332
|
return;
|
|
7309
7333
|
}
|
|
7310
7334
|
ctx.ui.setWorkingVisible(false);
|
|
7311
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
7335
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
7312
7336
|
}
|
|
7313
7337
|
function applyStatus(state, payload) {
|
|
7314
7338
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -7453,19 +7477,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
7453
7477
|
}
|
|
7454
7478
|
syncNativeDisplayCwd(ctx, state);
|
|
7455
7479
|
}
|
|
7480
|
+
function resolveAttachReadyTimeoutMs() {
|
|
7481
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
7482
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
7483
|
+
}
|
|
7484
|
+
function formatElapsed(sinceMs) {
|
|
7485
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
7486
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
7487
|
+
const seconds = totalSeconds % 60;
|
|
7488
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
7489
|
+
}
|
|
7456
7490
|
async function waitForWorkerReady(options, ctx, state) {
|
|
7491
|
+
const startedAt = Date.now();
|
|
7492
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
7493
|
+
let consecutiveFailures = 0;
|
|
7457
7494
|
while (true) {
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7495
|
+
let requestFailed = false;
|
|
7496
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
7497
|
+
requestFailed = true;
|
|
7498
|
+
return {
|
|
7499
|
+
ready: false,
|
|
7500
|
+
status: error instanceof Error ? error.message : String(error),
|
|
7501
|
+
retryAfterMs: 1000
|
|
7502
|
+
};
|
|
7503
|
+
});
|
|
7463
7504
|
if (session.ready === false) {
|
|
7505
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
7464
7506
|
const status = String(session.status ?? "starting");
|
|
7465
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
7466
|
-
updatePiUi(ctx, state);
|
|
7467
7507
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
7468
|
-
|
|
7508
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
7509
|
+
return false;
|
|
7510
|
+
}
|
|
7511
|
+
if (consecutiveFailures >= 5) {
|
|
7512
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
7513
|
+
} else {
|
|
7514
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
7515
|
+
}
|
|
7516
|
+
updatePiUi(ctx, state);
|
|
7517
|
+
if (Date.now() >= deadline) {
|
|
7518
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
7469
7519
|
return false;
|
|
7470
7520
|
}
|
|
7471
7521
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -7673,7 +7723,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7673
7723
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
7674
7724
|
state.nativeStream = nativePiUiContextAvailable;
|
|
7675
7725
|
updatePiUi(ctx, state);
|
|
7676
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
7726
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
7677
7727
|
ctx.ui.onTerminalInput((data) => {
|
|
7678
7728
|
if (data.includes("\x04")) {
|
|
7679
7729
|
ctx.shutdown();
|
|
@@ -124,7 +124,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
124
124
|
}
|
|
125
125
|
if (entry.type === "timeline_warning") {
|
|
126
126
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (entry.type === "action") {
|
|
130
|
+
const text = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
131
|
+
if (text)
|
|
132
|
+
writeLine(`[Rig action] ${text}`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (entry.type === "user_message") {
|
|
136
|
+
const text = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
137
|
+
if (text)
|
|
138
|
+
writeLine(`[Operator] ${text}`);
|
|
139
|
+
continue;
|
|
127
140
|
}
|
|
141
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
142
|
+
if (fallback)
|
|
143
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
128
144
|
}
|
|
129
145
|
},
|
|
130
146
|
renderLogs(entries) {
|
|
@@ -410,7 +410,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
410
410
|
}
|
|
411
411
|
if (entry.type === "timeline_warning") {
|
|
412
412
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (entry.type === "action") {
|
|
416
|
+
const text = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
417
|
+
if (text)
|
|
418
|
+
writeLine(`[Rig action] ${text}`);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (entry.type === "user_message") {
|
|
422
|
+
const text = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
423
|
+
if (text)
|
|
424
|
+
writeLine(`[Operator] ${text}`);
|
|
425
|
+
continue;
|
|
413
426
|
}
|
|
427
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
428
|
+
if (fallback)
|
|
429
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
414
430
|
}
|
|
415
431
|
},
|
|
416
432
|
renderLogs(entries) {
|
|
@@ -543,12 +559,12 @@ function parseExtensionUiRequest(value) {
|
|
|
543
559
|
}
|
|
544
560
|
function renderBridgeWidget(state) {
|
|
545
561
|
const statusParts = [
|
|
546
|
-
state.wsConnected ? "live
|
|
562
|
+
state.wsConnected ? "live" : "connecting",
|
|
547
563
|
state.status,
|
|
548
564
|
state.model,
|
|
549
565
|
state.cwd
|
|
550
566
|
].filter(Boolean);
|
|
551
|
-
const lines = [`
|
|
567
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
552
568
|
if (state.activity)
|
|
553
569
|
lines.push(state.activity);
|
|
554
570
|
if (state.commands.length > 0) {
|
|
@@ -558,27 +574,35 @@ function renderBridgeWidget(state) {
|
|
|
558
574
|
if (state.transcript.length > 0) {
|
|
559
575
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
560
576
|
} else {
|
|
561
|
-
lines.push("Waiting for worker
|
|
577
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
562
578
|
}
|
|
563
579
|
if (state.pendingUi) {
|
|
564
580
|
lines.push("");
|
|
565
|
-
lines.push(`
|
|
581
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
566
582
|
lines.push(state.pendingUi.prompt);
|
|
567
583
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
568
|
-
lines.push("Reply in the
|
|
584
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
569
585
|
}
|
|
570
586
|
return lines;
|
|
571
587
|
}
|
|
588
|
+
function reportBridgeError(ctx, state, message) {
|
|
589
|
+
appendTranscript(state, "Error", message);
|
|
590
|
+
state.status = message;
|
|
591
|
+
try {
|
|
592
|
+
ctx.ui.notify(message, "error");
|
|
593
|
+
} catch {}
|
|
594
|
+
updatePiUi(ctx, state);
|
|
595
|
+
}
|
|
572
596
|
function updatePiUi(ctx, state) {
|
|
573
|
-
ctx.ui.setTitle("
|
|
574
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
597
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
598
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
575
599
|
syncNativeDisplayCwd(ctx, state);
|
|
576
600
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
577
601
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
578
602
|
return;
|
|
579
603
|
}
|
|
580
604
|
ctx.ui.setWorkingVisible(false);
|
|
581
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
605
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
582
606
|
}
|
|
583
607
|
function applyStatus(state, payload) {
|
|
584
608
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -723,19 +747,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
723
747
|
}
|
|
724
748
|
syncNativeDisplayCwd(ctx, state);
|
|
725
749
|
}
|
|
750
|
+
function resolveAttachReadyTimeoutMs() {
|
|
751
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
752
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
753
|
+
}
|
|
754
|
+
function formatElapsed(sinceMs) {
|
|
755
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
756
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
757
|
+
const seconds = totalSeconds % 60;
|
|
758
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
759
|
+
}
|
|
726
760
|
async function waitForWorkerReady(options, ctx, state) {
|
|
761
|
+
const startedAt = Date.now();
|
|
762
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
763
|
+
let consecutiveFailures = 0;
|
|
727
764
|
while (true) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
765
|
+
let requestFailed = false;
|
|
766
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
767
|
+
requestFailed = true;
|
|
768
|
+
return {
|
|
769
|
+
ready: false,
|
|
770
|
+
status: error instanceof Error ? error.message : String(error),
|
|
771
|
+
retryAfterMs: 1000
|
|
772
|
+
};
|
|
773
|
+
});
|
|
733
774
|
if (session.ready === false) {
|
|
775
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
734
776
|
const status = String(session.status ?? "starting");
|
|
735
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
736
|
-
updatePiUi(ctx, state);
|
|
737
777
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
738
|
-
|
|
778
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
if (consecutiveFailures >= 5) {
|
|
782
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
783
|
+
} else {
|
|
784
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
785
|
+
}
|
|
786
|
+
updatePiUi(ctx, state);
|
|
787
|
+
if (Date.now() >= deadline) {
|
|
788
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
739
789
|
return false;
|
|
740
790
|
}
|
|
741
791
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -943,7 +993,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
943
993
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
944
994
|
state.nativeStream = nativePiUiContextAvailable;
|
|
945
995
|
updatePiUi(ctx, state);
|
|
946
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
996
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
947
997
|
ctx.ui.onTerminalInput((data) => {
|
|
948
998
|
if (data.includes("\x04")) {
|
|
949
999
|
ctx.shutdown();
|
|
@@ -333,12 +333,12 @@ function parseExtensionUiRequest(value) {
|
|
|
333
333
|
}
|
|
334
334
|
function renderBridgeWidget(state) {
|
|
335
335
|
const statusParts = [
|
|
336
|
-
state.wsConnected ? "live
|
|
336
|
+
state.wsConnected ? "live" : "connecting",
|
|
337
337
|
state.status,
|
|
338
338
|
state.model,
|
|
339
339
|
state.cwd
|
|
340
340
|
].filter(Boolean);
|
|
341
|
-
const lines = [`
|
|
341
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
342
342
|
if (state.activity)
|
|
343
343
|
lines.push(state.activity);
|
|
344
344
|
if (state.commands.length > 0) {
|
|
@@ -348,27 +348,35 @@ function renderBridgeWidget(state) {
|
|
|
348
348
|
if (state.transcript.length > 0) {
|
|
349
349
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
350
350
|
} else {
|
|
351
|
-
lines.push("Waiting for worker
|
|
351
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
352
352
|
}
|
|
353
353
|
if (state.pendingUi) {
|
|
354
354
|
lines.push("");
|
|
355
|
-
lines.push(`
|
|
355
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
356
356
|
lines.push(state.pendingUi.prompt);
|
|
357
357
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
358
|
-
lines.push("Reply in the
|
|
358
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
359
359
|
}
|
|
360
360
|
return lines;
|
|
361
361
|
}
|
|
362
|
+
function reportBridgeError(ctx, state, message) {
|
|
363
|
+
appendTranscript(state, "Error", message);
|
|
364
|
+
state.status = message;
|
|
365
|
+
try {
|
|
366
|
+
ctx.ui.notify(message, "error");
|
|
367
|
+
} catch {}
|
|
368
|
+
updatePiUi(ctx, state);
|
|
369
|
+
}
|
|
362
370
|
function updatePiUi(ctx, state) {
|
|
363
|
-
ctx.ui.setTitle("
|
|
364
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
371
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
372
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
365
373
|
syncNativeDisplayCwd(ctx, state);
|
|
366
374
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
367
375
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
368
376
|
return;
|
|
369
377
|
}
|
|
370
378
|
ctx.ui.setWorkingVisible(false);
|
|
371
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
379
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
372
380
|
}
|
|
373
381
|
function applyStatus(state, payload) {
|
|
374
382
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -513,19 +521,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
513
521
|
}
|
|
514
522
|
syncNativeDisplayCwd(ctx, state);
|
|
515
523
|
}
|
|
524
|
+
function resolveAttachReadyTimeoutMs() {
|
|
525
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
526
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
527
|
+
}
|
|
528
|
+
function formatElapsed(sinceMs) {
|
|
529
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
530
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
531
|
+
const seconds = totalSeconds % 60;
|
|
532
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
533
|
+
}
|
|
516
534
|
async function waitForWorkerReady(options, ctx, state) {
|
|
535
|
+
const startedAt = Date.now();
|
|
536
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
537
|
+
let consecutiveFailures = 0;
|
|
517
538
|
while (true) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
539
|
+
let requestFailed = false;
|
|
540
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
541
|
+
requestFailed = true;
|
|
542
|
+
return {
|
|
543
|
+
ready: false,
|
|
544
|
+
status: error instanceof Error ? error.message : String(error),
|
|
545
|
+
retryAfterMs: 1000
|
|
546
|
+
};
|
|
547
|
+
});
|
|
523
548
|
if (session.ready === false) {
|
|
549
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
524
550
|
const status = String(session.status ?? "starting");
|
|
525
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
526
|
-
updatePiUi(ctx, state);
|
|
527
551
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
528
|
-
|
|
552
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
if (consecutiveFailures >= 5) {
|
|
556
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
557
|
+
} else {
|
|
558
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
559
|
+
}
|
|
560
|
+
updatePiUi(ctx, state);
|
|
561
|
+
if (Date.now() >= deadline) {
|
|
562
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
529
563
|
return false;
|
|
530
564
|
}
|
|
531
565
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -733,7 +767,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
733
767
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
734
768
|
state.nativeStream = nativePiUiContextAvailable;
|
|
735
769
|
updatePiUi(ctx, state);
|
|
736
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
770
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
737
771
|
ctx.ui.onTerminalInput((data) => {
|
|
738
772
|
if (data.includes("\x04")) {
|
|
739
773
|
ctx.shutdown();
|
|
@@ -323,12 +323,12 @@ function parseExtensionUiRequest(value) {
|
|
|
323
323
|
}
|
|
324
324
|
function renderBridgeWidget(state) {
|
|
325
325
|
const statusParts = [
|
|
326
|
-
state.wsConnected ? "live
|
|
326
|
+
state.wsConnected ? "live" : "connecting",
|
|
327
327
|
state.status,
|
|
328
328
|
state.model,
|
|
329
329
|
state.cwd
|
|
330
330
|
].filter(Boolean);
|
|
331
|
-
const lines = [`
|
|
331
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
332
332
|
if (state.activity)
|
|
333
333
|
lines.push(state.activity);
|
|
334
334
|
if (state.commands.length > 0) {
|
|
@@ -338,27 +338,35 @@ function renderBridgeWidget(state) {
|
|
|
338
338
|
if (state.transcript.length > 0) {
|
|
339
339
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
340
340
|
} else {
|
|
341
|
-
lines.push("Waiting for worker
|
|
341
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
342
342
|
}
|
|
343
343
|
if (state.pendingUi) {
|
|
344
344
|
lines.push("");
|
|
345
|
-
lines.push(`
|
|
345
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
346
346
|
lines.push(state.pendingUi.prompt);
|
|
347
347
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
348
|
-
lines.push("Reply in the
|
|
348
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
349
349
|
}
|
|
350
350
|
return lines;
|
|
351
351
|
}
|
|
352
|
+
function reportBridgeError(ctx, state, message) {
|
|
353
|
+
appendTranscript(state, "Error", message);
|
|
354
|
+
state.status = message;
|
|
355
|
+
try {
|
|
356
|
+
ctx.ui.notify(message, "error");
|
|
357
|
+
} catch {}
|
|
358
|
+
updatePiUi(ctx, state);
|
|
359
|
+
}
|
|
352
360
|
function updatePiUi(ctx, state) {
|
|
353
|
-
ctx.ui.setTitle("
|
|
354
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
361
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
362
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
355
363
|
syncNativeDisplayCwd(ctx, state);
|
|
356
364
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
357
365
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
358
366
|
return;
|
|
359
367
|
}
|
|
360
368
|
ctx.ui.setWorkingVisible(false);
|
|
361
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
369
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
362
370
|
}
|
|
363
371
|
function applyStatus(state, payload) {
|
|
364
372
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -503,19 +511,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
503
511
|
}
|
|
504
512
|
syncNativeDisplayCwd(ctx, state);
|
|
505
513
|
}
|
|
514
|
+
function resolveAttachReadyTimeoutMs() {
|
|
515
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
516
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
517
|
+
}
|
|
518
|
+
function formatElapsed(sinceMs) {
|
|
519
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
520
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
521
|
+
const seconds = totalSeconds % 60;
|
|
522
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
523
|
+
}
|
|
506
524
|
async function waitForWorkerReady(options, ctx, state) {
|
|
525
|
+
const startedAt = Date.now();
|
|
526
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
527
|
+
let consecutiveFailures = 0;
|
|
507
528
|
while (true) {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
529
|
+
let requestFailed = false;
|
|
530
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
531
|
+
requestFailed = true;
|
|
532
|
+
return {
|
|
533
|
+
ready: false,
|
|
534
|
+
status: error instanceof Error ? error.message : String(error),
|
|
535
|
+
retryAfterMs: 1000
|
|
536
|
+
};
|
|
537
|
+
});
|
|
513
538
|
if (session.ready === false) {
|
|
539
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
514
540
|
const status = String(session.status ?? "starting");
|
|
515
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
516
|
-
updatePiUi(ctx, state);
|
|
517
541
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
518
|
-
|
|
542
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
if (consecutiveFailures >= 5) {
|
|
546
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
547
|
+
} else {
|
|
548
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
549
|
+
}
|
|
550
|
+
updatePiUi(ctx, state);
|
|
551
|
+
if (Date.now() >= deadline) {
|
|
552
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
519
553
|
return false;
|
|
520
554
|
}
|
|
521
555
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -723,7 +757,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
723
757
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
724
758
|
state.nativeStream = nativePiUiContextAvailable;
|
|
725
759
|
updatePiUi(ctx, state);
|
|
726
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
760
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
727
761
|
ctx.ui.onTerminalInput((data) => {
|
|
728
762
|
if (data.includes("\x04")) {
|
|
729
763
|
ctx.shutdown();
|
package/dist/src/commands/run.js
CHANGED
|
@@ -488,7 +488,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
488
488
|
}
|
|
489
489
|
if (entry.type === "timeline_warning") {
|
|
490
490
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (entry.type === "action") {
|
|
494
|
+
const text = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
495
|
+
if (text)
|
|
496
|
+
writeLine(`[Rig action] ${text}`);
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (entry.type === "user_message") {
|
|
500
|
+
const text = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
501
|
+
if (text)
|
|
502
|
+
writeLine(`[Operator] ${text}`);
|
|
503
|
+
continue;
|
|
491
504
|
}
|
|
505
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
506
|
+
if (fallback)
|
|
507
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
492
508
|
}
|
|
493
509
|
},
|
|
494
510
|
renderLogs(entries) {
|
|
@@ -621,12 +637,12 @@ function parseExtensionUiRequest(value) {
|
|
|
621
637
|
}
|
|
622
638
|
function renderBridgeWidget(state) {
|
|
623
639
|
const statusParts = [
|
|
624
|
-
state.wsConnected ? "live
|
|
640
|
+
state.wsConnected ? "live" : "connecting",
|
|
625
641
|
state.status,
|
|
626
642
|
state.model,
|
|
627
643
|
state.cwd
|
|
628
644
|
].filter(Boolean);
|
|
629
|
-
const lines = [`
|
|
645
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
630
646
|
if (state.activity)
|
|
631
647
|
lines.push(state.activity);
|
|
632
648
|
if (state.commands.length > 0) {
|
|
@@ -636,27 +652,35 @@ function renderBridgeWidget(state) {
|
|
|
636
652
|
if (state.transcript.length > 0) {
|
|
637
653
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
638
654
|
} else {
|
|
639
|
-
lines.push("Waiting for worker
|
|
655
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
640
656
|
}
|
|
641
657
|
if (state.pendingUi) {
|
|
642
658
|
lines.push("");
|
|
643
|
-
lines.push(`
|
|
659
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
644
660
|
lines.push(state.pendingUi.prompt);
|
|
645
661
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
646
|
-
lines.push("Reply in the
|
|
662
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
647
663
|
}
|
|
648
664
|
return lines;
|
|
649
665
|
}
|
|
666
|
+
function reportBridgeError(ctx, state, message) {
|
|
667
|
+
appendTranscript(state, "Error", message);
|
|
668
|
+
state.status = message;
|
|
669
|
+
try {
|
|
670
|
+
ctx.ui.notify(message, "error");
|
|
671
|
+
} catch {}
|
|
672
|
+
updatePiUi(ctx, state);
|
|
673
|
+
}
|
|
650
674
|
function updatePiUi(ctx, state) {
|
|
651
|
-
ctx.ui.setTitle("
|
|
652
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
675
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
676
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
653
677
|
syncNativeDisplayCwd(ctx, state);
|
|
654
678
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
655
679
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
656
680
|
return;
|
|
657
681
|
}
|
|
658
682
|
ctx.ui.setWorkingVisible(false);
|
|
659
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
683
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
660
684
|
}
|
|
661
685
|
function applyStatus(state, payload) {
|
|
662
686
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -801,19 +825,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
801
825
|
}
|
|
802
826
|
syncNativeDisplayCwd(ctx, state);
|
|
803
827
|
}
|
|
828
|
+
function resolveAttachReadyTimeoutMs() {
|
|
829
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
830
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
831
|
+
}
|
|
832
|
+
function formatElapsed(sinceMs) {
|
|
833
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
834
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
835
|
+
const seconds = totalSeconds % 60;
|
|
836
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
837
|
+
}
|
|
804
838
|
async function waitForWorkerReady(options, ctx, state) {
|
|
839
|
+
const startedAt = Date.now();
|
|
840
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
841
|
+
let consecutiveFailures = 0;
|
|
805
842
|
while (true) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
843
|
+
let requestFailed = false;
|
|
844
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
845
|
+
requestFailed = true;
|
|
846
|
+
return {
|
|
847
|
+
ready: false,
|
|
848
|
+
status: error instanceof Error ? error.message : String(error),
|
|
849
|
+
retryAfterMs: 1000
|
|
850
|
+
};
|
|
851
|
+
});
|
|
811
852
|
if (session.ready === false) {
|
|
853
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
812
854
|
const status = String(session.status ?? "starting");
|
|
813
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
814
|
-
updatePiUi(ctx, state);
|
|
815
855
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
816
|
-
|
|
856
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
if (consecutiveFailures >= 5) {
|
|
860
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
861
|
+
} else {
|
|
862
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
863
|
+
}
|
|
864
|
+
updatePiUi(ctx, state);
|
|
865
|
+
if (Date.now() >= deadline) {
|
|
866
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
817
867
|
return false;
|
|
818
868
|
}
|
|
819
869
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -1021,7 +1071,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
1021
1071
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
1022
1072
|
state.nativeStream = nativePiUiContextAvailable;
|
|
1023
1073
|
updatePiUi(ctx, state);
|
|
1024
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
1074
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
1025
1075
|
ctx.ui.onTerminalInput((data) => {
|
|
1026
1076
|
if (data.includes("\x04")) {
|
|
1027
1077
|
ctx.shutdown();
|
|
@@ -825,7 +825,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
825
825
|
}
|
|
826
826
|
if (entry.type === "timeline_warning") {
|
|
827
827
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
if (entry.type === "action") {
|
|
831
|
+
const text = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
832
|
+
if (text)
|
|
833
|
+
writeLine(`[Rig action] ${text}`);
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (entry.type === "user_message") {
|
|
837
|
+
const text = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
838
|
+
if (text)
|
|
839
|
+
writeLine(`[Operator] ${text}`);
|
|
840
|
+
continue;
|
|
828
841
|
}
|
|
842
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
843
|
+
if (fallback)
|
|
844
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
829
845
|
}
|
|
830
846
|
},
|
|
831
847
|
renderLogs(entries) {
|
|
@@ -1024,12 +1040,12 @@ function parseExtensionUiRequest(value) {
|
|
|
1024
1040
|
}
|
|
1025
1041
|
function renderBridgeWidget(state) {
|
|
1026
1042
|
const statusParts = [
|
|
1027
|
-
state.wsConnected ? "live
|
|
1043
|
+
state.wsConnected ? "live" : "connecting",
|
|
1028
1044
|
state.status,
|
|
1029
1045
|
state.model,
|
|
1030
1046
|
state.cwd
|
|
1031
1047
|
].filter(Boolean);
|
|
1032
|
-
const lines = [`
|
|
1048
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
1033
1049
|
if (state.activity)
|
|
1034
1050
|
lines.push(state.activity);
|
|
1035
1051
|
if (state.commands.length > 0) {
|
|
@@ -1039,27 +1055,35 @@ function renderBridgeWidget(state) {
|
|
|
1039
1055
|
if (state.transcript.length > 0) {
|
|
1040
1056
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
1041
1057
|
} else {
|
|
1042
|
-
lines.push("Waiting for worker
|
|
1058
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
1043
1059
|
}
|
|
1044
1060
|
if (state.pendingUi) {
|
|
1045
1061
|
lines.push("");
|
|
1046
|
-
lines.push(`
|
|
1062
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
1047
1063
|
lines.push(state.pendingUi.prompt);
|
|
1048
1064
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
1049
|
-
lines.push("Reply in the
|
|
1065
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
1050
1066
|
}
|
|
1051
1067
|
return lines;
|
|
1052
1068
|
}
|
|
1069
|
+
function reportBridgeError(ctx, state, message2) {
|
|
1070
|
+
appendTranscript(state, "Error", message2);
|
|
1071
|
+
state.status = message2;
|
|
1072
|
+
try {
|
|
1073
|
+
ctx.ui.notify(message2, "error");
|
|
1074
|
+
} catch {}
|
|
1075
|
+
updatePiUi(ctx, state);
|
|
1076
|
+
}
|
|
1053
1077
|
function updatePiUi(ctx, state) {
|
|
1054
|
-
ctx.ui.setTitle("
|
|
1055
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
1078
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
1079
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
1056
1080
|
syncNativeDisplayCwd(ctx, state);
|
|
1057
1081
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
1058
1082
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
1059
1083
|
return;
|
|
1060
1084
|
}
|
|
1061
1085
|
ctx.ui.setWorkingVisible(false);
|
|
1062
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
1086
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
1063
1087
|
}
|
|
1064
1088
|
function applyStatus(state, payload) {
|
|
1065
1089
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -1204,19 +1228,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
1204
1228
|
}
|
|
1205
1229
|
syncNativeDisplayCwd(ctx, state);
|
|
1206
1230
|
}
|
|
1231
|
+
function resolveAttachReadyTimeoutMs() {
|
|
1232
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
1233
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
1234
|
+
}
|
|
1235
|
+
function formatElapsed(sinceMs) {
|
|
1236
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
1237
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
1238
|
+
const seconds = totalSeconds % 60;
|
|
1239
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
1240
|
+
}
|
|
1207
1241
|
async function waitForWorkerReady(options, ctx, state) {
|
|
1242
|
+
const startedAt = Date.now();
|
|
1243
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
1244
|
+
let consecutiveFailures = 0;
|
|
1208
1245
|
while (true) {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1246
|
+
let requestFailed = false;
|
|
1247
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
1248
|
+
requestFailed = true;
|
|
1249
|
+
return {
|
|
1250
|
+
ready: false,
|
|
1251
|
+
status: error instanceof Error ? error.message : String(error),
|
|
1252
|
+
retryAfterMs: 1000
|
|
1253
|
+
};
|
|
1254
|
+
});
|
|
1214
1255
|
if (session.ready === false) {
|
|
1256
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
1215
1257
|
const status = String(session.status ?? "starting");
|
|
1216
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
1217
|
-
updatePiUi(ctx, state);
|
|
1218
1258
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
1219
|
-
|
|
1259
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
if (consecutiveFailures >= 5) {
|
|
1263
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
1264
|
+
} else {
|
|
1265
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
1266
|
+
}
|
|
1267
|
+
updatePiUi(ctx, state);
|
|
1268
|
+
if (Date.now() >= deadline) {
|
|
1269
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
1220
1270
|
return false;
|
|
1221
1271
|
}
|
|
1222
1272
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -1424,7 +1474,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
1424
1474
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
1425
1475
|
state.nativeStream = nativePiUiContextAvailable;
|
|
1426
1476
|
updatePiUi(ctx, state);
|
|
1427
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
1477
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
1428
1478
|
ctx.ui.onTerminalInput((data) => {
|
|
1429
1479
|
if (data.includes("\x04")) {
|
|
1430
1480
|
ctx.shutdown();
|
package/dist/src/commands.js
CHANGED
|
@@ -6926,7 +6926,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
6926
6926
|
}
|
|
6927
6927
|
if (entry.type === "timeline_warning") {
|
|
6928
6928
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
6929
|
+
continue;
|
|
6930
|
+
}
|
|
6931
|
+
if (entry.type === "action") {
|
|
6932
|
+
const text2 = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
6933
|
+
if (text2)
|
|
6934
|
+
writeLine(`[Rig action] ${text2}`);
|
|
6935
|
+
continue;
|
|
6929
6936
|
}
|
|
6937
|
+
if (entry.type === "user_message") {
|
|
6938
|
+
const text2 = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
6939
|
+
if (text2)
|
|
6940
|
+
writeLine(`[Operator] ${text2}`);
|
|
6941
|
+
continue;
|
|
6942
|
+
}
|
|
6943
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
6944
|
+
if (fallback)
|
|
6945
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
6930
6946
|
}
|
|
6931
6947
|
},
|
|
6932
6948
|
renderLogs(entries) {
|
|
@@ -7079,12 +7095,12 @@ function parseExtensionUiRequest(value) {
|
|
|
7079
7095
|
}
|
|
7080
7096
|
function renderBridgeWidget(state) {
|
|
7081
7097
|
const statusParts = [
|
|
7082
|
-
state.wsConnected ? "live
|
|
7098
|
+
state.wsConnected ? "live" : "connecting",
|
|
7083
7099
|
state.status,
|
|
7084
7100
|
state.model,
|
|
7085
7101
|
state.cwd
|
|
7086
7102
|
].filter(Boolean);
|
|
7087
|
-
const lines = [`
|
|
7103
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
7088
7104
|
if (state.activity)
|
|
7089
7105
|
lines.push(state.activity);
|
|
7090
7106
|
if (state.commands.length > 0) {
|
|
@@ -7094,27 +7110,35 @@ function renderBridgeWidget(state) {
|
|
|
7094
7110
|
if (state.transcript.length > 0) {
|
|
7095
7111
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
7096
7112
|
} else {
|
|
7097
|
-
lines.push("Waiting for worker
|
|
7113
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
7098
7114
|
}
|
|
7099
7115
|
if (state.pendingUi) {
|
|
7100
7116
|
lines.push("");
|
|
7101
|
-
lines.push(`
|
|
7117
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
7102
7118
|
lines.push(state.pendingUi.prompt);
|
|
7103
7119
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
7104
|
-
lines.push("Reply in the
|
|
7120
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
7105
7121
|
}
|
|
7106
7122
|
return lines;
|
|
7107
7123
|
}
|
|
7124
|
+
function reportBridgeError(ctx, state, message2) {
|
|
7125
|
+
appendTranscript(state, "Error", message2);
|
|
7126
|
+
state.status = message2;
|
|
7127
|
+
try {
|
|
7128
|
+
ctx.ui.notify(message2, "error");
|
|
7129
|
+
} catch {}
|
|
7130
|
+
updatePiUi(ctx, state);
|
|
7131
|
+
}
|
|
7108
7132
|
function updatePiUi(ctx, state) {
|
|
7109
|
-
ctx.ui.setTitle("
|
|
7110
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
7133
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
7134
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
7111
7135
|
syncNativeDisplayCwd(ctx, state);
|
|
7112
7136
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
7113
7137
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
7114
7138
|
return;
|
|
7115
7139
|
}
|
|
7116
7140
|
ctx.ui.setWorkingVisible(false);
|
|
7117
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
7141
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
7118
7142
|
}
|
|
7119
7143
|
function applyStatus(state, payload) {
|
|
7120
7144
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -7259,19 +7283,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
7259
7283
|
}
|
|
7260
7284
|
syncNativeDisplayCwd(ctx, state);
|
|
7261
7285
|
}
|
|
7286
|
+
function resolveAttachReadyTimeoutMs() {
|
|
7287
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
7288
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
7289
|
+
}
|
|
7290
|
+
function formatElapsed(sinceMs) {
|
|
7291
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
7292
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
7293
|
+
const seconds = totalSeconds % 60;
|
|
7294
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
7295
|
+
}
|
|
7262
7296
|
async function waitForWorkerReady(options, ctx, state) {
|
|
7297
|
+
const startedAt = Date.now();
|
|
7298
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
7299
|
+
let consecutiveFailures = 0;
|
|
7263
7300
|
while (true) {
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7301
|
+
let requestFailed = false;
|
|
7302
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
7303
|
+
requestFailed = true;
|
|
7304
|
+
return {
|
|
7305
|
+
ready: false,
|
|
7306
|
+
status: error instanceof Error ? error.message : String(error),
|
|
7307
|
+
retryAfterMs: 1000
|
|
7308
|
+
};
|
|
7309
|
+
});
|
|
7269
7310
|
if (session.ready === false) {
|
|
7311
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
7270
7312
|
const status = String(session.status ?? "starting");
|
|
7271
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
7272
|
-
updatePiUi(ctx, state);
|
|
7273
7313
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
7274
|
-
|
|
7314
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
7315
|
+
return false;
|
|
7316
|
+
}
|
|
7317
|
+
if (consecutiveFailures >= 5) {
|
|
7318
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
7319
|
+
} else {
|
|
7320
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
7321
|
+
}
|
|
7322
|
+
updatePiUi(ctx, state);
|
|
7323
|
+
if (Date.now() >= deadline) {
|
|
7324
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
7275
7325
|
return false;
|
|
7276
7326
|
}
|
|
7277
7327
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -7479,7 +7529,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7479
7529
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
7480
7530
|
state.nativeStream = nativePiUiContextAvailable;
|
|
7481
7531
|
updatePiUi(ctx, state);
|
|
7482
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
7532
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
7483
7533
|
ctx.ui.onTerminalInput((data) => {
|
|
7484
7534
|
if (data.includes("\x04")) {
|
|
7485
7535
|
ctx.shutdown();
|
package/dist/src/index.js
CHANGED
|
@@ -7116,7 +7116,23 @@ function createPiRunStreamRenderer(output = process.stdout) {
|
|
|
7116
7116
|
}
|
|
7117
7117
|
if (entry.type === "timeline_warning") {
|
|
7118
7118
|
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
7119
|
+
continue;
|
|
7120
|
+
}
|
|
7121
|
+
if (entry.type === "action") {
|
|
7122
|
+
const text2 = String(entry.detail ?? entry.message ?? entry.title ?? "").trim();
|
|
7123
|
+
if (text2)
|
|
7124
|
+
writeLine(`[Rig action] ${text2}`);
|
|
7125
|
+
continue;
|
|
7119
7126
|
}
|
|
7127
|
+
if (entry.type === "user_message") {
|
|
7128
|
+
const text2 = String(entry.text ?? entry.message ?? entry.detail ?? "").trim();
|
|
7129
|
+
if (text2)
|
|
7130
|
+
writeLine(`[Operator] ${text2}`);
|
|
7131
|
+
continue;
|
|
7132
|
+
}
|
|
7133
|
+
const fallback = String(entry.detail ?? entry.message ?? entry.text ?? entry.title ?? "").trim();
|
|
7134
|
+
if (fallback)
|
|
7135
|
+
writeLine(`[${String(entry.type ?? "timeline")}] ${fallback}`);
|
|
7120
7136
|
}
|
|
7121
7137
|
},
|
|
7122
7138
|
renderLogs(entries) {
|
|
@@ -7269,12 +7285,12 @@ function parseExtensionUiRequest(value) {
|
|
|
7269
7285
|
}
|
|
7270
7286
|
function renderBridgeWidget(state) {
|
|
7271
7287
|
const statusParts = [
|
|
7272
|
-
state.wsConnected ? "live
|
|
7288
|
+
state.wsConnected ? "live" : "connecting",
|
|
7273
7289
|
state.status,
|
|
7274
7290
|
state.model,
|
|
7275
7291
|
state.cwd
|
|
7276
7292
|
].filter(Boolean);
|
|
7277
|
-
const lines = [`
|
|
7293
|
+
const lines = [`Rig worker session \xB7 ${statusParts.join(" \xB7 ")}`];
|
|
7278
7294
|
if (state.activity)
|
|
7279
7295
|
lines.push(state.activity);
|
|
7280
7296
|
if (state.commands.length > 0) {
|
|
@@ -7284,27 +7300,35 @@ function renderBridgeWidget(state) {
|
|
|
7284
7300
|
if (state.transcript.length > 0) {
|
|
7285
7301
|
lines.push(...state.transcript.slice(-MAX_TRANSCRIPT_LINES));
|
|
7286
7302
|
} else {
|
|
7287
|
-
lines.push("Waiting for worker
|
|
7303
|
+
lines.push("Waiting for the worker session transcript\u2026 (/detach exits and leaves the worker running)");
|
|
7288
7304
|
}
|
|
7289
7305
|
if (state.pendingUi) {
|
|
7290
7306
|
lines.push("");
|
|
7291
|
-
lines.push(`
|
|
7307
|
+
lines.push(`Worker needs input \xB7 ${state.pendingUi.method}`);
|
|
7292
7308
|
lines.push(state.pendingUi.prompt);
|
|
7293
7309
|
state.pendingUi.options.forEach((option, index) => lines.push(`${index + 1}. ${option}`));
|
|
7294
|
-
lines.push("Reply in the
|
|
7310
|
+
lines.push("Reply in the editor below. /cancel dismisses this request.");
|
|
7295
7311
|
}
|
|
7296
7312
|
return lines;
|
|
7297
7313
|
}
|
|
7314
|
+
function reportBridgeError(ctx, state, message2) {
|
|
7315
|
+
appendTranscript(state, "Error", message2);
|
|
7316
|
+
state.status = message2;
|
|
7317
|
+
try {
|
|
7318
|
+
ctx.ui.notify(message2, "error");
|
|
7319
|
+
} catch {}
|
|
7320
|
+
updatePiUi(ctx, state);
|
|
7321
|
+
}
|
|
7298
7322
|
function updatePiUi(ctx, state) {
|
|
7299
|
-
ctx.ui.setTitle("
|
|
7300
|
-
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker
|
|
7323
|
+
ctx.ui.setTitle("Rig \xB7 worker session");
|
|
7324
|
+
ctx.ui.setStatus("rig-worker-pi", state.wsConnected ? "worker session live" : state.status);
|
|
7301
7325
|
syncNativeDisplayCwd(ctx, state);
|
|
7302
7326
|
if (state.nativeStream && nativePiUi(ctx)) {
|
|
7303
7327
|
ctx.ui.setWidget("rig-worker-pi-transcript", undefined);
|
|
7304
7328
|
return;
|
|
7305
7329
|
}
|
|
7306
7330
|
ctx.ui.setWorkingVisible(false);
|
|
7307
|
-
ctx.ui.setWidget("rig-worker-pi-transcript",
|
|
7331
|
+
ctx.ui.setWidget("rig-worker-pi-transcript", renderBridgeWidget(state), { placement: "aboveEditor" });
|
|
7308
7332
|
}
|
|
7309
7333
|
function applyStatus(state, payload) {
|
|
7310
7334
|
const status = recordOf(payload.status) ?? payload;
|
|
@@ -7449,19 +7473,45 @@ function applyEnvelope(ctx, state, envelopeValue) {
|
|
|
7449
7473
|
}
|
|
7450
7474
|
syncNativeDisplayCwd(ctx, state);
|
|
7451
7475
|
}
|
|
7476
|
+
function resolveAttachReadyTimeoutMs() {
|
|
7477
|
+
const raw = Number.parseInt(process.env.RIG_PI_ATTACH_TIMEOUT_MS ?? "", 10);
|
|
7478
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 10 * 60000;
|
|
7479
|
+
}
|
|
7480
|
+
function formatElapsed(sinceMs) {
|
|
7481
|
+
const totalSeconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
7482
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
7483
|
+
const seconds = totalSeconds % 60;
|
|
7484
|
+
return minutes > 0 ? `${minutes}m${String(seconds).padStart(2, "0")}s` : `${seconds}s`;
|
|
7485
|
+
}
|
|
7452
7486
|
async function waitForWorkerReady(options, ctx, state) {
|
|
7487
|
+
const startedAt = Date.now();
|
|
7488
|
+
const deadline = startedAt + resolveAttachReadyTimeoutMs();
|
|
7489
|
+
let consecutiveFailures = 0;
|
|
7453
7490
|
while (true) {
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7491
|
+
let requestFailed = false;
|
|
7492
|
+
const session = await getRunPiSessionViaServer(options.context, options.runId).catch((error) => {
|
|
7493
|
+
requestFailed = true;
|
|
7494
|
+
return {
|
|
7495
|
+
ready: false,
|
|
7496
|
+
status: error instanceof Error ? error.message : String(error),
|
|
7497
|
+
retryAfterMs: 1000
|
|
7498
|
+
};
|
|
7499
|
+
});
|
|
7459
7500
|
if (session.ready === false) {
|
|
7501
|
+
consecutiveFailures = requestFailed ? consecutiveFailures + 1 : 0;
|
|
7460
7502
|
const status = String(session.status ?? "starting");
|
|
7461
|
-
state.status = `waiting for worker Pi daemon \xB7 ${status}`;
|
|
7462
|
-
updatePiUi(ctx, state);
|
|
7463
7503
|
if (TERMINAL_RUN_STATUSES.has(status.toLowerCase())) {
|
|
7464
|
-
|
|
7504
|
+
reportBridgeError(ctx, state, `Run ended before worker Pi daemon became ready: ${status}. Inspect with \`rig run show ${options.runId}\`; restart with \`rig task run --task <id>\`.`);
|
|
7505
|
+
return false;
|
|
7506
|
+
}
|
|
7507
|
+
if (consecutiveFailures >= 5) {
|
|
7508
|
+
state.status = `Rig server unreachable \xB7 retrying (${formatElapsed(startedAt)}) \xB7 /detach to exit`;
|
|
7509
|
+
} else {
|
|
7510
|
+
state.status = `waiting for worker Pi daemon \xB7 ${status} \xB7 ${formatElapsed(startedAt)} \xB7 /detach to exit`;
|
|
7511
|
+
}
|
|
7512
|
+
updatePiUi(ctx, state);
|
|
7513
|
+
if (Date.now() >= deadline) {
|
|
7514
|
+
reportBridgeError(ctx, state, `Worker Pi daemon did not become ready within ${formatElapsed(startedAt)} (last status: ${status}). ` + `Check \`rig run show ${options.runId}\` and \`rig doctor\`; the run may have been restarted by a server deploy. ` + "Set RIG_PI_ATTACH_TIMEOUT_MS to wait longer.");
|
|
7465
7515
|
return false;
|
|
7466
7516
|
}
|
|
7467
7517
|
await Bun.sleep(typeof session.retryAfterMs === "number" ? session.retryAfterMs : 750);
|
|
@@ -7669,7 +7719,7 @@ function createRigWorkerPiBridgeExtension(options) {
|
|
|
7669
7719
|
nativePiUiContextAvailable = Boolean(nativePiUi(ctx));
|
|
7670
7720
|
state.nativeStream = nativePiUiContextAvailable;
|
|
7671
7721
|
updatePiUi(ctx, state);
|
|
7672
|
-
ctx.ui.notify(nativePiUiContextAvailable ? "Rig worker
|
|
7722
|
+
ctx.ui.notify(nativePiUiContextAvailable ? "Connected to the Rig worker session (native stream). /detach exits, /stop cancels the run." : "Connected to the Rig worker session (transcript view). /detach exits, /stop cancels the run.", "info");
|
|
7673
7723
|
ctx.ui.onTerminalInput((data) => {
|
|
7674
7724
|
if (data.includes("\x04")) {
|
|
7675
7725
|
ctx.shutdown();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/cli",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rig package",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@clack/prompts": "^1.2.0",
|
|
26
|
-
"@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.
|
|
27
|
-
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.
|
|
28
|
-
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.
|
|
29
|
-
"@rig/client": "npm:@h-rig/client@0.0.6-alpha.
|
|
30
|
-
"@rig/server": "npm:@h-rig/server@0.0.6-alpha.
|
|
26
|
+
"@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.34",
|
|
27
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.34",
|
|
28
|
+
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.34",
|
|
29
|
+
"@rig/client": "npm:@h-rig/client@0.0.6-alpha.34",
|
|
30
|
+
"@rig/server": "npm:@h-rig/server@0.0.6-alpha.34",
|
|
31
31
|
"picocolors": "^1.1.1"
|
|
32
32
|
}
|
|
33
33
|
}
|