@evident-ai/cli 3.5.0 → 3.5.1-dev.7db3e09
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/index.js +102 -56
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1158,7 +1158,7 @@ import ora4 from "ora";
|
|
|
1158
1158
|
import { select as select4 } from "@inquirer/prompts";
|
|
1159
1159
|
|
|
1160
1160
|
// src/lib/telemetry.ts
|
|
1161
|
-
var CLI_VERSION = (true ? "3.5.
|
|
1161
|
+
var CLI_VERSION = (true ? "3.5.1-dev.7db3e09" : void 0) ?? process.env.npm_package_version ?? "unknown";
|
|
1162
1162
|
function getCliVersion() {
|
|
1163
1163
|
return CLI_VERSION;
|
|
1164
1164
|
}
|
|
@@ -1630,12 +1630,18 @@ async function checkOpenCodeHealth(port) {
|
|
|
1630
1630
|
return { healthy: false, error: message };
|
|
1631
1631
|
}
|
|
1632
1632
|
}
|
|
1633
|
+
function bodyExcerpt(body) {
|
|
1634
|
+
const excerpt = body.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
1635
|
+
return excerpt ? ` (body="${excerpt}")` : " (empty body)";
|
|
1636
|
+
}
|
|
1633
1637
|
async function checkOpenCode2Health(port, password) {
|
|
1634
1638
|
try {
|
|
1635
|
-
const
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
+
const headers = {};
|
|
1640
|
+
if (password !== void 0) {
|
|
1641
|
+
headers.Authorization = buildOpenCodeBasicAuthHeader(password);
|
|
1642
|
+
}
|
|
1643
|
+
const response = await fetch(`http://127.0.0.1:${port}/api/health`, {
|
|
1644
|
+
headers,
|
|
1639
1645
|
signal: AbortSignal.timeout(2e3)
|
|
1640
1646
|
});
|
|
1641
1647
|
if (response.status === 401) {
|
|
@@ -1644,8 +1650,31 @@ async function checkOpenCode2Health(port, password) {
|
|
|
1644
1650
|
if (!response.ok) {
|
|
1645
1651
|
return { healthy: false, error: `HTTP ${response.status}` };
|
|
1646
1652
|
}
|
|
1647
|
-
const
|
|
1648
|
-
|
|
1653
|
+
const body = await response.text();
|
|
1654
|
+
const excerpt = bodyExcerpt(body);
|
|
1655
|
+
let data;
|
|
1656
|
+
try {
|
|
1657
|
+
data = JSON.parse(body);
|
|
1658
|
+
} catch (error2) {
|
|
1659
|
+
return {
|
|
1660
|
+
healthy: false,
|
|
1661
|
+
error: `Invalid JSON health response${excerpt}: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
1665
|
+
return {
|
|
1666
|
+
healthy: false,
|
|
1667
|
+
error: `Invalid health response${excerpt}: expected healthy=true`
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
const health = data;
|
|
1671
|
+
if (health.healthy !== true) {
|
|
1672
|
+
return {
|
|
1673
|
+
healthy: false,
|
|
1674
|
+
error: `Invalid health response${excerpt}: expected healthy=true`
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
return typeof health.version === "string" ? { healthy: true, version: health.version } : { healthy: true };
|
|
1649
1678
|
} catch (error2) {
|
|
1650
1679
|
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
1651
1680
|
return { healthy: false, error: message };
|
|
@@ -6399,6 +6428,7 @@ var DEFAULT_PAUSED_POLL_INTERVAL_MS = 2e3;
|
|
|
6399
6428
|
var DEFAULT_PAUSED_MAX_WAIT_MS = 10 * 60 * 1e3;
|
|
6400
6429
|
var DEFAULT_STUCK_QUEUED_MS = 6e4;
|
|
6401
6430
|
var HEARTBEAT_MS = 6e4;
|
|
6431
|
+
var ALIVE_WITHHELD_THRESHOLD_MS = 3 * HEARTBEAT_MS;
|
|
6402
6432
|
var ABSOLUTE_MAX_PROCESSING_MS = 6 * 60 * 60 * 1e3;
|
|
6403
6433
|
var B2_ABANDONMENT_MIN_PINNED_MS = 3 * 6e4;
|
|
6404
6434
|
var AMBIGUOUS_FINISH_MAX_PINNED_MS = 3 * 6e4;
|
|
@@ -7603,7 +7633,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7603
7633
|
return "dispatch";
|
|
7604
7634
|
}
|
|
7605
7635
|
}
|
|
7606
|
-
return this.reattachRedrive(conv, sessionId, message, ocId);
|
|
7636
|
+
return this.reattachRedrive(conv, sessionId, message, ocId, state);
|
|
7607
7637
|
}
|
|
7608
7638
|
if (ongoing === false) {
|
|
7609
7639
|
if (state === "running" && isAmbiguousFinishPinnedRunning(messages, ocId ?? "")) {
|
|
@@ -7620,11 +7650,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7620
7650
|
return "dispatch";
|
|
7621
7651
|
}
|
|
7622
7652
|
/**
|
|
7623
|
-
* The `reattached` outcome (Task 3.3):
|
|
7624
|
-
*
|
|
7625
|
-
*
|
|
7653
|
+
* The `reattached` outcome (Task 3.3): opencode's own status map says the session
|
|
7654
|
+
* is ongoing, so undo the false reclaim instead of starting a second turn. `state`
|
|
7655
|
+
* carries the correlated message's observed state so the outcome does not claim
|
|
7656
|
+
* that a queued message's own turn was already running.
|
|
7626
7657
|
*/
|
|
7627
|
-
async reattachRedrive(conv, sessionId, message, ocId) {
|
|
7658
|
+
async reattachRedrive(conv, sessionId, message, ocId, state) {
|
|
7628
7659
|
let anchorMs;
|
|
7629
7660
|
const parsed = message.processing_started_at ? Date.parse(message.processing_started_at) : NaN;
|
|
7630
7661
|
if (!Number.isNaN(parsed)) {
|
|
@@ -7633,7 +7664,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7633
7664
|
anchorMs = this.now();
|
|
7634
7665
|
this.log({
|
|
7635
7666
|
level: "warn",
|
|
7636
|
-
message: `Re-drive: message ${message.id.slice(0, 8)} has
|
|
7667
|
+
message: `Re-drive: message ${message.id.slice(0, 8)} has no usable processing_started_at (${String(message.processing_started_at)}) \u2014 anchoring the watcher's absolute-age ceiling to now`,
|
|
7637
7668
|
conversation_id: conv.id,
|
|
7638
7669
|
message_id: message.id
|
|
7639
7670
|
});
|
|
@@ -7662,17 +7693,19 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7662
7693
|
return bound === "abandoned" ? "abandoned" : "unresolved";
|
|
7663
7694
|
}
|
|
7664
7695
|
this.clearRedriveUnresolved(message.id);
|
|
7665
|
-
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs);
|
|
7696
|
+
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs, this.now());
|
|
7666
7697
|
this.dispatched.add(message.id);
|
|
7667
7698
|
this.readopted.add(message.id);
|
|
7668
|
-
this.ensureWatcherRunning(sessionId);
|
|
7699
|
+
const watcherState = this.ensureWatcherRunning(sessionId);
|
|
7669
7700
|
const watchedForMs = this.now() - anchorMs;
|
|
7670
7701
|
void this.postSignal(conv.id, message.id, "redrive_reattached", {
|
|
7671
|
-
watched_for_ms: watchedForMs
|
|
7702
|
+
watched_for_ms: watchedForMs,
|
|
7703
|
+
run_state: state,
|
|
7704
|
+
watcher_state: watcherState
|
|
7672
7705
|
});
|
|
7673
7706
|
this.log({
|
|
7674
7707
|
level: "warn",
|
|
7675
|
-
message: `Re-drive: message ${message.id.slice(0, 8)} (session ${sessionId.slice(0, 8)}) was wrongly reclaimed to pending while its turn was still running (watched ${watchedForMs}ms) \u2014 restored to processing instead of re-dispatching`,
|
|
7708
|
+
message: state === "running" ? `Re-drive: message ${message.id.slice(0, 8)} (session ${sessionId.slice(0, 8)}) was wrongly reclaimed to pending while its turn was still running (watched ${watchedForMs}ms) \u2014 restored to processing instead of re-dispatching` : `Re-drive: message ${message.id.slice(0, 8)} (session ${sessionId.slice(0, 8)}) was reclaimed to pending while its own turn had not started and the session was busy (watched ${watchedForMs}ms) \u2014 restored to processing instead of re-dispatching to avoid a duplicate`,
|
|
7676
7709
|
conversation_id: conv.id,
|
|
7677
7710
|
message_id: message.id
|
|
7678
7711
|
});
|
|
@@ -8279,6 +8312,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8279
8312
|
stuckReported: false,
|
|
8280
8313
|
lastAliveAt: 0,
|
|
8281
8314
|
aliveInFlight: false,
|
|
8315
|
+
aliveWithheldSignalled: false,
|
|
8282
8316
|
titleSynced: false,
|
|
8283
8317
|
titleSyncInFlight: false,
|
|
8284
8318
|
awaitingHumanLatched: false,
|
|
@@ -8338,9 +8372,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8338
8372
|
/**
|
|
8339
8373
|
* Register a RE-ADOPTED `processing` message with its session watcher
|
|
8340
8374
|
* (ADR-0046, WI-4). Mirrors `registerInFlight` but anchors the give-up
|
|
8341
|
-
* `deadline` to the
|
|
8342
|
-
* `
|
|
8343
|
-
*
|
|
8375
|
+
* `deadline` to the attempt's SERVER-SIDE `processed_at` (Invariant 1), while
|
|
8376
|
+
* `processingAnchorMs` keeps the absolute-age ceiling tied to the original turn.
|
|
8377
|
+
* The deadline tracks THIS attempt; the ceiling tracks THE TURN. For a fresh
|
|
8378
|
+
* dispatch both anchors are `now`; a restart re-adopt passes the server's
|
|
8379
|
+
* `processed_at` for both, while a re-drive passes the newly stamped attempt time
|
|
8380
|
+
* only for the deadline.
|
|
8344
8381
|
*
|
|
8345
8382
|
* This re-attaches into the SAME watcher, so the ADR-0047 progressing-vs-paused
|
|
8346
8383
|
* give-up (`serviceInFlightMessage`) applies unchanged: a re-adopted turn
|
|
@@ -8361,7 +8398,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8361
8398
|
* server already flipped to `processing`; the running/done transitions still
|
|
8362
8399
|
* fire from the watcher's normal branches.
|
|
8363
8400
|
*/
|
|
8364
|
-
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs) {
|
|
8401
|
+
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs, watchDeadlineAnchorMs) {
|
|
8365
8402
|
let watcher = this.watchers.get(sessionId);
|
|
8366
8403
|
if (!watcher) {
|
|
8367
8404
|
watcher = this.newSessionWatcher(conv);
|
|
@@ -8372,11 +8409,11 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8372
8409
|
opencodeMessageId,
|
|
8373
8410
|
message,
|
|
8374
8411
|
dispatchedAt: this.now(),
|
|
8375
|
-
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at
|
|
8376
|
-
//
|
|
8377
|
-
//
|
|
8412
|
+
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at`, NOT
|
|
8413
|
+
// `dispatchedAt` — so a re-adopted zombie's age reflects the real turn duration
|
|
8414
|
+
// and the ceiling fires on the ORIGINAL turn.
|
|
8378
8415
|
processingAnchorMs: processedAtMs,
|
|
8379
|
-
deadline:
|
|
8416
|
+
deadline: watchDeadlineAnchorMs + this.pausedMaxWaitMs,
|
|
8380
8417
|
// The server row is ALREADY `processing`; do not re-fire markProcessing.
|
|
8381
8418
|
started: true,
|
|
8382
8419
|
done: false,
|
|
@@ -8393,6 +8430,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8393
8430
|
// with no extra `re_adopted` signal needed (folds old WI-6).
|
|
8394
8431
|
lastAliveAt: 0,
|
|
8395
8432
|
aliveInFlight: false,
|
|
8433
|
+
aliveWithheldSignalled: false,
|
|
8396
8434
|
titleSynced: false,
|
|
8397
8435
|
titleSyncInFlight: false,
|
|
8398
8436
|
awaitingHumanLatched: false,
|
|
@@ -8509,6 +8547,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8509
8547
|
* tracked on the watcher and cleared when it settles; it never rejects (fully
|
|
8510
8548
|
* guarded), so a failed poll/callback can never crash the run loop — the cron
|
|
8511
8549
|
* stays as the safety net.
|
|
8550
|
+
* Returns the branch taken so re-attach telemetry can show whether it left a
|
|
8551
|
+
* ticking loop behind.
|
|
8512
8552
|
*
|
|
8513
8553
|
* The generation started here (#1618) is captured in the `.finally` closure
|
|
8514
8554
|
* so a RETIRED loop settling late — after `reconcileWatchers` has already
|
|
@@ -8522,7 +8562,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8522
8562
|
level: "debug",
|
|
8523
8563
|
message: `No watcher entry exists for session ${sessionId} \u2014 nothing to do`
|
|
8524
8564
|
});
|
|
8525
|
-
return;
|
|
8565
|
+
return "no_watcher";
|
|
8526
8566
|
}
|
|
8527
8567
|
this.ensureSessionErrorStream();
|
|
8528
8568
|
if (watcher.loop) {
|
|
@@ -8531,7 +8571,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8531
8571
|
message: `Watcher loop already running for session ${sessionId}; no-op with ${watcher.inFlight.size} message(s) in flight`,
|
|
8532
8572
|
conversation_id: watcher.conv.id
|
|
8533
8573
|
});
|
|
8534
|
-
return;
|
|
8574
|
+
return "already_running";
|
|
8535
8575
|
}
|
|
8536
8576
|
if (watcher.inFlight.size === 0) {
|
|
8537
8577
|
this.log({
|
|
@@ -8540,7 +8580,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8540
8580
|
conversation_id: watcher.conv.id
|
|
8541
8581
|
});
|
|
8542
8582
|
this.watchers.delete(sessionId);
|
|
8543
|
-
return;
|
|
8583
|
+
return "no_in_flight";
|
|
8544
8584
|
}
|
|
8545
8585
|
const generation = watcher.generation;
|
|
8546
8586
|
this.log({
|
|
@@ -8556,6 +8596,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8556
8596
|
}
|
|
8557
8597
|
});
|
|
8558
8598
|
watcher.loop = loop;
|
|
8599
|
+
return "started";
|
|
8559
8600
|
}
|
|
8560
8601
|
ensureSessionErrorStream() {
|
|
8561
8602
|
if (this.sessionErrorStream || this.stopped) return;
|
|
@@ -9081,7 +9122,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9081
9122
|
this.removeInFlight(watcher, inFlight.evidentMessageId);
|
|
9082
9123
|
return;
|
|
9083
9124
|
}
|
|
9084
|
-
|
|
9125
|
+
const heartbeatDue = activelyRunning && !inFlight.awaitingHumanLatched && !inFlight.aliveInFlight && this.now() - inFlight.lastAliveAt >= HEARTBEAT_MS;
|
|
9126
|
+
if (heartbeatDue) {
|
|
9085
9127
|
inFlight.aliveInFlight = true;
|
|
9086
9128
|
this.log({
|
|
9087
9129
|
level: "debug",
|
|
@@ -9091,7 +9133,10 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9091
9133
|
});
|
|
9092
9134
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive").then((ok) => {
|
|
9093
9135
|
inFlight.aliveInFlight = false;
|
|
9094
|
-
if (ok)
|
|
9136
|
+
if (ok) {
|
|
9137
|
+
inFlight.lastAliveAt = this.now();
|
|
9138
|
+
inFlight.aliveWithheldSignalled = false;
|
|
9139
|
+
}
|
|
9095
9140
|
this.log({
|
|
9096
9141
|
level: "debug",
|
|
9097
9142
|
message: `Heartbeat POST for message ${inFlight.evidentMessageId} in session ${sessionId} completed with ok=${ok}`,
|
|
@@ -9143,6 +9188,16 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9143
9188
|
inFlight.pausedOnPermission = false;
|
|
9144
9189
|
inFlight.pausedClearConfirmed = false;
|
|
9145
9190
|
}
|
|
9191
|
+
const watchedForMs = this.now() - Math.max(inFlight.lastAliveAt, inFlight.dispatchedAt);
|
|
9192
|
+
if (!heartbeatDue && !inFlight.aliveWithheldSignalled && watchedForMs >= ALIVE_WITHHELD_THRESHOLD_MS) {
|
|
9193
|
+
inFlight.aliveWithheldSignalled = true;
|
|
9194
|
+
const reason = inFlight.awaitingHumanLatched ? "awaiting_human" : inFlight.aliveInFlight ? "alive_in_flight" : "not_running";
|
|
9195
|
+
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive_withheld", {
|
|
9196
|
+
reason,
|
|
9197
|
+
run_state: state,
|
|
9198
|
+
watched_for_ms: watchedForMs
|
|
9199
|
+
});
|
|
9200
|
+
}
|
|
9146
9201
|
const siblingPaused = (sib) => openQuestions.has(sib.evidentMessageId) || openPermissions.has(sib.evidentMessageId) || sib.awaitingHumanLatched || sib.pausedOnQuestion || sib.pausedOnPermission;
|
|
9147
9202
|
const hasActivelyRunningSibling = [...watcher.inFlight.values()].some(
|
|
9148
9203
|
(sib) => sib.evidentMessageId !== inFlight.evidentMessageId && messageRunState(messages, sib.opencodeMessageId) === "running" && !siblingPaused(sib)
|
|
@@ -9153,15 +9208,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9153
9208
|
const attempts = this.recordNeverStartedAttempt(id, sessionId);
|
|
9154
9209
|
if (attempts >= MAX_NEVER_STARTED_ATTEMPTS) {
|
|
9155
9210
|
inFlight.neverStartedResolved = true;
|
|
9156
|
-
const
|
|
9211
|
+
const watchedForMs2 = this.now() - inFlight.dispatchedAt;
|
|
9157
9212
|
this.log({
|
|
9158
9213
|
level: "error",
|
|
9159
|
-
message: `Message ${id.slice(0, 8)} never started after ${attempts} attempts (${
|
|
9214
|
+
message: `Message ${id.slice(0, 8)} never started after ${attempts} attempts (${watchedForMs2}ms watched) \u2014 reporting the run failed; the accepted OpenCode copy was not cancelled`,
|
|
9160
9215
|
conversation_id: conv.id,
|
|
9161
9216
|
message_id: id
|
|
9162
9217
|
});
|
|
9163
9218
|
void this.postSignal(conv.id, id, "never_started_failed", {
|
|
9164
|
-
watched_for_ms:
|
|
9219
|
+
watched_for_ms: watchedForMs2,
|
|
9165
9220
|
attempts
|
|
9166
9221
|
});
|
|
9167
9222
|
await this.settleMessageNeverStarted(sessionId, watcher, inFlight, attempts);
|
|
@@ -9175,7 +9230,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9175
9230
|
message_id: inFlight.evidentMessageId
|
|
9176
9231
|
});
|
|
9177
9232
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "gave_up", {
|
|
9178
|
-
watched_for_ms: this.now() - inFlight.dispatchedAt
|
|
9233
|
+
watched_for_ms: this.now() - inFlight.dispatchedAt,
|
|
9234
|
+
run_state: state
|
|
9179
9235
|
});
|
|
9180
9236
|
this.recordReleasedOpencodeId(
|
|
9181
9237
|
inFlight.evidentMessageId,
|
|
@@ -9632,7 +9688,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9632
9688
|
if ((state === "running" || state === "queued") && ocId) {
|
|
9633
9689
|
const conv = this.convForRow(sessionId, row);
|
|
9634
9690
|
const message = this.queuedMessageForRow(row);
|
|
9635
|
-
|
|
9691
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9692
|
+
this.registerReadopted(conv, sessionId, message, ocId, processedAtMs, processedAtMs);
|
|
9636
9693
|
this.dispatched.add(row.id);
|
|
9637
9694
|
this.readopted.add(row.id);
|
|
9638
9695
|
this.ensureWatcherRunning(sessionId);
|
|
@@ -9927,7 +9984,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9927
9984
|
return;
|
|
9928
9985
|
}
|
|
9929
9986
|
this.unconfirmedDispatchFailures.delete(row.id);
|
|
9930
|
-
|
|
9987
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9988
|
+
this.registerReadopted(
|
|
9989
|
+
readoptConv,
|
|
9990
|
+
sessionId,
|
|
9991
|
+
readoptMessage,
|
|
9992
|
+
ocId,
|
|
9993
|
+
processedAtMs,
|
|
9994
|
+
processedAtMs
|
|
9995
|
+
);
|
|
9931
9996
|
this.dispatched.add(row.id);
|
|
9932
9997
|
this.readopted.add(row.id);
|
|
9933
9998
|
this.awaitingReadopt.delete(row.id);
|
|
@@ -11347,25 +11412,6 @@ Port ${port} is already in use.`));
|
|
|
11347
11412
|
import chalk6 from "chalk";
|
|
11348
11413
|
import ora3 from "ora";
|
|
11349
11414
|
import { select as select3 } from "@inquirer/prompts";
|
|
11350
|
-
async function probeOpenCode2WithoutPassword(port) {
|
|
11351
|
-
try {
|
|
11352
|
-
const response = await fetch(`http://127.0.0.1:${port}/global/health`, {
|
|
11353
|
-
signal: AbortSignal.timeout(2e3)
|
|
11354
|
-
});
|
|
11355
|
-
if (response.status === 401) {
|
|
11356
|
-
return { healthy: false, authFailed: true, error: "HTTP 401" };
|
|
11357
|
-
}
|
|
11358
|
-
if (!response.ok) {
|
|
11359
|
-
return { healthy: false, error: `HTTP ${response.status}` };
|
|
11360
|
-
}
|
|
11361
|
-
return { healthy: true };
|
|
11362
|
-
} catch (error2) {
|
|
11363
|
-
return {
|
|
11364
|
-
healthy: false,
|
|
11365
|
-
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
11366
|
-
};
|
|
11367
|
-
}
|
|
11368
|
-
}
|
|
11369
11415
|
function unknownPasswordError(port) {
|
|
11370
11416
|
return new Error(
|
|
11371
11417
|
`OpenCode V2 (opencode2) is already running on port ${port} with a password this runner doesn't know. Free the port or pass --port.`
|
|
@@ -11373,7 +11419,7 @@ function unknownPasswordError(port) {
|
|
|
11373
11419
|
}
|
|
11374
11420
|
var INTERACTIVE_START_TIMEOUT_MS2 = 3e4;
|
|
11375
11421
|
async function ensureOpenCode2Running(ctx) {
|
|
11376
|
-
const initialHealth = await
|
|
11422
|
+
const initialHealth = await checkOpenCode2Health(ctx.port);
|
|
11377
11423
|
if (initialHealth.authFailed) {
|
|
11378
11424
|
throw unknownPasswordError(ctx.port);
|
|
11379
11425
|
}
|