@evident-ai/cli 3.5.0 → 3.5.1-dev.18543a6
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 +108 -59
- 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.18543a6" : 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 };
|
|
@@ -4282,6 +4311,9 @@ function isSessionDbProvenanceRecord(value) {
|
|
|
4282
4311
|
return typeof record.opencodeVersion === "string" && Array.isArray(record.migrationIds) && record.migrationIds.every((id) => typeof id === "string") && typeof record.updatedAt === "string";
|
|
4283
4312
|
}
|
|
4284
4313
|
|
|
4314
|
+
// src/lib/opencode/opencode2-package.ts
|
|
4315
|
+
var OPENCODE2_PACKAGE_SPEC = "@opencode-ai/cli@0.0.0-beta-17823";
|
|
4316
|
+
|
|
4285
4317
|
// src/lib/opencode/opencode-version-gate.ts
|
|
4286
4318
|
var QUEUE_VALIDATED_OPENCODE_VERSIONS = ["1.17.11", "1.18.3"];
|
|
4287
4319
|
function isQueueValidatedVersion(version2) {
|
|
@@ -4588,7 +4620,7 @@ async function startOpenCode2(port, options = {}) {
|
|
|
4588
4620
|
args = [
|
|
4589
4621
|
"-y",
|
|
4590
4622
|
"-p",
|
|
4591
|
-
|
|
4623
|
+
OPENCODE2_PACKAGE_SPEC,
|
|
4592
4624
|
"--",
|
|
4593
4625
|
"opencode2",
|
|
4594
4626
|
"serve",
|
|
@@ -4665,7 +4697,7 @@ async function promptOpenCodeInstall(interactive) {
|
|
|
4665
4697
|
npm: "npm install -g opencode-ai",
|
|
4666
4698
|
curl: "curl -fsSL https://opencode.ai/install.sh | sh",
|
|
4667
4699
|
v2: {
|
|
4668
|
-
npm:
|
|
4700
|
+
npm: `npm install -g ${OPENCODE2_PACKAGE_SPEC}`,
|
|
4669
4701
|
curl: "curl -fsSL https://opencode.ai/v2/install | bash"
|
|
4670
4702
|
}
|
|
4671
4703
|
}
|
|
@@ -6399,6 +6431,7 @@ var DEFAULT_PAUSED_POLL_INTERVAL_MS = 2e3;
|
|
|
6399
6431
|
var DEFAULT_PAUSED_MAX_WAIT_MS = 10 * 60 * 1e3;
|
|
6400
6432
|
var DEFAULT_STUCK_QUEUED_MS = 6e4;
|
|
6401
6433
|
var HEARTBEAT_MS = 6e4;
|
|
6434
|
+
var ALIVE_WITHHELD_THRESHOLD_MS = 3 * HEARTBEAT_MS;
|
|
6402
6435
|
var ABSOLUTE_MAX_PROCESSING_MS = 6 * 60 * 60 * 1e3;
|
|
6403
6436
|
var B2_ABANDONMENT_MIN_PINNED_MS = 3 * 6e4;
|
|
6404
6437
|
var AMBIGUOUS_FINISH_MAX_PINNED_MS = 3 * 6e4;
|
|
@@ -7603,7 +7636,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7603
7636
|
return "dispatch";
|
|
7604
7637
|
}
|
|
7605
7638
|
}
|
|
7606
|
-
return this.reattachRedrive(conv, sessionId, message, ocId);
|
|
7639
|
+
return this.reattachRedrive(conv, sessionId, message, ocId, state);
|
|
7607
7640
|
}
|
|
7608
7641
|
if (ongoing === false) {
|
|
7609
7642
|
if (state === "running" && isAmbiguousFinishPinnedRunning(messages, ocId ?? "")) {
|
|
@@ -7620,11 +7653,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7620
7653
|
return "dispatch";
|
|
7621
7654
|
}
|
|
7622
7655
|
/**
|
|
7623
|
-
* The `reattached` outcome (Task 3.3):
|
|
7624
|
-
*
|
|
7625
|
-
*
|
|
7656
|
+
* The `reattached` outcome (Task 3.3): opencode's own status map says the session
|
|
7657
|
+
* is ongoing, so undo the false reclaim instead of starting a second turn. `state`
|
|
7658
|
+
* carries the correlated message's observed state so the outcome does not claim
|
|
7659
|
+
* that a queued message's own turn was already running.
|
|
7626
7660
|
*/
|
|
7627
|
-
async reattachRedrive(conv, sessionId, message, ocId) {
|
|
7661
|
+
async reattachRedrive(conv, sessionId, message, ocId, state) {
|
|
7628
7662
|
let anchorMs;
|
|
7629
7663
|
const parsed = message.processing_started_at ? Date.parse(message.processing_started_at) : NaN;
|
|
7630
7664
|
if (!Number.isNaN(parsed)) {
|
|
@@ -7633,7 +7667,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7633
7667
|
anchorMs = this.now();
|
|
7634
7668
|
this.log({
|
|
7635
7669
|
level: "warn",
|
|
7636
|
-
message: `Re-drive: message ${message.id.slice(0, 8)} has
|
|
7670
|
+
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
7671
|
conversation_id: conv.id,
|
|
7638
7672
|
message_id: message.id
|
|
7639
7673
|
});
|
|
@@ -7662,17 +7696,19 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7662
7696
|
return bound === "abandoned" ? "abandoned" : "unresolved";
|
|
7663
7697
|
}
|
|
7664
7698
|
this.clearRedriveUnresolved(message.id);
|
|
7665
|
-
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs);
|
|
7699
|
+
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs, this.now());
|
|
7666
7700
|
this.dispatched.add(message.id);
|
|
7667
7701
|
this.readopted.add(message.id);
|
|
7668
|
-
this.ensureWatcherRunning(sessionId);
|
|
7702
|
+
const watcherState = this.ensureWatcherRunning(sessionId);
|
|
7669
7703
|
const watchedForMs = this.now() - anchorMs;
|
|
7670
7704
|
void this.postSignal(conv.id, message.id, "redrive_reattached", {
|
|
7671
|
-
watched_for_ms: watchedForMs
|
|
7705
|
+
watched_for_ms: watchedForMs,
|
|
7706
|
+
run_state: state,
|
|
7707
|
+
watcher_state: watcherState
|
|
7672
7708
|
});
|
|
7673
7709
|
this.log({
|
|
7674
7710
|
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`,
|
|
7711
|
+
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
7712
|
conversation_id: conv.id,
|
|
7677
7713
|
message_id: message.id
|
|
7678
7714
|
});
|
|
@@ -8279,6 +8315,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8279
8315
|
stuckReported: false,
|
|
8280
8316
|
lastAliveAt: 0,
|
|
8281
8317
|
aliveInFlight: false,
|
|
8318
|
+
aliveWithheldSignalled: false,
|
|
8282
8319
|
titleSynced: false,
|
|
8283
8320
|
titleSyncInFlight: false,
|
|
8284
8321
|
awaitingHumanLatched: false,
|
|
@@ -8338,9 +8375,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8338
8375
|
/**
|
|
8339
8376
|
* Register a RE-ADOPTED `processing` message with its session watcher
|
|
8340
8377
|
* (ADR-0046, WI-4). Mirrors `registerInFlight` but anchors the give-up
|
|
8341
|
-
* `deadline` to the
|
|
8342
|
-
* `
|
|
8343
|
-
*
|
|
8378
|
+
* `deadline` to the attempt's SERVER-SIDE `processed_at` (Invariant 1), while
|
|
8379
|
+
* `processingAnchorMs` keeps the absolute-age ceiling tied to the original turn.
|
|
8380
|
+
* The deadline tracks THIS attempt; the ceiling tracks THE TURN. For a fresh
|
|
8381
|
+
* dispatch both anchors are `now`; a restart re-adopt passes the server's
|
|
8382
|
+
* `processed_at` for both, while a re-drive passes the newly stamped attempt time
|
|
8383
|
+
* only for the deadline.
|
|
8344
8384
|
*
|
|
8345
8385
|
* This re-attaches into the SAME watcher, so the ADR-0047 progressing-vs-paused
|
|
8346
8386
|
* give-up (`serviceInFlightMessage`) applies unchanged: a re-adopted turn
|
|
@@ -8361,7 +8401,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8361
8401
|
* server already flipped to `processing`; the running/done transitions still
|
|
8362
8402
|
* fire from the watcher's normal branches.
|
|
8363
8403
|
*/
|
|
8364
|
-
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs) {
|
|
8404
|
+
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs, watchDeadlineAnchorMs) {
|
|
8365
8405
|
let watcher = this.watchers.get(sessionId);
|
|
8366
8406
|
if (!watcher) {
|
|
8367
8407
|
watcher = this.newSessionWatcher(conv);
|
|
@@ -8372,11 +8412,11 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8372
8412
|
opencodeMessageId,
|
|
8373
8413
|
message,
|
|
8374
8414
|
dispatchedAt: this.now(),
|
|
8375
|
-
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at
|
|
8376
|
-
//
|
|
8377
|
-
//
|
|
8415
|
+
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at`, NOT
|
|
8416
|
+
// `dispatchedAt` — so a re-adopted zombie's age reflects the real turn duration
|
|
8417
|
+
// and the ceiling fires on the ORIGINAL turn.
|
|
8378
8418
|
processingAnchorMs: processedAtMs,
|
|
8379
|
-
deadline:
|
|
8419
|
+
deadline: watchDeadlineAnchorMs + this.pausedMaxWaitMs,
|
|
8380
8420
|
// The server row is ALREADY `processing`; do not re-fire markProcessing.
|
|
8381
8421
|
started: true,
|
|
8382
8422
|
done: false,
|
|
@@ -8393,6 +8433,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8393
8433
|
// with no extra `re_adopted` signal needed (folds old WI-6).
|
|
8394
8434
|
lastAliveAt: 0,
|
|
8395
8435
|
aliveInFlight: false,
|
|
8436
|
+
aliveWithheldSignalled: false,
|
|
8396
8437
|
titleSynced: false,
|
|
8397
8438
|
titleSyncInFlight: false,
|
|
8398
8439
|
awaitingHumanLatched: false,
|
|
@@ -8509,6 +8550,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8509
8550
|
* tracked on the watcher and cleared when it settles; it never rejects (fully
|
|
8510
8551
|
* guarded), so a failed poll/callback can never crash the run loop — the cron
|
|
8511
8552
|
* stays as the safety net.
|
|
8553
|
+
* Returns the branch taken so re-attach telemetry can show whether it left a
|
|
8554
|
+
* ticking loop behind.
|
|
8512
8555
|
*
|
|
8513
8556
|
* The generation started here (#1618) is captured in the `.finally` closure
|
|
8514
8557
|
* so a RETIRED loop settling late — after `reconcileWatchers` has already
|
|
@@ -8522,7 +8565,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8522
8565
|
level: "debug",
|
|
8523
8566
|
message: `No watcher entry exists for session ${sessionId} \u2014 nothing to do`
|
|
8524
8567
|
});
|
|
8525
|
-
return;
|
|
8568
|
+
return "no_watcher";
|
|
8526
8569
|
}
|
|
8527
8570
|
this.ensureSessionErrorStream();
|
|
8528
8571
|
if (watcher.loop) {
|
|
@@ -8531,7 +8574,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8531
8574
|
message: `Watcher loop already running for session ${sessionId}; no-op with ${watcher.inFlight.size} message(s) in flight`,
|
|
8532
8575
|
conversation_id: watcher.conv.id
|
|
8533
8576
|
});
|
|
8534
|
-
return;
|
|
8577
|
+
return "already_running";
|
|
8535
8578
|
}
|
|
8536
8579
|
if (watcher.inFlight.size === 0) {
|
|
8537
8580
|
this.log({
|
|
@@ -8540,7 +8583,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8540
8583
|
conversation_id: watcher.conv.id
|
|
8541
8584
|
});
|
|
8542
8585
|
this.watchers.delete(sessionId);
|
|
8543
|
-
return;
|
|
8586
|
+
return "no_in_flight";
|
|
8544
8587
|
}
|
|
8545
8588
|
const generation = watcher.generation;
|
|
8546
8589
|
this.log({
|
|
@@ -8556,6 +8599,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8556
8599
|
}
|
|
8557
8600
|
});
|
|
8558
8601
|
watcher.loop = loop;
|
|
8602
|
+
return "started";
|
|
8559
8603
|
}
|
|
8560
8604
|
ensureSessionErrorStream() {
|
|
8561
8605
|
if (this.sessionErrorStream || this.stopped) return;
|
|
@@ -9081,7 +9125,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9081
9125
|
this.removeInFlight(watcher, inFlight.evidentMessageId);
|
|
9082
9126
|
return;
|
|
9083
9127
|
}
|
|
9084
|
-
|
|
9128
|
+
const heartbeatDue = activelyRunning && !inFlight.awaitingHumanLatched && !inFlight.aliveInFlight && this.now() - inFlight.lastAliveAt >= HEARTBEAT_MS;
|
|
9129
|
+
if (heartbeatDue) {
|
|
9085
9130
|
inFlight.aliveInFlight = true;
|
|
9086
9131
|
this.log({
|
|
9087
9132
|
level: "debug",
|
|
@@ -9091,7 +9136,10 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9091
9136
|
});
|
|
9092
9137
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive").then((ok) => {
|
|
9093
9138
|
inFlight.aliveInFlight = false;
|
|
9094
|
-
if (ok)
|
|
9139
|
+
if (ok) {
|
|
9140
|
+
inFlight.lastAliveAt = this.now();
|
|
9141
|
+
inFlight.aliveWithheldSignalled = false;
|
|
9142
|
+
}
|
|
9095
9143
|
this.log({
|
|
9096
9144
|
level: "debug",
|
|
9097
9145
|
message: `Heartbeat POST for message ${inFlight.evidentMessageId} in session ${sessionId} completed with ok=${ok}`,
|
|
@@ -9143,6 +9191,16 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9143
9191
|
inFlight.pausedOnPermission = false;
|
|
9144
9192
|
inFlight.pausedClearConfirmed = false;
|
|
9145
9193
|
}
|
|
9194
|
+
const watchedForMs = this.now() - Math.max(inFlight.lastAliveAt, inFlight.dispatchedAt);
|
|
9195
|
+
if (!heartbeatDue && !inFlight.aliveWithheldSignalled && watchedForMs >= ALIVE_WITHHELD_THRESHOLD_MS) {
|
|
9196
|
+
inFlight.aliveWithheldSignalled = true;
|
|
9197
|
+
const reason = inFlight.awaitingHumanLatched ? "awaiting_human" : inFlight.aliveInFlight ? "alive_in_flight" : "not_running";
|
|
9198
|
+
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive_withheld", {
|
|
9199
|
+
reason,
|
|
9200
|
+
run_state: state,
|
|
9201
|
+
watched_for_ms: watchedForMs
|
|
9202
|
+
});
|
|
9203
|
+
}
|
|
9146
9204
|
const siblingPaused = (sib) => openQuestions.has(sib.evidentMessageId) || openPermissions.has(sib.evidentMessageId) || sib.awaitingHumanLatched || sib.pausedOnQuestion || sib.pausedOnPermission;
|
|
9147
9205
|
const hasActivelyRunningSibling = [...watcher.inFlight.values()].some(
|
|
9148
9206
|
(sib) => sib.evidentMessageId !== inFlight.evidentMessageId && messageRunState(messages, sib.opencodeMessageId) === "running" && !siblingPaused(sib)
|
|
@@ -9153,15 +9211,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9153
9211
|
const attempts = this.recordNeverStartedAttempt(id, sessionId);
|
|
9154
9212
|
if (attempts >= MAX_NEVER_STARTED_ATTEMPTS) {
|
|
9155
9213
|
inFlight.neverStartedResolved = true;
|
|
9156
|
-
const
|
|
9214
|
+
const watchedForMs2 = this.now() - inFlight.dispatchedAt;
|
|
9157
9215
|
this.log({
|
|
9158
9216
|
level: "error",
|
|
9159
|
-
message: `Message ${id.slice(0, 8)} never started after ${attempts} attempts (${
|
|
9217
|
+
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
9218
|
conversation_id: conv.id,
|
|
9161
9219
|
message_id: id
|
|
9162
9220
|
});
|
|
9163
9221
|
void this.postSignal(conv.id, id, "never_started_failed", {
|
|
9164
|
-
watched_for_ms:
|
|
9222
|
+
watched_for_ms: watchedForMs2,
|
|
9165
9223
|
attempts
|
|
9166
9224
|
});
|
|
9167
9225
|
await this.settleMessageNeverStarted(sessionId, watcher, inFlight, attempts);
|
|
@@ -9175,7 +9233,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9175
9233
|
message_id: inFlight.evidentMessageId
|
|
9176
9234
|
});
|
|
9177
9235
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "gave_up", {
|
|
9178
|
-
watched_for_ms: this.now() - inFlight.dispatchedAt
|
|
9236
|
+
watched_for_ms: this.now() - inFlight.dispatchedAt,
|
|
9237
|
+
run_state: state
|
|
9179
9238
|
});
|
|
9180
9239
|
this.recordReleasedOpencodeId(
|
|
9181
9240
|
inFlight.evidentMessageId,
|
|
@@ -9632,7 +9691,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9632
9691
|
if ((state === "running" || state === "queued") && ocId) {
|
|
9633
9692
|
const conv = this.convForRow(sessionId, row);
|
|
9634
9693
|
const message = this.queuedMessageForRow(row);
|
|
9635
|
-
|
|
9694
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9695
|
+
this.registerReadopted(conv, sessionId, message, ocId, processedAtMs, processedAtMs);
|
|
9636
9696
|
this.dispatched.add(row.id);
|
|
9637
9697
|
this.readopted.add(row.id);
|
|
9638
9698
|
this.ensureWatcherRunning(sessionId);
|
|
@@ -9927,7 +9987,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9927
9987
|
return;
|
|
9928
9988
|
}
|
|
9929
9989
|
this.unconfirmedDispatchFailures.delete(row.id);
|
|
9930
|
-
|
|
9990
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9991
|
+
this.registerReadopted(
|
|
9992
|
+
readoptConv,
|
|
9993
|
+
sessionId,
|
|
9994
|
+
readoptMessage,
|
|
9995
|
+
ocId,
|
|
9996
|
+
processedAtMs,
|
|
9997
|
+
processedAtMs
|
|
9998
|
+
);
|
|
9931
9999
|
this.dispatched.add(row.id);
|
|
9932
10000
|
this.readopted.add(row.id);
|
|
9933
10001
|
this.awaitingReadopt.delete(row.id);
|
|
@@ -11347,25 +11415,6 @@ Port ${port} is already in use.`));
|
|
|
11347
11415
|
import chalk6 from "chalk";
|
|
11348
11416
|
import ora3 from "ora";
|
|
11349
11417
|
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
11418
|
function unknownPasswordError(port) {
|
|
11370
11419
|
return new Error(
|
|
11371
11420
|
`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 +11422,7 @@ function unknownPasswordError(port) {
|
|
|
11373
11422
|
}
|
|
11374
11423
|
var INTERACTIVE_START_TIMEOUT_MS2 = 3e4;
|
|
11375
11424
|
async function ensureOpenCode2Running(ctx) {
|
|
11376
|
-
const initialHealth = await
|
|
11425
|
+
const initialHealth = await checkOpenCode2Health(ctx.port);
|
|
11377
11426
|
if (initialHealth.authFailed) {
|
|
11378
11427
|
throw unknownPasswordError(ctx.port);
|
|
11379
11428
|
}
|
|
@@ -11388,7 +11437,7 @@ async function ensureOpenCode2Running(ctx) {
|
|
|
11388
11437
|
}
|
|
11389
11438
|
if (!isOpenCode2Installed()) {
|
|
11390
11439
|
throw new Error(
|
|
11391
|
-
|
|
11440
|
+
`OpenCode V2 (opencode2) is not installed. Install it with: npm install -g ${OPENCODE2_PACKAGE_SPEC}`
|
|
11392
11441
|
);
|
|
11393
11442
|
}
|
|
11394
11443
|
let port = ctx.port;
|