@evident-ai/cli 3.5.0 → 3.5.1-dev.8b4b29a
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 +66 -30
- 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.8b4b29a" : void 0) ?? process.env.npm_package_version ?? "unknown";
|
|
1162
1162
|
function getCliVersion() {
|
|
1163
1163
|
return CLI_VERSION;
|
|
1164
1164
|
}
|
|
@@ -6399,6 +6399,7 @@ var DEFAULT_PAUSED_POLL_INTERVAL_MS = 2e3;
|
|
|
6399
6399
|
var DEFAULT_PAUSED_MAX_WAIT_MS = 10 * 60 * 1e3;
|
|
6400
6400
|
var DEFAULT_STUCK_QUEUED_MS = 6e4;
|
|
6401
6401
|
var HEARTBEAT_MS = 6e4;
|
|
6402
|
+
var ALIVE_WITHHELD_THRESHOLD_MS = 3 * HEARTBEAT_MS;
|
|
6402
6403
|
var ABSOLUTE_MAX_PROCESSING_MS = 6 * 60 * 60 * 1e3;
|
|
6403
6404
|
var B2_ABANDONMENT_MIN_PINNED_MS = 3 * 6e4;
|
|
6404
6405
|
var AMBIGUOUS_FINISH_MAX_PINNED_MS = 3 * 6e4;
|
|
@@ -7603,7 +7604,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7603
7604
|
return "dispatch";
|
|
7604
7605
|
}
|
|
7605
7606
|
}
|
|
7606
|
-
return this.reattachRedrive(conv, sessionId, message, ocId);
|
|
7607
|
+
return this.reattachRedrive(conv, sessionId, message, ocId, state);
|
|
7607
7608
|
}
|
|
7608
7609
|
if (ongoing === false) {
|
|
7609
7610
|
if (state === "running" && isAmbiguousFinishPinnedRunning(messages, ocId ?? "")) {
|
|
@@ -7620,11 +7621,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7620
7621
|
return "dispatch";
|
|
7621
7622
|
}
|
|
7622
7623
|
/**
|
|
7623
|
-
* The `reattached` outcome (Task 3.3):
|
|
7624
|
-
*
|
|
7625
|
-
*
|
|
7624
|
+
* The `reattached` outcome (Task 3.3): opencode's own status map says the session
|
|
7625
|
+
* is ongoing, so undo the false reclaim instead of starting a second turn. `state`
|
|
7626
|
+
* carries the correlated message's observed state so the outcome does not claim
|
|
7627
|
+
* that a queued message's own turn was already running.
|
|
7626
7628
|
*/
|
|
7627
|
-
async reattachRedrive(conv, sessionId, message, ocId) {
|
|
7629
|
+
async reattachRedrive(conv, sessionId, message, ocId, state) {
|
|
7628
7630
|
let anchorMs;
|
|
7629
7631
|
const parsed = message.processing_started_at ? Date.parse(message.processing_started_at) : NaN;
|
|
7630
7632
|
if (!Number.isNaN(parsed)) {
|
|
@@ -7633,7 +7635,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7633
7635
|
anchorMs = this.now();
|
|
7634
7636
|
this.log({
|
|
7635
7637
|
level: "warn",
|
|
7636
|
-
message: `Re-drive: message ${message.id.slice(0, 8)} has
|
|
7638
|
+
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
7639
|
conversation_id: conv.id,
|
|
7638
7640
|
message_id: message.id
|
|
7639
7641
|
});
|
|
@@ -7662,17 +7664,19 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
7662
7664
|
return bound === "abandoned" ? "abandoned" : "unresolved";
|
|
7663
7665
|
}
|
|
7664
7666
|
this.clearRedriveUnresolved(message.id);
|
|
7665
|
-
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs);
|
|
7667
|
+
this.registerReadopted(conv, sessionId, message, ocId ?? "", anchorMs, this.now());
|
|
7666
7668
|
this.dispatched.add(message.id);
|
|
7667
7669
|
this.readopted.add(message.id);
|
|
7668
|
-
this.ensureWatcherRunning(sessionId);
|
|
7670
|
+
const watcherState = this.ensureWatcherRunning(sessionId);
|
|
7669
7671
|
const watchedForMs = this.now() - anchorMs;
|
|
7670
7672
|
void this.postSignal(conv.id, message.id, "redrive_reattached", {
|
|
7671
|
-
watched_for_ms: watchedForMs
|
|
7673
|
+
watched_for_ms: watchedForMs,
|
|
7674
|
+
run_state: state,
|
|
7675
|
+
watcher_state: watcherState
|
|
7672
7676
|
});
|
|
7673
7677
|
this.log({
|
|
7674
7678
|
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`,
|
|
7679
|
+
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
7680
|
conversation_id: conv.id,
|
|
7677
7681
|
message_id: message.id
|
|
7678
7682
|
});
|
|
@@ -8279,6 +8283,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8279
8283
|
stuckReported: false,
|
|
8280
8284
|
lastAliveAt: 0,
|
|
8281
8285
|
aliveInFlight: false,
|
|
8286
|
+
aliveWithheldSignalled: false,
|
|
8282
8287
|
titleSynced: false,
|
|
8283
8288
|
titleSyncInFlight: false,
|
|
8284
8289
|
awaitingHumanLatched: false,
|
|
@@ -8338,9 +8343,12 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8338
8343
|
/**
|
|
8339
8344
|
* Register a RE-ADOPTED `processing` message with its session watcher
|
|
8340
8345
|
* (ADR-0046, WI-4). Mirrors `registerInFlight` but anchors the give-up
|
|
8341
|
-
* `deadline` to the
|
|
8342
|
-
* `
|
|
8343
|
-
*
|
|
8346
|
+
* `deadline` to the attempt's SERVER-SIDE `processed_at` (Invariant 1), while
|
|
8347
|
+
* `processingAnchorMs` keeps the absolute-age ceiling tied to the original turn.
|
|
8348
|
+
* The deadline tracks THIS attempt; the ceiling tracks THE TURN. For a fresh
|
|
8349
|
+
* dispatch both anchors are `now`; a restart re-adopt passes the server's
|
|
8350
|
+
* `processed_at` for both, while a re-drive passes the newly stamped attempt time
|
|
8351
|
+
* only for the deadline.
|
|
8344
8352
|
*
|
|
8345
8353
|
* This re-attaches into the SAME watcher, so the ADR-0047 progressing-vs-paused
|
|
8346
8354
|
* give-up (`serviceInFlightMessage`) applies unchanged: a re-adopted turn
|
|
@@ -8361,7 +8369,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8361
8369
|
* server already flipped to `processing`; the running/done transitions still
|
|
8362
8370
|
* fire from the watcher's normal branches.
|
|
8363
8371
|
*/
|
|
8364
|
-
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs) {
|
|
8372
|
+
registerReadopted(conv, sessionId, message, opencodeMessageId, processedAtMs, watchDeadlineAnchorMs) {
|
|
8365
8373
|
let watcher = this.watchers.get(sessionId);
|
|
8366
8374
|
if (!watcher) {
|
|
8367
8375
|
watcher = this.newSessionWatcher(conv);
|
|
@@ -8372,11 +8380,11 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8372
8380
|
opencodeMessageId,
|
|
8373
8381
|
message,
|
|
8374
8382
|
dispatchedAt: this.now(),
|
|
8375
|
-
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at
|
|
8376
|
-
//
|
|
8377
|
-
//
|
|
8383
|
+
// Anchor the absolute-age ceiling to the SERVER-SIDE `processed_at`, NOT
|
|
8384
|
+
// `dispatchedAt` — so a re-adopted zombie's age reflects the real turn duration
|
|
8385
|
+
// and the ceiling fires on the ORIGINAL turn.
|
|
8378
8386
|
processingAnchorMs: processedAtMs,
|
|
8379
|
-
deadline:
|
|
8387
|
+
deadline: watchDeadlineAnchorMs + this.pausedMaxWaitMs,
|
|
8380
8388
|
// The server row is ALREADY `processing`; do not re-fire markProcessing.
|
|
8381
8389
|
started: true,
|
|
8382
8390
|
done: false,
|
|
@@ -8393,6 +8401,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8393
8401
|
// with no extra `re_adopted` signal needed (folds old WI-6).
|
|
8394
8402
|
lastAliveAt: 0,
|
|
8395
8403
|
aliveInFlight: false,
|
|
8404
|
+
aliveWithheldSignalled: false,
|
|
8396
8405
|
titleSynced: false,
|
|
8397
8406
|
titleSyncInFlight: false,
|
|
8398
8407
|
awaitingHumanLatched: false,
|
|
@@ -8509,6 +8518,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8509
8518
|
* tracked on the watcher and cleared when it settles; it never rejects (fully
|
|
8510
8519
|
* guarded), so a failed poll/callback can never crash the run loop — the cron
|
|
8511
8520
|
* stays as the safety net.
|
|
8521
|
+
* Returns the branch taken so re-attach telemetry can show whether it left a
|
|
8522
|
+
* ticking loop behind.
|
|
8512
8523
|
*
|
|
8513
8524
|
* The generation started here (#1618) is captured in the `.finally` closure
|
|
8514
8525
|
* so a RETIRED loop settling late — after `reconcileWatchers` has already
|
|
@@ -8522,7 +8533,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8522
8533
|
level: "debug",
|
|
8523
8534
|
message: `No watcher entry exists for session ${sessionId} \u2014 nothing to do`
|
|
8524
8535
|
});
|
|
8525
|
-
return;
|
|
8536
|
+
return "no_watcher";
|
|
8526
8537
|
}
|
|
8527
8538
|
this.ensureSessionErrorStream();
|
|
8528
8539
|
if (watcher.loop) {
|
|
@@ -8531,7 +8542,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8531
8542
|
message: `Watcher loop already running for session ${sessionId}; no-op with ${watcher.inFlight.size} message(s) in flight`,
|
|
8532
8543
|
conversation_id: watcher.conv.id
|
|
8533
8544
|
});
|
|
8534
|
-
return;
|
|
8545
|
+
return "already_running";
|
|
8535
8546
|
}
|
|
8536
8547
|
if (watcher.inFlight.size === 0) {
|
|
8537
8548
|
this.log({
|
|
@@ -8540,7 +8551,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8540
8551
|
conversation_id: watcher.conv.id
|
|
8541
8552
|
});
|
|
8542
8553
|
this.watchers.delete(sessionId);
|
|
8543
|
-
return;
|
|
8554
|
+
return "no_in_flight";
|
|
8544
8555
|
}
|
|
8545
8556
|
const generation = watcher.generation;
|
|
8546
8557
|
this.log({
|
|
@@ -8556,6 +8567,7 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
8556
8567
|
}
|
|
8557
8568
|
});
|
|
8558
8569
|
watcher.loop = loop;
|
|
8570
|
+
return "started";
|
|
8559
8571
|
}
|
|
8560
8572
|
ensureSessionErrorStream() {
|
|
8561
8573
|
if (this.sessionErrorStream || this.stopped) return;
|
|
@@ -9081,7 +9093,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9081
9093
|
this.removeInFlight(watcher, inFlight.evidentMessageId);
|
|
9082
9094
|
return;
|
|
9083
9095
|
}
|
|
9084
|
-
|
|
9096
|
+
const heartbeatDue = activelyRunning && !inFlight.awaitingHumanLatched && !inFlight.aliveInFlight && this.now() - inFlight.lastAliveAt >= HEARTBEAT_MS;
|
|
9097
|
+
if (heartbeatDue) {
|
|
9085
9098
|
inFlight.aliveInFlight = true;
|
|
9086
9099
|
this.log({
|
|
9087
9100
|
level: "debug",
|
|
@@ -9091,7 +9104,10 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9091
9104
|
});
|
|
9092
9105
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive").then((ok) => {
|
|
9093
9106
|
inFlight.aliveInFlight = false;
|
|
9094
|
-
if (ok)
|
|
9107
|
+
if (ok) {
|
|
9108
|
+
inFlight.lastAliveAt = this.now();
|
|
9109
|
+
inFlight.aliveWithheldSignalled = false;
|
|
9110
|
+
}
|
|
9095
9111
|
this.log({
|
|
9096
9112
|
level: "debug",
|
|
9097
9113
|
message: `Heartbeat POST for message ${inFlight.evidentMessageId} in session ${sessionId} completed with ok=${ok}`,
|
|
@@ -9143,6 +9159,16 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9143
9159
|
inFlight.pausedOnPermission = false;
|
|
9144
9160
|
inFlight.pausedClearConfirmed = false;
|
|
9145
9161
|
}
|
|
9162
|
+
const watchedForMs = this.now() - Math.max(inFlight.lastAliveAt, inFlight.dispatchedAt);
|
|
9163
|
+
if (!heartbeatDue && !inFlight.aliveWithheldSignalled && watchedForMs >= ALIVE_WITHHELD_THRESHOLD_MS) {
|
|
9164
|
+
inFlight.aliveWithheldSignalled = true;
|
|
9165
|
+
const reason = inFlight.awaitingHumanLatched ? "awaiting_human" : inFlight.aliveInFlight ? "alive_in_flight" : "not_running";
|
|
9166
|
+
void this.postSignal(conv.id, inFlight.evidentMessageId, "alive_withheld", {
|
|
9167
|
+
reason,
|
|
9168
|
+
run_state: state,
|
|
9169
|
+
watched_for_ms: watchedForMs
|
|
9170
|
+
});
|
|
9171
|
+
}
|
|
9146
9172
|
const siblingPaused = (sib) => openQuestions.has(sib.evidentMessageId) || openPermissions.has(sib.evidentMessageId) || sib.awaitingHumanLatched || sib.pausedOnQuestion || sib.pausedOnPermission;
|
|
9147
9173
|
const hasActivelyRunningSibling = [...watcher.inFlight.values()].some(
|
|
9148
9174
|
(sib) => sib.evidentMessageId !== inFlight.evidentMessageId && messageRunState(messages, sib.opencodeMessageId) === "running" && !siblingPaused(sib)
|
|
@@ -9153,15 +9179,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9153
9179
|
const attempts = this.recordNeverStartedAttempt(id, sessionId);
|
|
9154
9180
|
if (attempts >= MAX_NEVER_STARTED_ATTEMPTS) {
|
|
9155
9181
|
inFlight.neverStartedResolved = true;
|
|
9156
|
-
const
|
|
9182
|
+
const watchedForMs2 = this.now() - inFlight.dispatchedAt;
|
|
9157
9183
|
this.log({
|
|
9158
9184
|
level: "error",
|
|
9159
|
-
message: `Message ${id.slice(0, 8)} never started after ${attempts} attempts (${
|
|
9185
|
+
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
9186
|
conversation_id: conv.id,
|
|
9161
9187
|
message_id: id
|
|
9162
9188
|
});
|
|
9163
9189
|
void this.postSignal(conv.id, id, "never_started_failed", {
|
|
9164
|
-
watched_for_ms:
|
|
9190
|
+
watched_for_ms: watchedForMs2,
|
|
9165
9191
|
attempts
|
|
9166
9192
|
});
|
|
9167
9193
|
await this.settleMessageNeverStarted(sessionId, watcher, inFlight, attempts);
|
|
@@ -9175,7 +9201,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9175
9201
|
message_id: inFlight.evidentMessageId
|
|
9176
9202
|
});
|
|
9177
9203
|
void this.postSignal(conv.id, inFlight.evidentMessageId, "gave_up", {
|
|
9178
|
-
watched_for_ms: this.now() - inFlight.dispatchedAt
|
|
9204
|
+
watched_for_ms: this.now() - inFlight.dispatchedAt,
|
|
9205
|
+
run_state: state
|
|
9179
9206
|
});
|
|
9180
9207
|
this.recordReleasedOpencodeId(
|
|
9181
9208
|
inFlight.evidentMessageId,
|
|
@@ -9632,7 +9659,8 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9632
9659
|
if ((state === "running" || state === "queued") && ocId) {
|
|
9633
9660
|
const conv = this.convForRow(sessionId, row);
|
|
9634
9661
|
const message = this.queuedMessageForRow(row);
|
|
9635
|
-
|
|
9662
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9663
|
+
this.registerReadopted(conv, sessionId, message, ocId, processedAtMs, processedAtMs);
|
|
9636
9664
|
this.dispatched.add(row.id);
|
|
9637
9665
|
this.readopted.add(row.id);
|
|
9638
9666
|
this.ensureWatcherRunning(sessionId);
|
|
@@ -9927,7 +9955,15 @@ var ChannelDriver = class _ChannelDriver {
|
|
|
9927
9955
|
return;
|
|
9928
9956
|
}
|
|
9929
9957
|
this.unconfirmedDispatchFailures.delete(row.id);
|
|
9930
|
-
|
|
9958
|
+
const processedAtMs = this.processedAtMs(row);
|
|
9959
|
+
this.registerReadopted(
|
|
9960
|
+
readoptConv,
|
|
9961
|
+
sessionId,
|
|
9962
|
+
readoptMessage,
|
|
9963
|
+
ocId,
|
|
9964
|
+
processedAtMs,
|
|
9965
|
+
processedAtMs
|
|
9966
|
+
);
|
|
9931
9967
|
this.dispatched.add(row.id);
|
|
9932
9968
|
this.readopted.add(row.id);
|
|
9933
9969
|
this.awaitingReadopt.delete(row.id);
|