@evident-ai/cli 3.0.1-dev.223a670 → 3.0.1-dev.23d3337

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 CHANGED
@@ -1059,6 +1059,10 @@ function finishOf(m) {
1059
1059
  const infoFinish = m.info?.finish;
1060
1060
  return typeof infoFinish === "string" ? infoFinish : void 0;
1061
1061
  }
1062
+ function isAssistantInFlight(m) {
1063
+ if (completedOf(m) == null) return true;
1064
+ return finishOf(m) === "tool-calls";
1065
+ }
1062
1066
  async function createOpenCodeSession(port, directory) {
1063
1067
  const url = new URL(`${opencodeBase(port)}/session`);
1064
1068
  if (directory && directory.trim()) {
@@ -1140,9 +1144,13 @@ function messageRunState(messages, userMessageId) {
1140
1144
  if (!reply) return "unknown";
1141
1145
  }
1142
1146
  if (!reply) return "queued";
1143
- if (completedOf(reply) == null) return "running";
1144
- if (finishOf(reply) === "tool-calls") return "running";
1145
- return "done";
1147
+ return isAssistantInFlight(reply) ? "running" : "done";
1148
+ }
1149
+ function hasRunningAssistantExcept(messages, exceptUserMessageId) {
1150
+ if (!messages || messages.length === 0) return false;
1151
+ return messages.some(
1152
+ (m) => roleOf(m) === "assistant" && parentIdOf(m) !== exceptUserMessageId && isAssistantInFlight(m)
1153
+ );
1146
1154
  }
1147
1155
  function opencodeMessageIdFor2(queuedMessageId) {
1148
1156
  return opencodeMessageIdFor(queuedMessageId);
@@ -1552,6 +1560,7 @@ var DEFAULT_RETRY_POLICY = {
1552
1560
  var DEFAULT_PAUSED_POLL_INTERVAL_MS = 2e3;
1553
1561
  var DEFAULT_PAUSED_MAX_WAIT_MS = 10 * 60 * 1e3;
1554
1562
  var DEFAULT_DISPATCH_CONFIRM_MS = 6e3;
1563
+ var DEFAULT_STUCK_QUEUED_MS = 6e4;
1555
1564
  var ChannelAuthError = class extends Error {
1556
1565
  constructor(message) {
1557
1566
  super(message);
@@ -1587,6 +1596,7 @@ var ChannelDriver = class {
1587
1596
  pausedPollIntervalMs;
1588
1597
  pausedMaxWaitMs;
1589
1598
  dispatchConfirmMs;
1599
+ stuckQueuedMs;
1590
1600
  now;
1591
1601
  /** Cache of conversationId → opencode sessionId. */
1592
1602
  sessions = /* @__PURE__ */ new Map();
@@ -1629,6 +1639,7 @@ var ChannelDriver = class {
1629
1639
  this.pausedPollIntervalMs = config2.pausedPollIntervalMs ?? DEFAULT_PAUSED_POLL_INTERVAL_MS;
1630
1640
  this.pausedMaxWaitMs = config2.pausedMaxWaitMs ?? DEFAULT_PAUSED_MAX_WAIT_MS;
1631
1641
  this.dispatchConfirmMs = config2.dispatchConfirmMs ?? DEFAULT_DISPATCH_CONFIRM_MS;
1642
+ this.stuckQueuedMs = config2.stuckQueuedMs ?? DEFAULT_STUCK_QUEUED_MS;
1632
1643
  this.now = config2.now ?? (() => Date.now());
1633
1644
  }
1634
1645
  /** The IPv4-loopback base URL for the local `opencode serve`. */
@@ -1747,6 +1758,7 @@ var ChannelDriver = class {
1747
1758
  this.dispatched.add(message.id);
1748
1759
  this.registerInFlight(conv, sessionId, message, opencodeMessageId);
1749
1760
  dispatched += 1;
1761
+ void this.postSignal(conv.id, message.id, "dispatched");
1750
1762
  }
1751
1763
  if (messages.length > 0 && dispatched === 0 && skippedAlreadyDispatched === messages.length) {
1752
1764
  this.log({
@@ -1812,7 +1824,8 @@ var ChannelDriver = class {
1812
1824
  dispatchedAt: now,
1813
1825
  deadline: now + this.pausedMaxWaitMs,
1814
1826
  started: false,
1815
- done: false
1827
+ done: false,
1828
+ stuckReported: false
1816
1829
  });
1817
1830
  }
1818
1831
  /**
@@ -1972,6 +1985,12 @@ var ChannelDriver = class {
1972
1985
  await this.redispatchInFlight(sessionId, inFlight);
1973
1986
  }
1974
1987
  }
1988
+ if (state === "queued" && !inFlight.started && !inFlight.stuckReported && this.now() - inFlight.dispatchedAt >= this.stuckQueuedMs && !hasRunningAssistantExcept(messages, inFlight.opencodeMessageId)) {
1989
+ inFlight.stuckReported = true;
1990
+ void this.postSignal(conv.id, inFlight.evidentMessageId, "stuck_queued", {
1991
+ stuck_for_ms: this.now() - inFlight.dispatchedAt
1992
+ });
1993
+ }
1975
1994
  if (this.now() >= inFlight.deadline) {
1976
1995
  this.log({
1977
1996
  level: "info",
@@ -2258,6 +2277,42 @@ var ChannelDriver = class {
2258
2277
  )
2259
2278
  );
2260
2279
  }
2280
+ /**
2281
+ * Best-effort, SINGLE-ATTEMPT runner→server telemetry ping
2282
+ * (queued-followup-redrive). `POST .../messages/:id/signal {signal, ...extra}`
2283
+ * — the server records it via `log()` (no DB write, no notification). This is
2284
+ * fire-and-forget: it MUST NEVER throw into the drain or the watcher tick, and
2285
+ * MUST NOT use `callWithRetry` (a telemetry ping must not block the sequential
2286
+ * watcher tick — one attempt is enough). A failure is SWALLOWED but LOGGED with
2287
+ * context (no silent catch, per development-workflow).
2288
+ */
2289
+ async postSignal(conversationId, messageId, signal, extra) {
2290
+ try {
2291
+ const res = await this.fetchImpl(
2292
+ `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}/messages/${messageId}/signal`,
2293
+ {
2294
+ method: "POST",
2295
+ headers: { Authorization: this.getAuthHeader(), "Content-Type": "application/json" },
2296
+ body: JSON.stringify({ signal, ...extra })
2297
+ }
2298
+ );
2299
+ if (!res.ok) {
2300
+ this.log({
2301
+ level: "error",
2302
+ message: `Signal '${signal}' for message ${messageId.slice(0, 8)} returned HTTP ${res.status} (telemetry-only, ignored)`,
2303
+ conversation_id: conversationId,
2304
+ message_id: messageId
2305
+ });
2306
+ }
2307
+ } catch (err) {
2308
+ this.log({
2309
+ level: "error",
2310
+ message: `Signal '${signal}' for message ${messageId.slice(0, 8)} failed (telemetry-only, ignored): ${err instanceof Error ? err.message : String(err)}`,
2311
+ conversation_id: conversationId,
2312
+ message_id: messageId
2313
+ });
2314
+ }
2315
+ }
2261
2316
  async persistSession(conversationId, sessionId) {
2262
2317
  const res = await this.fetchImpl(
2263
2318
  `${this.apiUrl}/agents/${this.agentId}/threads/${conversationId}`,